Home | History | Annotate | Download | only in text
      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 GrStrikeCache_DEFINED
      9 #define GrStrikeCache_DEFINED
     10 
     11 #include "GrDrawOpAtlas.h"
     12 #include "GrGlyph.h"
     13 #include "SkArenaAlloc.h"
     14 #include "SkMasks.h"
     15 #include "SkStrike.h"
     16 #include "SkTDynamicHash.h"
     17 
     18 class GrAtlasManager;
     19 class GrGpu;
     20 class GrStrikeCache;
     21 
     22 /**
     23  *  The GrTextStrike manages a pool of CPU backing memory for GrGlyphs. This backing memory
     24  *  is indexed by a PackedID and SkStrike. The SkStrike is what actually creates the mask.
     25  *  The GrTextStrike may outlive the generating SkStrike. However, it retains a copy
     26  *  of it's SkDescriptor as a key to access (or regenerate) the SkStrike. GrTextStrikes are
     27  *  created by and owned by a GrStrikeCache.
     28  */
     29 class GrTextStrike : public SkNVRefCnt<GrTextStrike> {
     30 public:
     31     GrTextStrike(const SkDescriptor& fontScalerKey);
     32 
     33     GrGlyph* getGlyph(const SkGlyph& skGlyph) {
     34         GrGlyph* glyph = fCache.find(skGlyph.getPackedID());
     35         if (!glyph) {
     36             glyph = this->generateGlyph(skGlyph);
     37         }
     38         return glyph;
     39     }
     40 
     41     // This variant of the above function is called by GrAtlasTextOp. At this point, it is possible
     42     // that the maskformat of the glyph differs from what we expect.  In these cases we will just
     43     // draw a clear square.
     44     // skbug:4143 crbug:510931
     45     GrGlyph* getGlyph(SkPackedGlyphID packed,
     46                       SkStrike* cache) {
     47         GrGlyph* glyph = fCache.find(packed);
     48         if (!glyph) {
     49             // We could return this to the caller, but in practice it adds code complexity for
     50             // potentially little benefit(ie, if the glyph is not in our font cache, then its not
     51             // in the atlas and we're going to be doing a texture upload anyways).
     52             const SkGlyph& skGlyph = GrToSkGlyph(cache, packed);
     53             glyph = this->generateGlyph(skGlyph);
     54         }
     55         return glyph;
     56     }
     57 
     58     // returns true if glyph successfully added to texture atlas, false otherwise.  If the glyph's
     59     // mask format has changed, then addGlyphToAtlas will draw a clear box.  This will almost never
     60     // happen.
     61     // TODO we can handle some of these cases if we really want to, but the long term solution is to
     62     // get the actual glyph image itself when we get the glyph metrics.
     63     GrDrawOpAtlas::ErrorCode addGlyphToAtlas(GrResourceProvider*, GrDeferredUploadTarget*,
     64                                              GrStrikeCache*, GrAtlasManager*, GrGlyph*,
     65                                              SkStrike*, GrMaskFormat expectedMaskFormat,
     66                                              bool isScaledGlyph);
     67 
     68     // testing
     69     int countGlyphs() const { return fCache.count(); }
     70 
     71     // remove any references to this plot
     72     void removeID(GrDrawOpAtlas::AtlasID);
     73 
     74     // If a TextStrike is abandoned by the cache, then the caller must get a new strike
     75     bool isAbandoned() const { return fIsAbandoned; }
     76 
     77     static const SkDescriptor& GetKey(const GrTextStrike& strike) {
     78         return *strike.fFontScalerKey.getDesc();
     79     }
     80 
     81     static uint32_t Hash(const SkDescriptor& desc) { return desc.getChecksum(); }
     82 
     83 private:
     84     SkTDynamicHash<GrGlyph, SkPackedGlyphID> fCache;
     85     SkAutoDescriptor fFontScalerKey;
     86     SkArenaAlloc fAlloc{512};
     87 
     88     int fAtlasedGlyphs{0};
     89     bool fIsAbandoned{false};
     90 
     91     static const SkGlyph& GrToSkGlyph(SkStrike* cache, SkPackedGlyphID id) {
     92         return cache->getGlyphIDMetrics(id.code(), id.getSubXFixed(), id.getSubYFixed());
     93     }
     94 
     95     GrGlyph* generateGlyph(const SkGlyph&);
     96 
     97     friend class GrStrikeCache;
     98 };
     99 
    100 /**
    101  * GrStrikeCache manages strikes which are indexed by a SkStrike. These strikes can then be
    102  * used to generate individual Glyph Masks.
    103  */
    104 class GrStrikeCache {
    105 public:
    106     GrStrikeCache(const GrCaps* caps, size_t maxTextureBytes);
    107     ~GrStrikeCache();
    108 
    109     void setStrikeToPreserve(GrTextStrike* strike) { fPreserveStrike = strike; }
    110 
    111     // The user of the cache may hold a long-lived ref to the returned strike. However, actions by
    112     // another client of the cache may cause the strike to be purged while it is still reffed.
    113     // Therefore, the caller must check GrTextStrike::isAbandoned() if there are other
    114     // interactions with the cache since the strike was received.
    115     sk_sp<GrTextStrike> getStrike(const SkDescriptor& desc) {
    116         sk_sp<GrTextStrike> strike = sk_ref_sp(fCache.find(desc));
    117         if (!strike) {
    118             strike = this->generateStrike(desc);
    119         }
    120         return strike;
    121     }
    122 
    123     const SkMasks& getMasks() const { return *f565Masks; }
    124 
    125     void freeAll();
    126 
    127     static void HandleEviction(GrDrawOpAtlas::AtlasID, void*);
    128 
    129 private:
    130     sk_sp<GrTextStrike> generateStrike(const SkDescriptor& desc) {
    131         // 'fCache' get the construction ref
    132         sk_sp<GrTextStrike> strike = sk_ref_sp(new GrTextStrike(desc));
    133         fCache.add(strike.get());
    134         return strike;
    135     }
    136 
    137     using StrikeHash = SkTDynamicHash<GrTextStrike, SkDescriptor>;
    138 
    139     StrikeHash fCache;
    140     GrTextStrike* fPreserveStrike;
    141     std::unique_ptr<const SkMasks> f565Masks;
    142 };
    143 
    144 #endif  // GrStrikeCache_DEFINED
    145