1e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb/*
2e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb * Copyright 2015 Google Inc.
3e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb *
4e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb * Use of this source code is governed by a BSD-style license that can be
5e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb * found in the LICENSE file.
6e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb */
7e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb
8e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb#ifndef SkFindAndPositionGlyph_DEFINED
9e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb#define SkFindAndPositionGlyph_DEFINED
10e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb
11e59124ed1a62f1fec79679c38cabed622a756f75herb#include "SkAutoKern.h"
12e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb#include "SkGlyph.h"
13e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb#include "SkGlyphCache.h"
14e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb#include "SkPaint.h"
15e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb#include "SkTemplates.h"
164c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb#include "SkUtils.h"
17221524de3be1fc343ad328c5e99562f32b5cad9cbungeman#include <utility>
18e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb
19e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb// Calculate a type with the same size as the max of all the Ts.
20e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb// This must be top level because the is no specialization of inner classes.
21e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherbtemplate<typename... Ts> struct SkMaxSizeOf;
22e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb
23e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherbtemplate<>
24e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherbstruct SkMaxSizeOf<> {
25e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb    static const size_t value = 0;
26e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb};
27e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb
28e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherbtemplate<typename H, typename... Ts>
29e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherbstruct SkMaxSizeOf<H, Ts...> {
30e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb    static const size_t value =
31e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb        sizeof(H) >= SkMaxSizeOf<Ts...>::value ? sizeof(H) : SkMaxSizeOf<Ts...>::value;
32e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb};
33e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb
34d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb
35d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb// This is a temporary helper function to work around a bug in the code generation
36d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb// for aarch64 (arm) on GCC 4.9. This bug does not show up on other platforms, so it
37d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb// seems to be an aarch64 backend problem.
38d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb//
39d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb// GCC 4.9 on ARM64 does not generate the proper constructor code for PositionReader or
40d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb// GlyphFindAndPlace. The vtable is not set properly without adding the fixme code.
41d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb// The implementation is in SkDraw.cpp.
42d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herbextern void FixGCC49Arm64Bug(int v);
43d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb
44e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherbclass SkFindAndPlaceGlyph {
45e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherbpublic:
46e59124ed1a62f1fec79679c38cabed622a756f75herb    template<typename ProcessOneGlyph>
474c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb    static void ProcessText(
484c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb        SkPaint::TextEncoding, const char text[], size_t byteLength,
494c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb        SkPoint offset, const SkMatrix& matrix, SkPaint::Align textAlignment,
504c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb        SkGlyphCache* cache, ProcessOneGlyph&& processOneGlyph);
51e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb    // ProcessPosText handles all cases for finding and positioning glyphs. It has a very large
52e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb    // multiplicity. It figures out the glyph, position and rounding and pass those parameters to
53e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb    // processOneGlyph.
54e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb    //
55e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb    // The routine processOneGlyph passed in by the client has the following signature:
56e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb    // void f(const SkGlyph& glyph, SkPoint position, SkPoint rounding);
57e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb    //
58e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb    // * Sub-pixel positioning (2) - use sub-pixel positioning.
59e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb    // * Text alignment (3) - text alignment with respect to the glyph's width.
60e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb    // * Matrix type (3) - special cases for translation and X-coordinate scaling.
61e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb    // * Components per position (2) - the positions vector can have a common Y with different
62e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb    //   Xs, or XY-pairs.
63e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb    // * Axis Alignment (for sub-pixel positioning) (3) - when using sub-pixel positioning, round
64e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb    //   to a whole coordinate instead of using sub-pixel positioning.
65e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb    // The number of variations is 108 for sub-pixel and 36 for full-pixel.
66e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb    // This routine handles all of them using inline polymorphic variable (no heap allocation).
67e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb    template<typename ProcessOneGlyph>
684c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb    static void ProcessPosText(
694c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb        SkPaint::TextEncoding, const char text[], size_t byteLength,
704c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb        SkPoint offset, const SkMatrix& matrix, const SkScalar pos[], int scalarsPerPosition,
714c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb        SkPaint::Align textAlignment,
724c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb        SkGlyphCache* cache, ProcessOneGlyph&& processOneGlyph);
73e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb
74e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherbprivate:
75e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb    // UntaggedVariant is a pile of memory that can hold one of the Ts. It provides a way
76e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb    // to initialize that memory in a typesafe way.
77e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb    template<typename... Ts>
78e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb    class UntaggedVariant {
79e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb    public:
80e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb        UntaggedVariant() { }
81e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb
82e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb        ~UntaggedVariant() { }
83e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb        UntaggedVariant(const UntaggedVariant&) = delete;
84e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb        UntaggedVariant& operator=(const UntaggedVariant&) = delete;
85e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb        UntaggedVariant(UntaggedVariant&&) = delete;
86e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb        UntaggedVariant& operator=(UntaggedVariant&&) = delete;
87e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb
88e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb        template<typename Variant, typename... Args>
89e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb        void initialize(Args&&... args) {
90e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb            SkASSERT(sizeof(Variant) <= sizeof(fSpace));
91e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb        #if defined(_MSC_VER) && _MSC_VER < 1900
92e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb            #define alignof __alignof
93e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb        #endif
94e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb            SkASSERT(alignof(Variant) <= alignof(Space));
95221524de3be1fc343ad328c5e99562f32b5cad9cbungeman            new(&fSpace) Variant(std::forward<Args>(args)...);
96e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb        }
97e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb
98e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb    private:
99e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb        typedef SkAlignedSStorage<SkMaxSizeOf<Ts...>::value> Space;
100e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb        Space fSpace;
101e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb    };
102e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb
103e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb    // PolymorphicVariant holds subclasses of Base without slicing. Ts must be subclasses of Base.
104e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb    template<typename Base, typename... Ts>
105e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb    class PolymorphicVariant {
106e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb    public:
107e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb        typedef UntaggedVariant<Ts...> Variants;
108e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb
109e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb        template<typename Initializer>
110e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb        PolymorphicVariant(Initializer&& initializer) {
111e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb            initializer(&fVariants);
112e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb        }
113e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb        ~PolymorphicVariant() { get()->~Base(); }
114e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb        Base* get() const { return reinterpret_cast<Base*>(&fVariants); }
115e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb        Base* operator->() const { return get(); }
116e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb        Base& operator*() const { return *get(); }
117e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb
118e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb    private:
119e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb        mutable Variants fVariants;
120e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb    };
121e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb
1224c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb    // GlyphFinderInterface is the polymorphic base for classes that parse a stream of chars into
1234c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb    // the right UniChar (or GlyphID) and lookup up the glyph on the cache. The concrete
1244c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb    // implementations are: Utf8GlyphFinder, Utf16GlyphFinder, Utf32GlyphFinder,
1254c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb    // and GlyphIdGlyphFinder.
1264c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb    class GlyphFinderInterface {
1274c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb    public:
1284c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb        virtual ~GlyphFinderInterface() {}
1294c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb        virtual const SkGlyph& lookupGlyph(const char** text) = 0;
1304c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb        virtual const SkGlyph& lookupGlyphXY(const char** text, SkFixed x, SkFixed y) = 0;
1314c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb    };
1324c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb
1334c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb    class UtfNGlyphFinder : public GlyphFinderInterface {
1344c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb    public:
1354c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb        UtfNGlyphFinder(SkGlyphCache* cache) : fCache(cache) { SkASSERT(cache != nullptr); }
1364c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb
1374c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb        const SkGlyph& lookupGlyph(const char** text) override {
1384c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb            SkASSERT(text != nullptr);
1394c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb            return fCache->getUnicharMetrics(nextUnichar(text));
1404c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb        }
1414c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb        const SkGlyph& lookupGlyphXY(const char** text, SkFixed x, SkFixed y) override {
1424c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb            SkASSERT(text != nullptr);
1434c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb            return fCache->getUnicharMetrics(nextUnichar(text), x, y);
1444c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb        }
1454c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb
1464c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb    private:
1474c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb        virtual SkUnichar nextUnichar(const char** text) = 0;
1484c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb        SkGlyphCache* fCache;
1494c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb    };
1504c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb
1514c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb    class Utf8GlyphFinder final : public UtfNGlyphFinder {
1524c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb    public:
1534c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb        Utf8GlyphFinder(SkGlyphCache* cache) : UtfNGlyphFinder(cache) { }
1544c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb
1554c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb    private:
1564c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb        SkUnichar nextUnichar(const char** text) override { return SkUTF8_NextUnichar(text); }
1574c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb    };
1584c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb
1594c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb    class Utf16GlyphFinder final : public UtfNGlyphFinder {
1604c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb    public:
1614c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb        Utf16GlyphFinder(SkGlyphCache* cache) : UtfNGlyphFinder(cache) { }
1624c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb
1634c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb    private:
1644c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb        SkUnichar nextUnichar(const char** text) override {
1654c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb            return SkUTF16_NextUnichar((const uint16_t**)text);
1664c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb        }
1674c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb    };
1684c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb
1694c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb    class Utf32GlyphFinder final : public UtfNGlyphFinder {
1704c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb    public:
1714c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb        Utf32GlyphFinder(SkGlyphCache* cache) : UtfNGlyphFinder(cache) { }
1724c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb
1734c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb    private:
1744c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb        SkUnichar nextUnichar(const char** text) override {
1754c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb            const int32_t* ptr = *(const int32_t**)text;
1764c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb            SkUnichar uni = *ptr++;
1774c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb            *text = (const char*)ptr;
1784c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb            return uni;
1794c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb        }
1804c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb    };
1814c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb
1824c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb    class GlyphIdGlyphFinder final : public GlyphFinderInterface {
1834c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb    public:
1844c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb        GlyphIdGlyphFinder(SkGlyphCache* cache) : fCache(cache) { SkASSERT(cache != nullptr); }
1854c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb
1864c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb        const SkGlyph& lookupGlyph(const char** text) override {
1874c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb            return fCache->getGlyphIDMetrics(nextGlyphId(text));
1884c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb        }
1894c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb        const SkGlyph& lookupGlyphXY(const char** text, SkFixed x, SkFixed y) override {
1904c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb            return fCache->getGlyphIDMetrics(nextGlyphId(text), x, y);
1914c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb        }
1924c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb
1934c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb    private:
1944c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb        uint16_t nextGlyphId(const char** text) {
1954c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb            SkASSERT(text != nullptr);
1964c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb
1974c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb            const uint16_t* ptr = *(const uint16_t**)text;
1984c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb            uint16_t glyphID = *ptr;
1994c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb            ptr += 1;
2004c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb            *text = (const char*)ptr;
2014c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb            return glyphID;
2024c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb        }
2034c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb        SkGlyphCache* fCache;
2044c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb    };
2054c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb
2064c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb    typedef PolymorphicVariant<
2074c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb        GlyphFinderInterface,
2084c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb        Utf8GlyphFinder,
2094c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb        Utf16GlyphFinder,
2104c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb        Utf32GlyphFinder,
2114c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb        GlyphIdGlyphFinder> LookupGlyphVariant;
2124c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb
2134c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb    class LookupGlyph : public LookupGlyphVariant {
2144c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb    public:
2154c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb        LookupGlyph(SkPaint::TextEncoding encoding, SkGlyphCache* cache)
2164c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb            : LookupGlyphVariant(
2174c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb            [&](LookupGlyphVariant::Variants* to_init) {
2184c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb                switch(encoding) {
2194c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb                    case SkPaint::kUTF8_TextEncoding:
2204c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb                        to_init->initialize<Utf8GlyphFinder>(cache);
2214c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb                        break;
2224c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb                    case SkPaint::kUTF16_TextEncoding:
2234c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb                        to_init->initialize<Utf16GlyphFinder>(cache);
2244c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb                        break;
2254c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb                    case SkPaint::kUTF32_TextEncoding:
2264c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb                        to_init->initialize<Utf32GlyphFinder>(cache);
2274c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb                        break;
2284c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb                    case SkPaint::kGlyphID_TextEncoding:
2294c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb                        to_init->initialize<GlyphIdGlyphFinder>(cache);
2304c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb                        break;
2314c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb                }
2324c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb            }
2334c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb        ) { }
2344c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb    };
2354c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb
236e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb    // PositionReaderInterface reads a point from the pos vector.
237e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb    // * HorizontalPositions - assumes a common Y for many X values.
238e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb    // * ArbitraryPositions - a list of (X,Y) pairs.
239e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb    class PositionReaderInterface {
240e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb    public:
241e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb        virtual ~PositionReaderInterface() { }
242e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb        virtual SkPoint nextPoint() = 0;
243d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb        // This is only here to fix a GCC 4.9 aarch64 code gen bug.
244d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb        // See comment at the top of the file.
245d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb        virtual int forceUseForBug() = 0;
246e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb    };
247e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb
248e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb    class HorizontalPositions final : public PositionReaderInterface {
249e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb    public:
250e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb        explicit HorizontalPositions(const SkScalar* positions)
251e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb            : fPositions(positions) { }
252e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb
253e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb        SkPoint nextPoint() override {
254e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb            SkScalar x = *fPositions++;
255e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb            return {x, 0};
256e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb        }
257e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb
258d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb        int forceUseForBug() override { return 1; }
259d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb
260e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb    private:
261e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb        const SkScalar* fPositions;
262e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb    };
263e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb
264e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb    class ArbitraryPositions final : public PositionReaderInterface {
265e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb    public:
266e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb        explicit ArbitraryPositions(const SkScalar* positions)
267e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb            : fPositions(positions) { }
268e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb
269e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb        SkPoint nextPoint() override {
270e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb            SkPoint to_return{fPositions[0], fPositions[1]};
271e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb            fPositions += 2;
272e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb            return to_return;
273e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb        }
274e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb
275d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb        int forceUseForBug() override { return 2; }
276d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb
277e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb    private:
278e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb        const SkScalar* fPositions;
279e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb    };
280e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb
281e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb    typedef PolymorphicVariant<PositionReaderInterface, HorizontalPositions, ArbitraryPositions>
282e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb        PositionReader;
283e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb
284e59124ed1a62f1fec79679c38cabed622a756f75herb    // MapperInterface given a point map it through the matrix. There are several shortcut
285e59124ed1a62f1fec79679c38cabed622a756f75herb    // variants.
286e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb    // * TranslationMapper - assumes a translation only matrix.
287e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb    // * XScaleMapper - assumes an X scaling and a translation.
288e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb    // * GeneralMapper - Does all other matricies.
289e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb    class MapperInterface {
290e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb    public:
291e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb        virtual ~MapperInterface() { }
292e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb
293e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb        virtual SkPoint map(SkPoint position) const = 0;
294e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb    };
295e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb
296e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb    class TranslationMapper final : public MapperInterface {
297e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb    public:
298e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb        TranslationMapper(const SkMatrix& matrix, const SkPoint origin)
299e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb            : fTranslate(matrix.mapXY(origin.fX, origin.fY)) { }
300e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb
301e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb        SkPoint map(SkPoint position) const override {
302e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb            return position + fTranslate;
303e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb        }
304e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb
305e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb    private:
306e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb        const SkPoint fTranslate;
307e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb    };
308e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb
309e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb    class XScaleMapper final : public MapperInterface {
310e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb    public:
311e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb        XScaleMapper(const SkMatrix& matrix, const SkPoint origin)
312e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb            : fTranslate(matrix.mapXY(origin.fX, origin.fY)), fXScale(matrix.getScaleX()) { }
313e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb
314e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb        SkPoint map(SkPoint position) const override {
315e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb            return {fXScale * position.fX + fTranslate.fX, fTranslate.fY};
316e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb        }
317e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb
318e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb    private:
319e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb        const SkPoint fTranslate;
320e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb        const SkScalar fXScale;
321e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb    };
322e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb
323e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb    // The caller must keep matrix alive while this class is used.
324e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb    class GeneralMapper final : public MapperInterface {
325e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb    public:
326e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb        GeneralMapper(const SkMatrix& matrix, const SkPoint origin)
327e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb            : fOrigin(origin), fMatrix(matrix), fMapProc(matrix.getMapXYProc()) { }
328e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb
329e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb        SkPoint map(SkPoint position) const override {
330e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb            SkPoint result;
331e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb            fMapProc(fMatrix, position.fX + fOrigin.fX, position.fY + fOrigin.fY, &result);
332e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb            return result;
333e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb        }
334e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb
335e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb    private:
336e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb        const SkPoint fOrigin;
337e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb        const SkMatrix& fMatrix;
338e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb        const SkMatrix::MapXYProc fMapProc;
339e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb    };
340e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb
341e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb    typedef PolymorphicVariant<
342e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb        MapperInterface, TranslationMapper, XScaleMapper, GeneralMapper> Mapper;
343e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb
344e59124ed1a62f1fec79679c38cabed622a756f75herb    // TextAlignmentAdjustment handles shifting the glyph based on its width.
345e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb    static SkPoint TextAlignmentAdjustment(SkPaint::Align textAlignment, const SkGlyph& glyph) {
346e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb        switch (textAlignment) {
347e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb            case SkPaint::kLeft_Align:
348e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb                return {0.0f, 0.0f};
349e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb            case SkPaint::kCenter_Align:
3506b3eacb0dfaeb3374d410c8c041bd39cd066e1eabenjaminwagner                return {SkFloatToScalar(glyph.fAdvanceX) / 2,
3516b3eacb0dfaeb3374d410c8c041bd39cd066e1eabenjaminwagner                        SkFloatToScalar(glyph.fAdvanceY) / 2};
352e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb            case SkPaint::kRight_Align:
3536b3eacb0dfaeb3374d410c8c041bd39cd066e1eabenjaminwagner                return {SkFloatToScalar(glyph.fAdvanceX),
3546b3eacb0dfaeb3374d410c8c041bd39cd066e1eabenjaminwagner                        SkFloatToScalar(glyph.fAdvanceY)};
355e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb        }
356e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb        // Even though the entire enum is covered above, MVSC doesn't think so. Make it happy.
357e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb        SkFAIL("Should never get here.");
358e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb        return {0.0f, 0.0f};
359e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb    }
360e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb
361e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb    // The "call" to SkFixedToScalar is actually a macro. It's macros all the way down.
362e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb    // Needs to be a macro because you can't have a const float unless you make it constexpr.
363e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb    #define kSubpixelRounding (SkFixedToScalar(SkGlyph::kSubpixelRound))
364e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb
365e59124ed1a62f1fec79679c38cabed622a756f75herb    // The SubpixelPositionRounding function returns a point suitable for rounding a sub-pixel
366e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb    // positioned glyph.
367e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb    static SkPoint SubpixelPositionRounding(SkAxisAlignment axisAlignment) {
368e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb        switch (axisAlignment) {
369e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb            case kX_SkAxisAlignment:
370fa5e5c75218a877d30177d08686d8ec0ea050b0abungeman                return {kSubpixelRounding, SK_ScalarHalf};
371e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb            case kY_SkAxisAlignment:
372e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb                return {SK_ScalarHalf, kSubpixelRounding};
373e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb            case kNone_SkAxisAlignment:
374e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb                return {kSubpixelRounding, kSubpixelRounding};
375e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb        }
376e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb        SkFAIL("Should not get here.");
377e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb        return {0.0f, 0.0f};
378e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb    }
379e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb
380e59124ed1a62f1fec79679c38cabed622a756f75herb    // The SubpixelAlignment function produces a suitable position for the glyph cache to
381e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb    // produce the correct sub-pixel alignment. If a position is aligned with an axis a shortcut
382e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb    // of 0 is used for the sub-pixel position.
383e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb    static SkIPoint SubpixelAlignment(SkAxisAlignment axisAlignment, SkPoint position) {
384db6bd3239fd5e35797a9aa36eb0044ecbe5557c4benjaminwagner        // Only the fractional part of position.fX and position.fY matter, because the result of
385db6bd3239fd5e35797a9aa36eb0044ecbe5557c4benjaminwagner        // this function will just be passed to FixedToSub.
386e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb        switch (axisAlignment) {
387e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb            case kX_SkAxisAlignment:
388db6bd3239fd5e35797a9aa36eb0044ecbe5557c4benjaminwagner                return {SkScalarToFixed(SkScalarFraction(position.fX) + kSubpixelRounding), 0};
389e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb            case kY_SkAxisAlignment:
390db6bd3239fd5e35797a9aa36eb0044ecbe5557c4benjaminwagner                return {0, SkScalarToFixed(SkScalarFraction(position.fY) + kSubpixelRounding)};
391e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb            case kNone_SkAxisAlignment:
392db6bd3239fd5e35797a9aa36eb0044ecbe5557c4benjaminwagner                return {SkScalarToFixed(SkScalarFraction(position.fX) + kSubpixelRounding),
393db6bd3239fd5e35797a9aa36eb0044ecbe5557c4benjaminwagner                        SkScalarToFixed(SkScalarFraction(position.fY) + kSubpixelRounding)};
394e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb        }
395e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb        SkFAIL("Should not get here.");
396e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb        return {0, 0};
397e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb    }
398e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb
399e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb    #undef kSubpixelRounding
400e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb
401e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb    // GlyphFindAndPlaceInterface given the text and position finds the correct glyph and does
402e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb    // glyph specific position adjustment. The findAndPositionGlyph method takes text and
403e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb    // position and calls processOneGlyph with the correct glyph, final position and rounding
404e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb    // terms. The final position is not rounded yet and is the responsibility of processOneGlyph.
405e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb    template<typename ProcessOneGlyph>
406e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb    class GlyphFindAndPlaceInterface : SkNoncopyable {
407e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb    public:
408fc6c37b981daeece7474ce61070c707c37eefa62Mike Klein        virtual ~GlyphFindAndPlaceInterface() { }
409e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb
410e59124ed1a62f1fec79679c38cabed622a756f75herb        // findAndPositionGlyph calculates the position of the glyph, finds the glyph, and
411e59124ed1a62f1fec79679c38cabed622a756f75herb        // returns the position of where the next glyph will be using the glyph's advance and
412e59124ed1a62f1fec79679c38cabed622a756f75herb        // possibly kerning. The returned position is used by drawText, but ignored by drawPosText.
413e59124ed1a62f1fec79679c38cabed622a756f75herb        // The compiler should prune all this calculation if the return value is not used.
414e59124ed1a62f1fec79679c38cabed622a756f75herb        //
415e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb        // This should be a pure virtual, but some versions of GCC <= 4.8 have a bug that causes a
416e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb        // compile error.
417e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb        // See GCC bug: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=60277
418e59124ed1a62f1fec79679c38cabed622a756f75herb        virtual SkPoint findAndPositionGlyph(
419e59124ed1a62f1fec79679c38cabed622a756f75herb            const char** text, SkPoint position, ProcessOneGlyph&& processOneGlyph) {
420e59124ed1a62f1fec79679c38cabed622a756f75herb            SkFAIL("Should never get here.");
421e59124ed1a62f1fec79679c38cabed622a756f75herb            return {0.0f, 0.0f};
422fc6c37b981daeece7474ce61070c707c37eefa62Mike Klein        }
423e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb    };
424e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb
425e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb    // GlyphFindAndPlaceSubpixel handles finding and placing glyphs when sub-pixel positioning is
426e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb    // requested. After it has found and placed the glyph it calls the templated function
427e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb    // ProcessOneGlyph in order to actually perform an action.
428e59124ed1a62f1fec79679c38cabed622a756f75herb    template<typename ProcessOneGlyph, SkPaint::Align kTextAlignment,
429e59124ed1a62f1fec79679c38cabed622a756f75herb             SkAxisAlignment kAxisAlignment>
430e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb    class GlyphFindAndPlaceSubpixel final : public GlyphFindAndPlaceInterface<ProcessOneGlyph> {
431e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb    public:
4324c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb        GlyphFindAndPlaceSubpixel(LookupGlyph& glyphFinder)
433d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb            : fGlyphFinder(glyphFinder) {
434d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb            FixGCC49Arm64Bug(1);
435d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb        }
436e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb
437e59124ed1a62f1fec79679c38cabed622a756f75herb        SkPoint findAndPositionGlyph(
438e59124ed1a62f1fec79679c38cabed622a756f75herb            const char** text, SkPoint position, ProcessOneGlyph&& processOneGlyph) override {
439428dfe01fca286d6ef952242388a1075b80bb4eeHerb Derby
440e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb            if (kTextAlignment != SkPaint::kLeft_Align) {
441e59124ed1a62f1fec79679c38cabed622a756f75herb                // Get the width of an un-sub-pixel positioned glyph for calculating the
442e59124ed1a62f1fec79679c38cabed622a756f75herb                // alignment. This is not needed for kLeftAlign because its adjustment is
443e59124ed1a62f1fec79679c38cabed622a756f75herb                // always {0, 0}.
444e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb                const char* tempText = *text;
4454c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb                const SkGlyph &metricGlyph = fGlyphFinder->lookupGlyph(&tempText);
446e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb
447e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb                if (metricGlyph.fWidth <= 0) {
448386127f1d431ef64bf655f39994f17daadfb5269herb                    // Exiting early, be sure to update text pointer.
449386127f1d431ef64bf655f39994f17daadfb5269herb                    *text = tempText;
450428dfe01fca286d6ef952242388a1075b80bb4eeHerb Derby                    return position + SkPoint{SkFloatToScalar(metricGlyph.fAdvanceX),
451428dfe01fca286d6ef952242388a1075b80bb4eeHerb Derby                                              SkFloatToScalar(metricGlyph.fAdvanceY)};
452e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb                }
453e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb
454e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb                // Adjust the final position by the alignment adjustment.
455428dfe01fca286d6ef952242388a1075b80bb4eeHerb Derby                position -= TextAlignmentAdjustment(kTextAlignment, metricGlyph);
456e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb            }
457e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb
458e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb            // Find the glyph.
459428dfe01fca286d6ef952242388a1075b80bb4eeHerb Derby            SkIPoint lookupPosition = SkScalarsAreFinite(position.fX, position.fY)
460428dfe01fca286d6ef952242388a1075b80bb4eeHerb Derby                                      ? SubpixelAlignment(kAxisAlignment, position)
461428dfe01fca286d6ef952242388a1075b80bb4eeHerb Derby                                      : SkIPoint{0, 0};
462e59124ed1a62f1fec79679c38cabed622a756f75herb            const SkGlyph& renderGlyph =
4634c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb                fGlyphFinder->lookupGlyphXY(text, lookupPosition.fX, lookupPosition.fY);
464e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb
465e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb            // If the glyph has no width (no pixels) then don't bother processing it.
466e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb            if (renderGlyph.fWidth > 0) {
467428dfe01fca286d6ef952242388a1075b80bb4eeHerb Derby                processOneGlyph(renderGlyph, position,
468e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb                                SubpixelPositionRounding(kAxisAlignment));
469e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb            }
470428dfe01fca286d6ef952242388a1075b80bb4eeHerb Derby            return position + SkPoint{SkFloatToScalar(renderGlyph.fAdvanceX),
471428dfe01fca286d6ef952242388a1075b80bb4eeHerb Derby                                      SkFloatToScalar(renderGlyph.fAdvanceY)};
472e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb        }
473e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb
474e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb    private:
4754c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb        LookupGlyph& fGlyphFinder;
476e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb    };
477e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb
478e59124ed1a62f1fec79679c38cabed622a756f75herb    enum SelectKerning {
479e59124ed1a62f1fec79679c38cabed622a756f75herb        kNoKerning = false,
480e59124ed1a62f1fec79679c38cabed622a756f75herb        kUseKerning = true
481e59124ed1a62f1fec79679c38cabed622a756f75herb    };
482e59124ed1a62f1fec79679c38cabed622a756f75herb
483e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb    // GlyphFindAndPlaceFullPixel handles finding and placing glyphs when no sub-pixel
484e59124ed1a62f1fec79679c38cabed622a756f75herb    // positioning is requested. The kUseKerning argument should be true for drawText, and false
485e59124ed1a62f1fec79679c38cabed622a756f75herb    // for drawPosText.
486e59124ed1a62f1fec79679c38cabed622a756f75herb    template<typename ProcessOneGlyph, SkPaint::Align kTextAlignment, SelectKerning kUseKerning>
487e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb    class GlyphFindAndPlaceFullPixel final : public GlyphFindAndPlaceInterface<ProcessOneGlyph> {
488e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb    public:
4894c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb        GlyphFindAndPlaceFullPixel(LookupGlyph& glyphFinder)
4904c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb            : fGlyphFinder(glyphFinder) {
491d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb            FixGCC49Arm64Bug(2);
492e59124ed1a62f1fec79679c38cabed622a756f75herb            // Kerning can only be used with SkPaint::kLeft_Align
493e59124ed1a62f1fec79679c38cabed622a756f75herb            static_assert(!kUseKerning || SkPaint::kLeft_Align == kTextAlignment,
494e59124ed1a62f1fec79679c38cabed622a756f75herb                          "Kerning can only be used with left aligned text.");
495e59124ed1a62f1fec79679c38cabed622a756f75herb        }
496e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb
497e59124ed1a62f1fec79679c38cabed622a756f75herb        SkPoint findAndPositionGlyph(
498e59124ed1a62f1fec79679c38cabed622a756f75herb            const char** text, SkPoint position, ProcessOneGlyph&& processOneGlyph) override {
499e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb            SkPoint finalPosition = position;
5004c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb            const SkGlyph& glyph = fGlyphFinder->lookupGlyph(text);
501e59124ed1a62f1fec79679c38cabed622a756f75herb            if (kUseKerning) {
5026b3eacb0dfaeb3374d410c8c041bd39cd066e1eabenjaminwagner                finalPosition += {fAutoKern.adjust(glyph), 0.0f};
503e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb            }
504e59124ed1a62f1fec79679c38cabed622a756f75herb            if (glyph.fWidth > 0) {
505e59124ed1a62f1fec79679c38cabed622a756f75herb                finalPosition -= TextAlignmentAdjustment(kTextAlignment, glyph);
506e59124ed1a62f1fec79679c38cabed622a756f75herb                processOneGlyph(glyph, finalPosition, {SK_ScalarHalf, SK_ScalarHalf});
507e59124ed1a62f1fec79679c38cabed622a756f75herb            }
5086b3eacb0dfaeb3374d410c8c041bd39cd066e1eabenjaminwagner            return finalPosition + SkPoint{SkFloatToScalar(glyph.fAdvanceX),
5096b3eacb0dfaeb3374d410c8c041bd39cd066e1eabenjaminwagner                                           SkFloatToScalar(glyph.fAdvanceY)};
510e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb        }
511e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb
512e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb    private:
5134c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb        LookupGlyph& fGlyphFinder;
5144c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb
515e59124ed1a62f1fec79679c38cabed622a756f75herb        SkAutoKern fAutoKern;
516e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb    };
517e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb
518e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb    // GlyphFindAndPlace is a large variant that encapsulates the multiple types of finding and
519e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb    // placing a glyph. There are three factors that go into the different factors.
520e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb    // * Is sub-pixel positioned - a boolean that says whether to use sub-pixel positioning.
521e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb    // * Text alignment - indicates if the glyph should be placed to the right, centered or left
522e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb    //   of a given position.
523e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb    // * Axis alignment - indicates if the glyphs final sub-pixel position should be rounded to a
524e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb    //   whole pixel if the glyph is aligned with an axis. This is only used for sub-pixel
525e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb    //   positioning and allows the baseline to look crisp.
526e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb    template<typename ProcessOneGlyph>
527e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb    using GlyphFindAndPlace = PolymorphicVariant<
528e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb        GlyphFindAndPlaceInterface<ProcessOneGlyph>,
529e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb        // Subpixel
530e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb        GlyphFindAndPlaceSubpixel<ProcessOneGlyph,  SkPaint::kLeft_Align,   kNone_SkAxisAlignment>,
531e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb        GlyphFindAndPlaceSubpixel<ProcessOneGlyph,  SkPaint::kLeft_Align,   kX_SkAxisAlignment   >,
532e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb        GlyphFindAndPlaceSubpixel<ProcessOneGlyph,  SkPaint::kLeft_Align,   kY_SkAxisAlignment   >,
533e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb        GlyphFindAndPlaceSubpixel<ProcessOneGlyph,  SkPaint::kCenter_Align, kNone_SkAxisAlignment>,
534e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb        GlyphFindAndPlaceSubpixel<ProcessOneGlyph,  SkPaint::kCenter_Align, kX_SkAxisAlignment   >,
535e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb        GlyphFindAndPlaceSubpixel<ProcessOneGlyph,  SkPaint::kCenter_Align, kY_SkAxisAlignment   >,
536e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb        GlyphFindAndPlaceSubpixel<ProcessOneGlyph,  SkPaint::kRight_Align,  kNone_SkAxisAlignment>,
537e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb        GlyphFindAndPlaceSubpixel<ProcessOneGlyph,  SkPaint::kRight_Align,  kX_SkAxisAlignment   >,
538e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb        GlyphFindAndPlaceSubpixel<ProcessOneGlyph,  SkPaint::kRight_Align,  kY_SkAxisAlignment   >,
539e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb        // Full pixel
540e59124ed1a62f1fec79679c38cabed622a756f75herb        GlyphFindAndPlaceFullPixel<ProcessOneGlyph, SkPaint::kLeft_Align,   kNoKerning>,
541e59124ed1a62f1fec79679c38cabed622a756f75herb        GlyphFindAndPlaceFullPixel<ProcessOneGlyph, SkPaint::kCenter_Align, kNoKerning>,
542e59124ed1a62f1fec79679c38cabed622a756f75herb        GlyphFindAndPlaceFullPixel<ProcessOneGlyph, SkPaint::kRight_Align,  kNoKerning>
543e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb    >;
544e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb
545e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb    // InitSubpixel is a helper function for initializing all the variants of
546e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb    // GlyphFindAndPlaceSubpixel.
547e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb    template<typename ProcessOneGlyph, SkPaint::Align kTextAlignment>
548e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb    static void InitSubpixel(
549e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb        typename GlyphFindAndPlace<ProcessOneGlyph>::Variants* to_init,
550e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb        SkAxisAlignment axisAlignment,
5514c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb        LookupGlyph& glyphFinder) {
552e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb        switch (axisAlignment) {
553e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb            case kX_SkAxisAlignment:
554e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb                to_init->template initialize<GlyphFindAndPlaceSubpixel<
5554c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb                    ProcessOneGlyph, kTextAlignment, kX_SkAxisAlignment>>(glyphFinder);
556e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb                break;
557e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb            case kNone_SkAxisAlignment:
558e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb                to_init->template initialize<GlyphFindAndPlaceSubpixel<
5594c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb                    ProcessOneGlyph, kTextAlignment, kNone_SkAxisAlignment>>(glyphFinder);
560e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb                break;
561e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb            case kY_SkAxisAlignment:
562e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb                to_init->template initialize<GlyphFindAndPlaceSubpixel<
5634c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb                    ProcessOneGlyph, kTextAlignment, kY_SkAxisAlignment>>(glyphFinder);
564e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb                break;
565e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb        }
566e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb    }
567e59124ed1a62f1fec79679c38cabed622a756f75herb
5684c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb    static SkPoint MeasureText(LookupGlyph& glyphFinder, const char text[], size_t byteLength) {
5696b3eacb0dfaeb3374d410c8c041bd39cd066e1eabenjaminwagner        SkScalar    x = 0, y = 0;
570e59124ed1a62f1fec79679c38cabed622a756f75herb        const char* stop = text + byteLength;
571e59124ed1a62f1fec79679c38cabed622a756f75herb
572e59124ed1a62f1fec79679c38cabed622a756f75herb        SkAutoKern  autokern;
573e59124ed1a62f1fec79679c38cabed622a756f75herb
574e59124ed1a62f1fec79679c38cabed622a756f75herb        while (text < stop) {
575e59124ed1a62f1fec79679c38cabed622a756f75herb            // don't need x, y here, since all subpixel variants will have the
576e59124ed1a62f1fec79679c38cabed622a756f75herb            // same advance
5774c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb            const SkGlyph& glyph = glyphFinder->lookupGlyph(&text);
578e59124ed1a62f1fec79679c38cabed622a756f75herb
5796b3eacb0dfaeb3374d410c8c041bd39cd066e1eabenjaminwagner            x += autokern.adjust(glyph) + SkFloatToScalar(glyph.fAdvanceX);
5806b3eacb0dfaeb3374d410c8c041bd39cd066e1eabenjaminwagner            y += SkFloatToScalar(glyph.fAdvanceY);
581e59124ed1a62f1fec79679c38cabed622a756f75herb        }
582e59124ed1a62f1fec79679c38cabed622a756f75herb        SkASSERT(text == stop);
5836b3eacb0dfaeb3374d410c8c041bd39cd066e1eabenjaminwagner        return {x, y};
584e59124ed1a62f1fec79679c38cabed622a756f75herb    }
585e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb};
586e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb
587e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherbtemplate<typename ProcessOneGlyph>
588e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherbinline void SkFindAndPlaceGlyph::ProcessPosText(
5894c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb    SkPaint::TextEncoding textEncoding, const char text[], size_t byteLength,
5904c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb    SkPoint offset, const SkMatrix& matrix, const SkScalar pos[], int scalarsPerPosition,
5914c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb    SkPaint::Align textAlignment,
5924c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb    SkGlyphCache* cache, ProcessOneGlyph&& processOneGlyph) {
593e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb
59427876bc1156bcdd15cac7f0fe6228eb7806b8e96bungeman    SkAxisAlignment axisAlignment = cache->getScalerContext()->computeAxisAlignmentForHText();
5959be5ff6f9871ef22740094e7c25dd67329a73d20herb    uint32_t mtype = matrix.getType();
5964c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb    LookupGlyph glyphFinder(textEncoding, cache);
5974c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb
5989be5ff6f9871ef22740094e7c25dd67329a73d20herb    // Specialized code for handling the most common case for blink. The while loop is totally
5999be5ff6f9871ef22740094e7c25dd67329a73d20herb    // de-virtualized.
6009be5ff6f9871ef22740094e7c25dd67329a73d20herb    if (scalarsPerPosition == 1
6019be5ff6f9871ef22740094e7c25dd67329a73d20herb        && textAlignment == SkPaint::kLeft_Align
6029be5ff6f9871ef22740094e7c25dd67329a73d20herb        && axisAlignment == kX_SkAxisAlignment
6039be5ff6f9871ef22740094e7c25dd67329a73d20herb        && cache->isSubpixel()
6049be5ff6f9871ef22740094e7c25dd67329a73d20herb        && mtype <= SkMatrix::kTranslate_Mask) {
6059be5ff6f9871ef22740094e7c25dd67329a73d20herb        typedef GlyphFindAndPlaceSubpixel<
6069be5ff6f9871ef22740094e7c25dd67329a73d20herb            ProcessOneGlyph, SkPaint::kLeft_Align, kX_SkAxisAlignment> Positioner;
6079be5ff6f9871ef22740094e7c25dd67329a73d20herb        HorizontalPositions positions{pos};
6089be5ff6f9871ef22740094e7c25dd67329a73d20herb        TranslationMapper mapper{matrix, offset};
6094c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb        Positioner positioner(glyphFinder);
6109be5ff6f9871ef22740094e7c25dd67329a73d20herb        const char* cursor = text;
6119be5ff6f9871ef22740094e7c25dd67329a73d20herb        const char* stop = text + byteLength;
6129be5ff6f9871ef22740094e7c25dd67329a73d20herb        while (cursor < stop) {
6139be5ff6f9871ef22740094e7c25dd67329a73d20herb            SkPoint mappedPoint = mapper.TranslationMapper::map(
6149be5ff6f9871ef22740094e7c25dd67329a73d20herb                positions.HorizontalPositions::nextPoint());
6159be5ff6f9871ef22740094e7c25dd67329a73d20herb            positioner.Positioner::findAndPositionGlyph(
616221524de3be1fc343ad328c5e99562f32b5cad9cbungeman                &cursor, mappedPoint, std::forward<ProcessOneGlyph>(processOneGlyph));
6179be5ff6f9871ef22740094e7c25dd67329a73d20herb        }
6189be5ff6f9871ef22740094e7c25dd67329a73d20herb        return;
6199be5ff6f9871ef22740094e7c25dd67329a73d20herb    }
6209be5ff6f9871ef22740094e7c25dd67329a73d20herb
621e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb    PositionReader positionReader{
622e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb        [&](PositionReader::Variants* to_init) {
623e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb            if (2 == scalarsPerPosition) {
624e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb                to_init->initialize<ArbitraryPositions>(pos);
625e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb            } else {
626e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb                to_init->initialize<HorizontalPositions>(pos);
627e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb            }
628d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb            positionReader->forceUseForBug();
629e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb        }
630e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb    };
631e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb
632e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb    Mapper mapper{
633e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb        [&](Mapper::Variants* to_init) {
634e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb            if (mtype & (SkMatrix::kAffine_Mask | SkMatrix::kPerspective_Mask)
635e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb                || scalarsPerPosition == 2) {
636e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb                to_init->initialize<GeneralMapper>(matrix, offset);
637e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb            } else if (mtype & SkMatrix::kScale_Mask) {
638e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb                to_init->initialize<XScaleMapper>(matrix, offset);
639e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb            } else {
640e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb                to_init->initialize<TranslationMapper>(matrix, offset);
641e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb            }
642e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb        }
643e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb    };
644e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb
645d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb    GlyphFindAndPlace<ProcessOneGlyph> findAndPosition {
646e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb        [&](typename GlyphFindAndPlace<ProcessOneGlyph>::Variants* to_init) {
647e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb            if (cache->isSubpixel()) {
648e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb                switch (textAlignment) {
649e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb                    case SkPaint::kLeft_Align:
650e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb                        InitSubpixel<ProcessOneGlyph, SkPaint::kLeft_Align>(
6514c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb                            to_init, axisAlignment, glyphFinder);
652e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb                        break;
653e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb                    case SkPaint::kCenter_Align:
654e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb                        InitSubpixel<ProcessOneGlyph, SkPaint::kCenter_Align>(
6554c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb                            to_init, axisAlignment, glyphFinder);
656e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb                        break;
657e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb                    case SkPaint::kRight_Align:
658e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb                        InitSubpixel<ProcessOneGlyph, SkPaint::kRight_Align>(
6594c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb                            to_init, axisAlignment, glyphFinder);
660e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb                        break;
661e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb                }
662e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb            } else {
663e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb                switch (textAlignment) {
664e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb                    case SkPaint::kLeft_Align:
665e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb                        to_init->template initialize<
666e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb                            GlyphFindAndPlaceFullPixel<ProcessOneGlyph,
6674c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb                            SkPaint::kLeft_Align, kNoKerning>>(glyphFinder);
668e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb                        break;
669e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb                    case SkPaint::kCenter_Align:
670e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb                        to_init->template initialize<
671e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb                            GlyphFindAndPlaceFullPixel<ProcessOneGlyph,
6724c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb                            SkPaint::kCenter_Align, kNoKerning>>(glyphFinder);
673e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb                        break;
674e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb                    case SkPaint::kRight_Align:
675e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb                        to_init->template initialize<
676e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb                            GlyphFindAndPlaceFullPixel<ProcessOneGlyph,
6774c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb                            SkPaint::kRight_Align, kNoKerning>>(glyphFinder);
678e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb                        break;
679e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb                }
680e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb            }
681e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb        }
682e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb    };
683e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb
684e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb    const char* stop = text + byteLength;
685e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb    while (text < stop) {
686e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb        SkPoint mappedPoint = mapper->map(positionReader->nextPoint());
687e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb        findAndPosition->findAndPositionGlyph(
688221524de3be1fc343ad328c5e99562f32b5cad9cbungeman            &text, mappedPoint, std::forward<ProcessOneGlyph>(processOneGlyph));
689e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb    }
690e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb}
691e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb
692e59124ed1a62f1fec79679c38cabed622a756f75herbtemplate<typename ProcessOneGlyph>
693e59124ed1a62f1fec79679c38cabed622a756f75herbinline void SkFindAndPlaceGlyph::ProcessText(
6944c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb    SkPaint::TextEncoding textEncoding, const char text[], size_t byteLength,
6954c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb    SkPoint offset, const SkMatrix& matrix, SkPaint::Align textAlignment,
6964c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb    SkGlyphCache* cache, ProcessOneGlyph&& processOneGlyph) {
697e59124ed1a62f1fec79679c38cabed622a756f75herb
698e59124ed1a62f1fec79679c38cabed622a756f75herb    // transform the starting point
699e59124ed1a62f1fec79679c38cabed622a756f75herb    matrix.mapPoints(&offset, 1);
700e59124ed1a62f1fec79679c38cabed622a756f75herb
7014c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb    LookupGlyph glyphFinder(textEncoding, cache);
7024c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb
703e59124ed1a62f1fec79679c38cabed622a756f75herb    // need to measure first
704e59124ed1a62f1fec79679c38cabed622a756f75herb    if (textAlignment != SkPaint::kLeft_Align) {
7054c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb        SkVector stop = MeasureText(glyphFinder, text, byteLength);
706e59124ed1a62f1fec79679c38cabed622a756f75herb
707e59124ed1a62f1fec79679c38cabed622a756f75herb        if (textAlignment == SkPaint::kCenter_Align) {
708e59124ed1a62f1fec79679c38cabed622a756f75herb            stop *= SK_ScalarHalf;
709e59124ed1a62f1fec79679c38cabed622a756f75herb        }
710e59124ed1a62f1fec79679c38cabed622a756f75herb        offset -= stop;
711e59124ed1a62f1fec79679c38cabed622a756f75herb    }
712e59124ed1a62f1fec79679c38cabed622a756f75herb
713e59124ed1a62f1fec79679c38cabed622a756f75herb    GlyphFindAndPlace<ProcessOneGlyph> findAndPosition{
714e59124ed1a62f1fec79679c38cabed622a756f75herb        [&](typename GlyphFindAndPlace<ProcessOneGlyph>::Variants* to_init) {
715e59124ed1a62f1fec79679c38cabed622a756f75herb            if (cache->isSubpixel()) {
71627876bc1156bcdd15cac7f0fe6228eb7806b8e96bungeman                SkAxisAlignment axisAlignment =
71727876bc1156bcdd15cac7f0fe6228eb7806b8e96bungeman                    cache->getScalerContext()->computeAxisAlignmentForHText();
718e59124ed1a62f1fec79679c38cabed622a756f75herb                InitSubpixel<ProcessOneGlyph, SkPaint::kLeft_Align>(
7194c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb                    to_init, axisAlignment, glyphFinder);
720e59124ed1a62f1fec79679c38cabed622a756f75herb            } else {
721e59124ed1a62f1fec79679c38cabed622a756f75herb                to_init->template initialize<
722e59124ed1a62f1fec79679c38cabed622a756f75herb                    GlyphFindAndPlaceFullPixel<
7234c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb                        ProcessOneGlyph, SkPaint::kLeft_Align, kUseKerning>>(glyphFinder);
724e59124ed1a62f1fec79679c38cabed622a756f75herb            }
725e59124ed1a62f1fec79679c38cabed622a756f75herb        }
726e59124ed1a62f1fec79679c38cabed622a756f75herb    };
727e59124ed1a62f1fec79679c38cabed622a756f75herb
728e59124ed1a62f1fec79679c38cabed622a756f75herb    const char* stop = text + byteLength;
729e59124ed1a62f1fec79679c38cabed622a756f75herb    SkPoint current = offset;
730e59124ed1a62f1fec79679c38cabed622a756f75herb    while (text < stop) {
731e59124ed1a62f1fec79679c38cabed622a756f75herb        current =
732e59124ed1a62f1fec79679c38cabed622a756f75herb            findAndPosition->findAndPositionGlyph(
733221524de3be1fc343ad328c5e99562f32b5cad9cbungeman                &text, current, std::forward<ProcessOneGlyph>(processOneGlyph));
734e59124ed1a62f1fec79679c38cabed622a756f75herb
735e59124ed1a62f1fec79679c38cabed622a756f75herb    }
736e59124ed1a62f1fec79679c38cabed622a756f75herb}
737e59124ed1a62f1fec79679c38cabed622a756f75herb
738e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb#endif  // SkFindAndPositionGlyph_DEFINED
739