LCOV - code coverage report
Current view: top level - gfx/skia/skia/src/core - SkFindAndPlaceGlyph.h (source / functions) Hit Total Coverage
Test: output.info Lines: 101 260 38.8 %
Date: 2017-07-14 16:53:18 Functions: 58 285 20.4 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Copyright 2015 Google Inc.
       3             :  *
       4             :  * Use of this source code is governed by a BSD-style license that can be
       5             :  * found in the LICENSE file.
       6             :  */
       7             : 
       8             : #ifndef SkFindAndPositionGlyph_DEFINED
       9             : #define SkFindAndPositionGlyph_DEFINED
      10             : 
      11             : #include "SkAutoKern.h"
      12             : #include "SkGlyph.h"
      13             : #include "SkGlyphCache.h"
      14             : #include "SkPaint.h"
      15             : #include "SkTemplates.h"
      16             : #include "SkUtils.h"
      17             : #include <utility>
      18             : 
      19             : // Calculate a type with the same size as the max of all the Ts.
      20             : // This must be top level because the is no specialization of inner classes.
      21             : template<typename... Ts> struct SkMaxSizeOf;
      22             : 
      23             : template<>
      24             : struct SkMaxSizeOf<> {
      25             :     static const size_t value = 0;
      26             : };
      27             : 
      28             : template<typename H, typename... Ts>
      29             : struct SkMaxSizeOf<H, Ts...> {
      30             :     static const size_t value =
      31             :         sizeof(H) >= SkMaxSizeOf<Ts...>::value ? sizeof(H) : SkMaxSizeOf<Ts...>::value;
      32             : };
      33             : 
      34             : 
      35             : // This is a temporary helper function to work around a bug in the code generation
      36             : // for aarch64 (arm) on GCC 4.9. This bug does not show up on other platforms, so it
      37             : // seems to be an aarch64 backend problem.
      38             : //
      39             : // GCC 4.9 on ARM64 does not generate the proper constructor code for PositionReader or
      40             : // GlyphFindAndPlace. The vtable is not set properly without adding the fixme code.
      41             : // The implementation is in SkDraw.cpp.
      42             : extern void FixGCC49Arm64Bug(int v);
      43             : 
      44             : class SkFindAndPlaceGlyph {
      45             : public:
      46             :     template<typename ProcessOneGlyph>
      47             :     static void ProcessText(
      48             :         SkPaint::TextEncoding, const char text[], size_t byteLength,
      49             :         SkPoint offset, const SkMatrix& matrix, SkPaint::Align textAlignment,
      50             :         SkGlyphCache* cache, ProcessOneGlyph&& processOneGlyph);
      51             :     // ProcessPosText handles all cases for finding and positioning glyphs. It has a very large
      52             :     // multiplicity. It figures out the glyph, position and rounding and pass those parameters to
      53             :     // processOneGlyph.
      54             :     //
      55             :     // The routine processOneGlyph passed in by the client has the following signature:
      56             :     // void f(const SkGlyph& glyph, SkPoint position, SkPoint rounding);
      57             :     //
      58             :     // * Sub-pixel positioning (2) - use sub-pixel positioning.
      59             :     // * Text alignment (3) - text alignment with respect to the glyph's width.
      60             :     // * Matrix type (3) - special cases for translation and X-coordinate scaling.
      61             :     // * Components per position (2) - the positions vector can have a common Y with different
      62             :     //   Xs, or XY-pairs.
      63             :     // * Axis Alignment (for sub-pixel positioning) (3) - when using sub-pixel positioning, round
      64             :     //   to a whole coordinate instead of using sub-pixel positioning.
      65             :     // The number of variations is 108 for sub-pixel and 36 for full-pixel.
      66             :     // This routine handles all of them using inline polymorphic variable (no heap allocation).
      67             :     template<typename ProcessOneGlyph>
      68             :     static void ProcessPosText(
      69             :         SkPaint::TextEncoding, const char text[], size_t byteLength,
      70             :         SkPoint offset, const SkMatrix& matrix, const SkScalar pos[], int scalarsPerPosition,
      71             :         SkPaint::Align textAlignment,
      72             :         SkGlyphCache* cache, ProcessOneGlyph&& processOneGlyph);
      73             : 
      74             : private:
      75             :     // UntaggedVariant is a pile of memory that can hold one of the Ts. It provides a way
      76             :     // to initialize that memory in a typesafe way.
      77             :     template<typename... Ts>
      78             :     class UntaggedVariant {
      79             :     public:
      80          84 :         UntaggedVariant() { }
      81             : 
      82          84 :         ~UntaggedVariant() { }
      83             :         UntaggedVariant(const UntaggedVariant&) = delete;
      84             :         UntaggedVariant& operator=(const UntaggedVariant&) = delete;
      85             :         UntaggedVariant(UntaggedVariant&&) = delete;
      86             :         UntaggedVariant& operator=(UntaggedVariant&&) = delete;
      87             : 
      88             :         template<typename Variant, typename... Args>
      89          84 :         void initialize(Args&&... args) {
      90             :             SkASSERT(sizeof(Variant) <= sizeof(fSpace));
      91             :         #if defined(_MSC_VER) && _MSC_VER < 1900
      92             :             #define alignof __alignof
      93             :         #endif
      94             :             SkASSERT(alignof(Variant) <= alignof(Space));
      95          84 :             new(&fSpace) Variant(std::forward<Args>(args)...);
      96          84 :         }
      97             : 
      98             :     private:
      99             :         typedef SkAlignedSStorage<SkMaxSizeOf<Ts...>::value> Space;
     100             :         Space fSpace;
     101             :     };
     102             : 
     103             :     // PolymorphicVariant holds subclasses of Base without slicing. Ts must be subclasses of Base.
     104             :     template<typename Base, typename... Ts>
     105             :     class PolymorphicVariant {
     106             :     public:
     107             :         typedef UntaggedVariant<Ts...> Variants;
     108             : 
     109             :         template<typename Initializer>
     110          84 :         PolymorphicVariant(Initializer&& initializer) {
     111          84 :             initializer(&fVariants);
     112          84 :         }
     113          84 :         ~PolymorphicVariant() { get()->~Base(); }
     114        1897 :         Base* get() const { return reinterpret_cast<Base*>(&fVariants); }
     115        1813 :         Base* operator->() const { return get(); }
     116             :         Base& operator*() const { return *get(); }
     117             : 
     118             :     private:
     119             :         mutable Variants fVariants;
     120             :     };
     121             : 
     122             :     // GlyphFinderInterface is the polymorphic base for classes that parse a stream of chars into
     123             :     // the right UniChar (or GlyphID) and lookup up the glyph on the cache. The concrete
     124             :     // implementations are: Utf8GlyphFinder, Utf16GlyphFinder, Utf32GlyphFinder,
     125             :     // and GlyphIdGlyphFinder.
     126          21 :     class GlyphFinderInterface {
     127             :     public:
     128          21 :         virtual ~GlyphFinderInterface() {}
     129             :         virtual const SkGlyph& lookupGlyph(const char** text) = 0;
     130             :         virtual const SkGlyph& lookupGlyphXY(const char** text, SkFixed x, SkFixed y) = 0;
     131             :     };
     132             : 
     133           0 :     class UtfNGlyphFinder : public GlyphFinderInterface {
     134             :     public:
     135           0 :         UtfNGlyphFinder(SkGlyphCache* cache) : fCache(cache) { SkASSERT(cache != nullptr); }
     136             : 
     137           0 :         const SkGlyph& lookupGlyph(const char** text) override {
     138           0 :             SkASSERT(text != nullptr);
     139           0 :             return fCache->getUnicharMetrics(nextUnichar(text));
     140             :         }
     141           0 :         const SkGlyph& lookupGlyphXY(const char** text, SkFixed x, SkFixed y) override {
     142           0 :             SkASSERT(text != nullptr);
     143           0 :             return fCache->getUnicharMetrics(nextUnichar(text), x, y);
     144             :         }
     145             : 
     146             :     private:
     147             :         virtual SkUnichar nextUnichar(const char** text) = 0;
     148             :         SkGlyphCache* fCache;
     149             :     };
     150             : 
     151           0 :     class Utf8GlyphFinder final : public UtfNGlyphFinder {
     152             :     public:
     153           0 :         Utf8GlyphFinder(SkGlyphCache* cache) : UtfNGlyphFinder(cache) { }
     154             : 
     155             :     private:
     156           0 :         SkUnichar nextUnichar(const char** text) override { return SkUTF8_NextUnichar(text); }
     157             :     };
     158             : 
     159           0 :     class Utf16GlyphFinder final : public UtfNGlyphFinder {
     160             :     public:
     161           0 :         Utf16GlyphFinder(SkGlyphCache* cache) : UtfNGlyphFinder(cache) { }
     162             : 
     163             :     private:
     164           0 :         SkUnichar nextUnichar(const char** text) override {
     165           0 :             return SkUTF16_NextUnichar((const uint16_t**)text);
     166             :         }
     167             :     };
     168             : 
     169           0 :     class Utf32GlyphFinder final : public UtfNGlyphFinder {
     170             :     public:
     171           0 :         Utf32GlyphFinder(SkGlyphCache* cache) : UtfNGlyphFinder(cache) { }
     172             : 
     173             :     private:
     174           0 :         SkUnichar nextUnichar(const char** text) override {
     175           0 :             const int32_t* ptr = *(const int32_t**)text;
     176           0 :             SkUnichar uni = *ptr++;
     177           0 :             *text = (const char*)ptr;
     178           0 :             return uni;
     179             :         }
     180             :     };
     181             : 
     182          21 :     class GlyphIdGlyphFinder final : public GlyphFinderInterface {
     183             :     public:
     184          21 :         GlyphIdGlyphFinder(SkGlyphCache* cache) : fCache(cache) { SkASSERT(cache != nullptr); }
     185             : 
     186         448 :         const SkGlyph& lookupGlyph(const char** text) override {
     187         448 :             return fCache->getGlyphIDMetrics(nextGlyphId(text));
     188             :         }
     189           0 :         const SkGlyph& lookupGlyphXY(const char** text, SkFixed x, SkFixed y) override {
     190           0 :             return fCache->getGlyphIDMetrics(nextGlyphId(text), x, y);
     191             :         }
     192             : 
     193             :     private:
     194         448 :         uint16_t nextGlyphId(const char** text) {
     195         448 :             SkASSERT(text != nullptr);
     196             : 
     197         448 :             const uint16_t* ptr = *(const uint16_t**)text;
     198         448 :             uint16_t glyphID = *ptr;
     199         448 :             ptr += 1;
     200         448 :             *text = (const char*)ptr;
     201         448 :             return glyphID;
     202             :         }
     203             :         SkGlyphCache* fCache;
     204             :     };
     205             : 
     206             :     typedef PolymorphicVariant<
     207             :         GlyphFinderInterface,
     208             :         Utf8GlyphFinder,
     209             :         Utf16GlyphFinder,
     210             :         Utf32GlyphFinder,
     211             :         GlyphIdGlyphFinder> LookupGlyphVariant;
     212             : 
     213          21 :     class LookupGlyph : public LookupGlyphVariant {
     214             :     public:
     215          21 :         LookupGlyph(SkPaint::TextEncoding encoding, SkGlyphCache* cache)
     216          21 :             : LookupGlyphVariant(
     217          21 :             [&](LookupGlyphVariant::Variants* to_init) {
     218          21 :                 switch(encoding) {
     219             :                     case SkPaint::kUTF8_TextEncoding:
     220          21 :                         to_init->initialize<Utf8GlyphFinder>(cache);
     221           0 :                         break;
     222             :                     case SkPaint::kUTF16_TextEncoding:
     223           0 :                         to_init->initialize<Utf16GlyphFinder>(cache);
     224           0 :                         break;
     225             :                     case SkPaint::kUTF32_TextEncoding:
     226           0 :                         to_init->initialize<Utf32GlyphFinder>(cache);
     227           0 :                         break;
     228             :                     case SkPaint::kGlyphID_TextEncoding:
     229          21 :                         to_init->initialize<GlyphIdGlyphFinder>(cache);
     230          21 :                         break;
     231             :                 }
     232          21 :             }
     233          21 :         ) { }
     234             :     };
     235             : 
     236             :     // PositionReaderInterface reads a point from the pos vector.
     237             :     // * HorizontalPositions - assumes a common Y for many X values.
     238             :     // * ArbitraryPositions - a list of (X,Y) pairs.
     239          21 :     class PositionReaderInterface {
     240             :     public:
     241          21 :         virtual ~PositionReaderInterface() { }
     242             :         virtual SkPoint nextPoint() = 0;
     243             :         // This is only here to fix a GCC 4.9 aarch64 code gen bug.
     244             :         // See comment at the top of the file.
     245             :         virtual int forceUseForBug() = 0;
     246             :     };
     247             : 
     248           0 :     class HorizontalPositions final : public PositionReaderInterface {
     249             :     public:
     250           0 :         explicit HorizontalPositions(const SkScalar* positions)
     251           0 :             : fPositions(positions) { }
     252             : 
     253           0 :         SkPoint nextPoint() override {
     254           0 :             SkScalar x = *fPositions++;
     255           0 :             return {x, 0};
     256             :         }
     257             : 
     258           0 :         int forceUseForBug() override { return 1; }
     259             : 
     260             :     private:
     261             :         const SkScalar* fPositions;
     262             :     };
     263             : 
     264          21 :     class ArbitraryPositions final : public PositionReaderInterface {
     265             :     public:
     266          21 :         explicit ArbitraryPositions(const SkScalar* positions)
     267          21 :             : fPositions(positions) { }
     268             : 
     269         448 :         SkPoint nextPoint() override {
     270         448 :             SkPoint to_return{fPositions[0], fPositions[1]};
     271         448 :             fPositions += 2;
     272         448 :             return to_return;
     273             :         }
     274             : 
     275          21 :         int forceUseForBug() override { return 2; }
     276             : 
     277             :     private:
     278             :         const SkScalar* fPositions;
     279             :     };
     280             : 
     281             :     typedef PolymorphicVariant<PositionReaderInterface, HorizontalPositions, ArbitraryPositions>
     282             :         PositionReader;
     283             : 
     284             :     // MapperInterface given a point map it through the matrix. There are several shortcut
     285             :     // variants.
     286             :     // * TranslationMapper - assumes a translation only matrix.
     287             :     // * XScaleMapper - assumes an X scaling and a translation.
     288             :     // * GeneralMapper - Does all other matricies.
     289          21 :     class MapperInterface {
     290             :     public:
     291          21 :         virtual ~MapperInterface() { }
     292             : 
     293             :         virtual SkPoint map(SkPoint position) const = 0;
     294             :     };
     295             : 
     296           0 :     class TranslationMapper final : public MapperInterface {
     297             :     public:
     298           0 :         TranslationMapper(const SkMatrix& matrix, const SkPoint origin)
     299           0 :             : fTranslate(matrix.mapXY(origin.fX, origin.fY)) { }
     300             : 
     301           0 :         SkPoint map(SkPoint position) const override {
     302           0 :             return position + fTranslate;
     303             :         }
     304             : 
     305             :     private:
     306             :         const SkPoint fTranslate;
     307             :     };
     308             : 
     309           0 :     class XScaleMapper final : public MapperInterface {
     310             :     public:
     311           0 :         XScaleMapper(const SkMatrix& matrix, const SkPoint origin)
     312           0 :             : fTranslate(matrix.mapXY(origin.fX, origin.fY)), fXScale(matrix.getScaleX()) { }
     313             : 
     314           0 :         SkPoint map(SkPoint position) const override {
     315           0 :             return {fXScale * position.fX + fTranslate.fX, fTranslate.fY};
     316             :         }
     317             : 
     318             :     private:
     319             :         const SkPoint fTranslate;
     320             :         const SkScalar fXScale;
     321             :     };
     322             : 
     323             :     // The caller must keep matrix alive while this class is used.
     324          21 :     class GeneralMapper final : public MapperInterface {
     325             :     public:
     326          21 :         GeneralMapper(const SkMatrix& matrix, const SkPoint origin)
     327          21 :             : fOrigin(origin), fMatrix(matrix), fMapProc(matrix.getMapXYProc()) { }
     328             : 
     329         448 :         SkPoint map(SkPoint position) const override {
     330             :             SkPoint result;
     331         448 :             fMapProc(fMatrix, position.fX + fOrigin.fX, position.fY + fOrigin.fY, &result);
     332         448 :             return result;
     333             :         }
     334             : 
     335             :     private:
     336             :         const SkPoint fOrigin;
     337             :         const SkMatrix& fMatrix;
     338             :         const SkMatrix::MapXYProc fMapProc;
     339             :     };
     340             : 
     341             :     typedef PolymorphicVariant<
     342             :         MapperInterface, TranslationMapper, XScaleMapper, GeneralMapper> Mapper;
     343             : 
     344             :     // TextAlignmentAdjustment handles shifting the glyph based on its width.
     345         422 :     static SkPoint TextAlignmentAdjustment(SkPaint::Align textAlignment, const SkGlyph& glyph) {
     346         422 :         switch (textAlignment) {
     347             :             case SkPaint::kLeft_Align:
     348         422 :                 return {0.0f, 0.0f};
     349             :             case SkPaint::kCenter_Align:
     350           0 :                 return {SkFloatToScalar(glyph.fAdvanceX) / 2,
     351           0 :                         SkFloatToScalar(glyph.fAdvanceY) / 2};
     352             :             case SkPaint::kRight_Align:
     353           0 :                 return {SkFloatToScalar(glyph.fAdvanceX),
     354           0 :                         SkFloatToScalar(glyph.fAdvanceY)};
     355             :         }
     356             :         // Even though the entire enum is covered above, MVSC doesn't think so. Make it happy.
     357           0 :         SkFAIL("Should never get here.");
     358           0 :         return {0.0f, 0.0f};
     359             :     }
     360             : 
     361             :     // The "call" to SkFixedToScalar is actually a macro. It's macros all the way down.
     362             :     // Needs to be a macro because you can't have a const float unless you make it constexpr.
     363             :     #define kSubpixelRounding (SkFixedToScalar(SkGlyph::kSubpixelRound))
     364             : 
     365             :     // The SubpixelPositionRounding function returns a point suitable for rounding a sub-pixel
     366             :     // positioned glyph.
     367           0 :     static SkPoint SubpixelPositionRounding(SkAxisAlignment axisAlignment) {
     368           0 :         switch (axisAlignment) {
     369             :             case kX_SkAxisAlignment:
     370           0 :                 return {kSubpixelRounding, SK_ScalarHalf};
     371             :             case kY_SkAxisAlignment:
     372           0 :                 return {SK_ScalarHalf, kSubpixelRounding};
     373             :             case kNone_SkAxisAlignment:
     374           0 :                 return {kSubpixelRounding, kSubpixelRounding};
     375             :         }
     376           0 :         SkFAIL("Should not get here.");
     377           0 :         return {0.0f, 0.0f};
     378             :     }
     379             : 
     380             :     // The SubpixelAlignment function produces a suitable position for the glyph cache to
     381             :     // produce the correct sub-pixel alignment. If a position is aligned with an axis a shortcut
     382             :     // of 0 is used for the sub-pixel position.
     383           0 :     static SkIPoint SubpixelAlignment(SkAxisAlignment axisAlignment, SkPoint position) {
     384             :         // Only the fractional part of position.fX and position.fY matter, because the result of
     385             :         // this function will just be passed to FixedToSub.
     386           0 :         switch (axisAlignment) {
     387             :             case kX_SkAxisAlignment:
     388           0 :                 return {SkScalarToFixed(SkScalarFraction(position.fX) + kSubpixelRounding), 0};
     389             :             case kY_SkAxisAlignment:
     390           0 :                 return {0, SkScalarToFixed(SkScalarFraction(position.fY) + kSubpixelRounding)};
     391             :             case kNone_SkAxisAlignment:
     392           0 :                 return {SkScalarToFixed(SkScalarFraction(position.fX) + kSubpixelRounding),
     393           0 :                         SkScalarToFixed(SkScalarFraction(position.fY) + kSubpixelRounding)};
     394             :         }
     395           0 :         SkFAIL("Should not get here.");
     396           0 :         return {0, 0};
     397             :     }
     398             : 
     399             :     #undef kSubpixelRounding
     400             : 
     401             :     // GlyphFindAndPlaceInterface given the text and position finds the correct glyph and does
     402             :     // glyph specific position adjustment. The findAndPositionGlyph method takes text and
     403             :     // position and calls processOneGlyph with the correct glyph, final position and rounding
     404             :     // terms. The final position is not rounded yet and is the responsibility of processOneGlyph.
     405             :     template<typename ProcessOneGlyph>
     406          21 :     class GlyphFindAndPlaceInterface : SkNoncopyable {
     407             :     public:
     408          21 :         virtual ~GlyphFindAndPlaceInterface() { }
     409             : 
     410             :         // findAndPositionGlyph calculates the position of the glyph, finds the glyph, and
     411             :         // returns the position of where the next glyph will be using the glyph's advance and
     412             :         // possibly kerning. The returned position is used by drawText, but ignored by drawPosText.
     413             :         // The compiler should prune all this calculation if the return value is not used.
     414             :         //
     415             :         // This should be a pure virtual, but some versions of GCC <= 4.8 have a bug that causes a
     416             :         // compile error.
     417             :         // See GCC bug: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=60277
     418           0 :         virtual SkPoint findAndPositionGlyph(
     419             :             const char** text, SkPoint position, ProcessOneGlyph&& processOneGlyph) {
     420           0 :             SkFAIL("Should never get here.");
     421           0 :             return {0.0f, 0.0f};
     422             :         }
     423             :     };
     424             : 
     425             :     // GlyphFindAndPlaceSubpixel handles finding and placing glyphs when sub-pixel positioning is
     426             :     // requested. After it has found and placed the glyph it calls the templated function
     427             :     // ProcessOneGlyph in order to actually perform an action.
     428             :     template<typename ProcessOneGlyph, SkPaint::Align kTextAlignment,
     429             :              SkAxisAlignment kAxisAlignment>
     430           0 :     class GlyphFindAndPlaceSubpixel final : public GlyphFindAndPlaceInterface<ProcessOneGlyph> {
     431             :     public:
     432           0 :         GlyphFindAndPlaceSubpixel(LookupGlyph& glyphFinder)
     433           0 :             : fGlyphFinder(glyphFinder) {
     434           0 :             FixGCC49Arm64Bug(1);
     435           0 :         }
     436             : 
     437           0 :         SkPoint findAndPositionGlyph(
     438             :             const char** text, SkPoint position, ProcessOneGlyph&& processOneGlyph) override {
     439             : 
     440             :             if (kTextAlignment != SkPaint::kLeft_Align) {
     441             :                 // Get the width of an un-sub-pixel positioned glyph for calculating the
     442             :                 // alignment. This is not needed for kLeftAlign because its adjustment is
     443             :                 // always {0, 0}.
     444           0 :                 const char* tempText = *text;
     445           0 :                 const SkGlyph &metricGlyph = fGlyphFinder->lookupGlyph(&tempText);
     446             : 
     447           0 :                 if (metricGlyph.fWidth <= 0) {
     448             :                     // Exiting early, be sure to update text pointer.
     449           0 :                     *text = tempText;
     450           0 :                     return position + SkPoint{SkFloatToScalar(metricGlyph.fAdvanceX),
     451           0 :                                               SkFloatToScalar(metricGlyph.fAdvanceY)};
     452             :                 }
     453             : 
     454             :                 // Adjust the final position by the alignment adjustment.
     455           0 :                 position -= TextAlignmentAdjustment(kTextAlignment, metricGlyph);
     456             :             }
     457             : 
     458             :             // Find the glyph.
     459           0 :             SkIPoint lookupPosition = SkScalarsAreFinite(position.fX, position.fY)
     460             :                                       ? SubpixelAlignment(kAxisAlignment, position)
     461           0 :                                       : SkIPoint{0, 0};
     462             :             const SkGlyph& renderGlyph =
     463           0 :                 fGlyphFinder->lookupGlyphXY(text, lookupPosition.fX, lookupPosition.fY);
     464             : 
     465             :             // If the glyph has no width (no pixels) then don't bother processing it.
     466           0 :             if (renderGlyph.fWidth > 0) {
     467           0 :                 processOneGlyph(renderGlyph, position,
     468             :                                 SubpixelPositionRounding(kAxisAlignment));
     469             :             }
     470           0 :             return position + SkPoint{SkFloatToScalar(renderGlyph.fAdvanceX),
     471           0 :                                       SkFloatToScalar(renderGlyph.fAdvanceY)};
     472             :         }
     473             : 
     474             :     private:
     475             :         LookupGlyph& fGlyphFinder;
     476             :     };
     477             : 
     478             :     enum SelectKerning {
     479             :         kNoKerning = false,
     480             :         kUseKerning = true
     481             :     };
     482             : 
     483             :     // GlyphFindAndPlaceFullPixel handles finding and placing glyphs when no sub-pixel
     484             :     // positioning is requested. The kUseKerning argument should be true for drawText, and false
     485             :     // for drawPosText.
     486             :     template<typename ProcessOneGlyph, SkPaint::Align kTextAlignment, SelectKerning kUseKerning>
     487          21 :     class GlyphFindAndPlaceFullPixel final : public GlyphFindAndPlaceInterface<ProcessOneGlyph> {
     488             :     public:
     489          21 :         GlyphFindAndPlaceFullPixel(LookupGlyph& glyphFinder)
     490          21 :             : fGlyphFinder(glyphFinder) {
     491          21 :             FixGCC49Arm64Bug(2);
     492             :             // Kerning can only be used with SkPaint::kLeft_Align
     493             :             static_assert(!kUseKerning || SkPaint::kLeft_Align == kTextAlignment,
     494             :                           "Kerning can only be used with left aligned text.");
     495          21 :         }
     496             : 
     497         448 :         SkPoint findAndPositionGlyph(
     498             :             const char** text, SkPoint position, ProcessOneGlyph&& processOneGlyph) override {
     499         448 :             SkPoint finalPosition = position;
     500         448 :             const SkGlyph& glyph = fGlyphFinder->lookupGlyph(text);
     501             :             if (kUseKerning) {
     502           0 :                 finalPosition += {fAutoKern.adjust(glyph), 0.0f};
     503             :             }
     504         448 :             if (glyph.fWidth > 0) {
     505         422 :                 finalPosition -= TextAlignmentAdjustment(kTextAlignment, glyph);
     506         422 :                 processOneGlyph(glyph, finalPosition, {SK_ScalarHalf, SK_ScalarHalf});
     507             :             }
     508        1344 :             return finalPosition + SkPoint{SkFloatToScalar(glyph.fAdvanceX),
     509        1344 :                                            SkFloatToScalar(glyph.fAdvanceY)};
     510             :         }
     511             : 
     512             :     private:
     513             :         LookupGlyph& fGlyphFinder;
     514             : 
     515             :         SkAutoKern fAutoKern;
     516             :     };
     517             : 
     518             :     // GlyphFindAndPlace is a large variant that encapsulates the multiple types of finding and
     519             :     // placing a glyph. There are three factors that go into the different factors.
     520             :     // * Is sub-pixel positioned - a boolean that says whether to use sub-pixel positioning.
     521             :     // * Text alignment - indicates if the glyph should be placed to the right, centered or left
     522             :     //   of a given position.
     523             :     // * Axis alignment - indicates if the glyphs final sub-pixel position should be rounded to a
     524             :     //   whole pixel if the glyph is aligned with an axis. This is only used for sub-pixel
     525             :     //   positioning and allows the baseline to look crisp.
     526             :     template<typename ProcessOneGlyph>
     527             :     using GlyphFindAndPlace = PolymorphicVariant<
     528             :         GlyphFindAndPlaceInterface<ProcessOneGlyph>,
     529             :         // Subpixel
     530             :         GlyphFindAndPlaceSubpixel<ProcessOneGlyph,  SkPaint::kLeft_Align,   kNone_SkAxisAlignment>,
     531             :         GlyphFindAndPlaceSubpixel<ProcessOneGlyph,  SkPaint::kLeft_Align,   kX_SkAxisAlignment   >,
     532             :         GlyphFindAndPlaceSubpixel<ProcessOneGlyph,  SkPaint::kLeft_Align,   kY_SkAxisAlignment   >,
     533             :         GlyphFindAndPlaceSubpixel<ProcessOneGlyph,  SkPaint::kCenter_Align, kNone_SkAxisAlignment>,
     534             :         GlyphFindAndPlaceSubpixel<ProcessOneGlyph,  SkPaint::kCenter_Align, kX_SkAxisAlignment   >,
     535             :         GlyphFindAndPlaceSubpixel<ProcessOneGlyph,  SkPaint::kCenter_Align, kY_SkAxisAlignment   >,
     536             :         GlyphFindAndPlaceSubpixel<ProcessOneGlyph,  SkPaint::kRight_Align,  kNone_SkAxisAlignment>,
     537             :         GlyphFindAndPlaceSubpixel<ProcessOneGlyph,  SkPaint::kRight_Align,  kX_SkAxisAlignment   >,
     538             :         GlyphFindAndPlaceSubpixel<ProcessOneGlyph,  SkPaint::kRight_Align,  kY_SkAxisAlignment   >,
     539             :         // Full pixel
     540             :         GlyphFindAndPlaceFullPixel<ProcessOneGlyph, SkPaint::kLeft_Align,   kNoKerning>,
     541             :         GlyphFindAndPlaceFullPixel<ProcessOneGlyph, SkPaint::kCenter_Align, kNoKerning>,
     542             :         GlyphFindAndPlaceFullPixel<ProcessOneGlyph, SkPaint::kRight_Align,  kNoKerning>
     543             :     >;
     544             : 
     545             :     // InitSubpixel is a helper function for initializing all the variants of
     546             :     // GlyphFindAndPlaceSubpixel.
     547             :     template<typename ProcessOneGlyph, SkPaint::Align kTextAlignment>
     548           0 :     static void InitSubpixel(
     549             :         typename GlyphFindAndPlace<ProcessOneGlyph>::Variants* to_init,
     550             :         SkAxisAlignment axisAlignment,
     551             :         LookupGlyph& glyphFinder) {
     552           0 :         switch (axisAlignment) {
     553             :             case kX_SkAxisAlignment:
     554           0 :                 to_init->template initialize<GlyphFindAndPlaceSubpixel<
     555             :                     ProcessOneGlyph, kTextAlignment, kX_SkAxisAlignment>>(glyphFinder);
     556           0 :                 break;
     557             :             case kNone_SkAxisAlignment:
     558           0 :                 to_init->template initialize<GlyphFindAndPlaceSubpixel<
     559             :                     ProcessOneGlyph, kTextAlignment, kNone_SkAxisAlignment>>(glyphFinder);
     560           0 :                 break;
     561             :             case kY_SkAxisAlignment:
     562           0 :                 to_init->template initialize<GlyphFindAndPlaceSubpixel<
     563             :                     ProcessOneGlyph, kTextAlignment, kY_SkAxisAlignment>>(glyphFinder);
     564           0 :                 break;
     565             :         }
     566           0 :     }
     567             : 
     568           0 :     static SkPoint MeasureText(LookupGlyph& glyphFinder, const char text[], size_t byteLength) {
     569           0 :         SkScalar    x = 0, y = 0;
     570           0 :         const char* stop = text + byteLength;
     571             : 
     572           0 :         SkAutoKern  autokern;
     573             : 
     574           0 :         while (text < stop) {
     575             :             // don't need x, y here, since all subpixel variants will have the
     576             :             // same advance
     577           0 :             const SkGlyph& glyph = glyphFinder->lookupGlyph(&text);
     578             : 
     579           0 :             x += autokern.adjust(glyph) + SkFloatToScalar(glyph.fAdvanceX);
     580           0 :             y += SkFloatToScalar(glyph.fAdvanceY);
     581             :         }
     582           0 :         SkASSERT(text == stop);
     583           0 :         return {x, y};
     584             :     }
     585             : };
     586             : 
     587             : template<typename ProcessOneGlyph>
     588          21 : inline void SkFindAndPlaceGlyph::ProcessPosText(
     589             :     SkPaint::TextEncoding textEncoding, const char text[], size_t byteLength,
     590             :     SkPoint offset, const SkMatrix& matrix, const SkScalar pos[], int scalarsPerPosition,
     591             :     SkPaint::Align textAlignment,
     592             :     SkGlyphCache* cache, ProcessOneGlyph&& processOneGlyph) {
     593             : 
     594          21 :     SkAxisAlignment axisAlignment = cache->getScalerContext()->computeAxisAlignmentForHText();
     595          21 :     uint32_t mtype = matrix.getType();
     596          42 :     LookupGlyph glyphFinder(textEncoding, cache);
     597             : 
     598             :     // Specialized code for handling the most common case for blink. The while loop is totally
     599             :     // de-virtualized.
     600          42 :     if (scalarsPerPosition == 1
     601           0 :         && textAlignment == SkPaint::kLeft_Align
     602           0 :         && axisAlignment == kX_SkAxisAlignment
     603           0 :         && cache->isSubpixel()
     604          21 :         && mtype <= SkMatrix::kTranslate_Mask) {
     605             :         typedef GlyphFindAndPlaceSubpixel<
     606             :             ProcessOneGlyph, SkPaint::kLeft_Align, kX_SkAxisAlignment> Positioner;
     607           0 :         HorizontalPositions positions{pos};
     608           0 :         TranslationMapper mapper{matrix, offset};
     609           0 :         Positioner positioner(glyphFinder);
     610           0 :         const char* cursor = text;
     611           0 :         const char* stop = text + byteLength;
     612           0 :         while (cursor < stop) {
     613           0 :             SkPoint mappedPoint = mapper.TranslationMapper::map(
     614           0 :                 positions.HorizontalPositions::nextPoint());
     615           0 :             positioner.Positioner::findAndPositionGlyph(
     616             :                 &cursor, mappedPoint, std::forward<ProcessOneGlyph>(processOneGlyph));
     617             :         }
     618           0 :         return;
     619             :     }
     620             : 
     621             :     PositionReader positionReader{
     622          21 :         [&](PositionReader::Variants* to_init) {
     623          21 :             if (2 == scalarsPerPosition) {
     624          21 :                 to_init->initialize<ArbitraryPositions>(pos);
     625             :             } else {
     626           0 :                 to_init->initialize<HorizontalPositions>(pos);
     627             :             }
     628          21 :             positionReader->forceUseForBug();
     629          21 :         }
     630          42 :     };
     631             : 
     632             :     Mapper mapper{
     633          21 :         [&](Mapper::Variants* to_init) {
     634          21 :             if (mtype & (SkMatrix::kAffine_Mask | SkMatrix::kPerspective_Mask)
     635          21 :                 || scalarsPerPosition == 2) {
     636          21 :                 to_init->initialize<GeneralMapper>(matrix, offset);
     637           0 :             } else if (mtype & SkMatrix::kScale_Mask) {
     638           0 :                 to_init->initialize<XScaleMapper>(matrix, offset);
     639             :             } else {
     640           0 :                 to_init->initialize<TranslationMapper>(matrix, offset);
     641             :             }
     642          21 :         }
     643          42 :     };
     644             : 
     645             :     GlyphFindAndPlace<ProcessOneGlyph> findAndPosition {
     646          21 :         [&](typename GlyphFindAndPlace<ProcessOneGlyph>::Variants* to_init) {
     647          21 :             if (cache->isSubpixel()) {
     648          21 :                 switch (textAlignment) {
     649             :                     case SkPaint::kLeft_Align:
     650           0 :                         InitSubpixel<ProcessOneGlyph, SkPaint::kLeft_Align>(
     651          21 :                             to_init, axisAlignment, glyphFinder);
     652           0 :                         break;
     653             :                     case SkPaint::kCenter_Align:
     654           0 :                         InitSubpixel<ProcessOneGlyph, SkPaint::kCenter_Align>(
     655             :                             to_init, axisAlignment, glyphFinder);
     656           0 :                         break;
     657             :                     case SkPaint::kRight_Align:
     658           0 :                         InitSubpixel<ProcessOneGlyph, SkPaint::kRight_Align>(
     659             :                             to_init, axisAlignment, glyphFinder);
     660           0 :                         break;
     661             :                 }
     662             :             } else {
     663          21 :                 switch (textAlignment) {
     664             :                     case SkPaint::kLeft_Align:
     665          21 :                         to_init->template initialize<
     666             :                             GlyphFindAndPlaceFullPixel<ProcessOneGlyph,
     667             :                             SkPaint::kLeft_Align, kNoKerning>>(glyphFinder);
     668          21 :                         break;
     669             :                     case SkPaint::kCenter_Align:
     670           0 :                         to_init->template initialize<
     671             :                             GlyphFindAndPlaceFullPixel<ProcessOneGlyph,
     672             :                             SkPaint::kCenter_Align, kNoKerning>>(glyphFinder);
     673           0 :                         break;
     674             :                     case SkPaint::kRight_Align:
     675           0 :                         to_init->template initialize<
     676             :                             GlyphFindAndPlaceFullPixel<ProcessOneGlyph,
     677             :                             SkPaint::kRight_Align, kNoKerning>>(glyphFinder);
     678           0 :                         break;
     679             :                 }
     680             :             }
     681          21 :         }
     682          42 :     };
     683             : 
     684          21 :     const char* stop = text + byteLength;
     685         917 :     while (text < stop) {
     686         448 :         SkPoint mappedPoint = mapper->map(positionReader->nextPoint());
     687         448 :         findAndPosition->findAndPositionGlyph(
     688             :             &text, mappedPoint, std::forward<ProcessOneGlyph>(processOneGlyph));
     689             :     }
     690             : }
     691             : 
     692             : template<typename ProcessOneGlyph>
     693           0 : inline void SkFindAndPlaceGlyph::ProcessText(
     694             :     SkPaint::TextEncoding textEncoding, const char text[], size_t byteLength,
     695             :     SkPoint offset, const SkMatrix& matrix, SkPaint::Align textAlignment,
     696             :     SkGlyphCache* cache, ProcessOneGlyph&& processOneGlyph) {
     697             : 
     698             :     // transform the starting point
     699           0 :     matrix.mapPoints(&offset, 1);
     700             : 
     701           0 :     LookupGlyph glyphFinder(textEncoding, cache);
     702             : 
     703             :     // need to measure first
     704           0 :     if (textAlignment != SkPaint::kLeft_Align) {
     705           0 :         SkVector stop = MeasureText(glyphFinder, text, byteLength);
     706             : 
     707           0 :         if (textAlignment == SkPaint::kCenter_Align) {
     708           0 :             stop *= SK_ScalarHalf;
     709             :         }
     710           0 :         offset -= stop;
     711             :     }
     712             : 
     713             :     GlyphFindAndPlace<ProcessOneGlyph> findAndPosition{
     714           0 :         [&](typename GlyphFindAndPlace<ProcessOneGlyph>::Variants* to_init) {
     715           0 :             if (cache->isSubpixel()) {
     716             :                 SkAxisAlignment axisAlignment =
     717           0 :                     cache->getScalerContext()->computeAxisAlignmentForHText();
     718           0 :                 InitSubpixel<ProcessOneGlyph, SkPaint::kLeft_Align>(
     719           0 :                     to_init, axisAlignment, glyphFinder);
     720             :             } else {
     721           0 :                 to_init->template initialize<
     722             :                     GlyphFindAndPlaceFullPixel<
     723             :                         ProcessOneGlyph, SkPaint::kLeft_Align, kUseKerning>>(glyphFinder);
     724             :             }
     725           0 :         }
     726           0 :     };
     727             : 
     728           0 :     const char* stop = text + byteLength;
     729           0 :     SkPoint current = offset;
     730           0 :     while (text < stop) {
     731           0 :         current =
     732           0 :             findAndPosition->findAndPositionGlyph(
     733             :                 &text, current, std::forward<ProcessOneGlyph>(processOneGlyph));
     734             : 
     735             :     }
     736           0 : }
     737             : 
     738             : #endif  // SkFindAndPositionGlyph_DEFINED

Generated by: LCOV version 1.13