Home | History | Annotate | Download | only in core
      1 /*
      2  * Copyright 2006 The Android Open Source Project
      3  *
      4  * Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.
      5  */
      6 
      7 #ifndef SkStrike_DEFINED
      8 #define SkStrike_DEFINED
      9 
     10 #include "SkArenaAlloc.h"
     11 #include "SkDescriptor.h"
     12 #include "SkFontMetrics.h"
     13 #include "SkFontTypes.h"
     14 #include "SkGlyph.h"
     15 #include "SkGlyphRunPainter.h"
     16 #include "SkPaint.h"
     17 #include "SkTHash.h"
     18 #include "SkScalerContext.h"
     19 #include "SkTemplates.h"
     20 #include <memory>
     21 
     22 /** \class SkGlyphCache
     23 
     24     This class represents a strike: a specific combination of typeface, size, matrix, etc., and
     25     holds the glyphs for that strike. Calling any of the getGlyphID... methods will
     26     return the requested glyph, either instantly if it is already cached, or by first generating
     27     it and then adding it to the strike.
     28 
     29     The strikes are held in a global list, available to all threads. To interact with one, call
     30     either Find{OrCreate}Exclusive().
     31 
     32     The Find*Exclusive() method returns SkExclusiveStrikePtr, which releases exclusive ownership
     33     when they go out of scope.
     34 */
     35 class SkStrike : public SkStrikeInterface {
     36 public:
     37     SkStrike(const SkDescriptor& desc,
     38              std::unique_ptr<SkScalerContext> scaler,
     39              const SkFontMetrics&);
     40 
     41     const SkDescriptor& getDescriptor() const;
     42 
     43     /** Return true if glyph is cached. */
     44     bool isGlyphCached(SkGlyphID glyphID, SkFixed x, SkFixed y) const;
     45 
     46     /**  Return a glyph that has no information if it is not already filled out. */
     47     SkGlyph* getRawGlyphByID(SkPackedGlyphID);
     48 
     49     /** Returns a glyph with valid fAdvance and fDevKern fields. The remaining fields may be
     50         valid, but that is not guaranteed. If you require those, call getGlyphIDMetrics instead.
     51     */
     52     const SkGlyph& getGlyphIDAdvance(SkGlyphID);
     53 
     54     /** Returns a glyph with all fields valid except fImage and fPath, which may be null. If they
     55         are null, call findImage or findPath for those. If they are not null, then they are valid.
     56 
     57         This call is potentially slower than the matching ...Advance call. If you only need the
     58         fAdvance/fDevKern fields, call those instead.
     59     */
     60     const SkGlyph& getGlyphIDMetrics(SkGlyphID);
     61 
     62     /** These are variants that take the device position of the glyph. Call these only if you are
     63         drawing in subpixel mode. Passing 0, 0 is effectively the same as calling the variants
     64         w/o the extra params, though a tiny bit slower.
     65     */
     66     const SkGlyph& getGlyphIDMetrics(uint16_t, SkFixed x, SkFixed y);
     67 
     68     void getAdvances(SkSpan<const SkGlyphID>, SkPoint[]);
     69 
     70     /** Returns the number of glyphs for this strike.
     71     */
     72     unsigned getGlyphCount() const;
     73 
     74     /** Return the number of glyphs currently cached. */
     75     int countCachedGlyphs() const;
     76 
     77     /** Return the image associated with the glyph. If it has not been generated this will
     78         trigger that.
     79     */
     80     const void* findImage(const SkGlyph&);
     81 
     82     /** Initializes the image associated with the glyph with |data|.
     83      */
     84     void initializeImage(const volatile void* data, size_t size, SkGlyph*);
     85 
     86     /** If the advance axis intersects the glyph's path, append the positions scaled and offset
     87         to the array (if non-null), and set the count to the updated array length.
     88     */
     89     void findIntercepts(const SkScalar bounds[2], SkScalar scale, SkScalar xPos,
     90                         bool yAxis, SkGlyph* , SkScalar* array, int* count);
     91 
     92     /** Return the Path associated with the glyph. If it has not been generated this will trigger
     93         that.
     94     */
     95     const SkPath* findPath(const SkGlyph&);
     96 
     97     /** Initializes the path associated with the glyph with |data|. Returns false if
     98      *  data is invalid.
     99      */
    100     bool initializePath(SkGlyph*, const volatile void* data, size_t size);
    101 
    102     /** Fallback glyphs used during font remoting if the original glyph can't be found.
    103      */
    104     bool belongsToCache(const SkGlyph* glyph) const;
    105     /** Find any glyph in this cache with the given ID, regardless of subpixel positioning.
    106      *  If set and present, skip over the glyph with vetoID.
    107      */
    108     const SkGlyph* getCachedGlyphAnySubPix(SkGlyphID,
    109                                            SkPackedGlyphID vetoID = SkPackedGlyphID()) const;
    110     void initializeGlyphFromFallback(SkGlyph* glyph, const SkGlyph&);
    111 
    112     /** Return the vertical metrics for this strike.
    113     */
    114     const SkFontMetrics& getFontMetrics() const {
    115         return fFontMetrics;
    116     }
    117 
    118     SkMask::Format getMaskFormat() const {
    119         return fScalerContext->getMaskFormat();
    120     }
    121 
    122     bool isSubpixel() const {
    123         return fIsSubpixel;
    124     }
    125 
    126     SkVector rounding() const override;
    127 
    128     const SkGlyph& getGlyphMetrics(SkGlyphID glyphID, SkPoint position) override;
    129 
    130     bool hasImage(const SkGlyph& glyph) override;
    131 
    132     bool hasPath(const SkGlyph& glyph) override;
    133 
    134     /** Return the approx RAM usage for this cache. */
    135     size_t getMemoryUsed() const { return fMemoryUsed; }
    136 
    137     void dump() const;
    138 
    139     SkScalerContext* getScalerContext() const { return fScalerContext.get(); }
    140 
    141 #ifdef SK_DEBUG
    142     void forceValidate() const;
    143     void validate() const;
    144 #else
    145     void validate() const {}
    146 #endif
    147 
    148     class AutoValidate : SkNoncopyable {
    149     public:
    150         AutoValidate(const SkStrike* cache) : fCache(cache) {
    151             if (fCache) {
    152                 fCache->validate();
    153             }
    154         }
    155         ~AutoValidate() {
    156             if (fCache) {
    157                 fCache->validate();
    158             }
    159         }
    160         void forget() {
    161             fCache = nullptr;
    162         }
    163     private:
    164         const SkStrike* fCache;
    165     };
    166 
    167 private:
    168     enum MetricsType {
    169         kNothing_MetricsType,
    170         kJustAdvance_MetricsType,
    171         kFull_MetricsType
    172     };
    173 
    174     enum {
    175         kHashBits  = 8,
    176         kHashCount = 1 << kHashBits,
    177         kHashMask  = kHashCount - 1
    178     };
    179 
    180     // Return the SkGlyph* associated with MakeID. The id parameter is the
    181     // combined glyph/x/y id generated by MakeID. If it is just a glyph id
    182     // then x and y are assumed to be zero.
    183     SkGlyph* lookupByPackedGlyphID(SkPackedGlyphID packedGlyphID, MetricsType type);
    184 
    185     // Return a new SkGlyph for the glyph ID and subpixel position id. Limit the amount
    186     // of work using type.
    187     SkGlyph* allocateNewGlyph(SkPackedGlyphID packedGlyphID, MetricsType type);
    188 
    189     static void OffsetResults(const SkGlyph::Intercept* intercept, SkScalar scale,
    190                               SkScalar xPos, SkScalar* array, int* count);
    191     static void AddInterval(SkScalar val, SkGlyph::Intercept* intercept);
    192     static void AddPoints(const SkPoint* pts, int ptCount, const SkScalar bounds[2],
    193                           bool yAxis, SkGlyph::Intercept* intercept);
    194     static void AddLine(const SkPoint pts[2], SkScalar axis, bool yAxis,
    195                         SkGlyph::Intercept* intercept);
    196     static void AddQuad(const SkPoint pts[2], SkScalar axis, bool yAxis,
    197                         SkGlyph::Intercept* intercept);
    198     static void AddCubic(const SkPoint pts[3], SkScalar axis, bool yAxis,
    199                          SkGlyph::Intercept* intercept);
    200     static const SkGlyph::Intercept* MatchBounds(const SkGlyph* glyph,
    201                                                  const SkScalar bounds[2]);
    202 
    203     const SkAutoDescriptor fDesc;
    204     const std::unique_ptr<SkScalerContext> fScalerContext;
    205     SkFontMetrics          fFontMetrics;
    206 
    207     class GlyphMapHashTraits {
    208     public:
    209         static SkPackedGlyphID GetKey(const SkGlyph* glyph) {
    210             return glyph->getPackedID();
    211         }
    212         static uint32_t Hash(SkPackedGlyphID glyphId) {
    213             return glyphId.hash();
    214         }
    215     };
    216 
    217     // Map from a combined GlyphID and sub-pixel position to a SkGlyph*.
    218     // The actual glyph is stored in the fAlloc. This structure provides an
    219     // unchanging pointer as long as the cache is alive.
    220     SkTHashTable<SkGlyph*, SkPackedGlyphID, GlyphMapHashTraits> fGlyphMap;
    221 
    222     // so we don't grow our arrays a lot
    223     static constexpr size_t kMinGlyphCount = 8;
    224     static constexpr size_t kMinGlyphImageSize = 16 /* height */ * 8 /* width */;
    225     static constexpr size_t kMinAllocAmount = kMinGlyphImageSize * kMinGlyphCount;
    226 
    227     SkArenaAlloc            fAlloc {kMinAllocAmount};
    228 
    229     // used to track (approx) how much ram is tied-up in this cache
    230     size_t                  fMemoryUsed;
    231 
    232     const bool              fIsSubpixel;
    233     const SkAxisAlignment   fAxisAlignment;
    234 };
    235 
    236 #endif  // SkStrike_DEFINED
    237