Home | History | Annotate | Download | only in core
      1 /*
      2  * Copyright 2014 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 SkTextBlob_DEFINED
      9 #define SkTextBlob_DEFINED
     10 
     11 #include "../private/SkTemplates.h"
     12 #include "../private/SkAtomics.h"
     13 #include "SkPaint.h"
     14 #include "SkString.h"
     15 #include "SkRefCnt.h"
     16 
     17 class SkReadBuffer;
     18 class SkWriteBuffer;
     19 
     20 typedef std::function<void(SkTypeface*)> SkTypefaceCataloger;
     21 typedef std::function<sk_sp<SkTypeface>(uint32_t)> SkTypefaceResolver;
     22 
     23 /** \class SkTextBlob
     24 
     25     SkTextBlob combines multiple text runs into an immutable, ref-counted structure.
     26 */
     27 class SK_API SkTextBlob final : public SkNVRefCnt<SkTextBlob> {
     28 public:
     29     /**
     30      *  Returns a conservative blob bounding box.
     31      */
     32     const SkRect& bounds() const { return fBounds; }
     33 
     34     /**
     35      *  Return a non-zero, unique value representing the text blob.
     36      */
     37     uint32_t uniqueID() const { return fUniqueID; }
     38 
     39     /**
     40      *  Serialize to a buffer.
     41      */
     42     void flatten(SkWriteBuffer&) const;
     43 
     44     /**
     45      *  Recreate an SkTextBlob that was serialized into a buffer.
     46      *
     47      *  @param  SkReadBuffer Serialized blob data.
     48      *  @return A new SkTextBlob representing the serialized data, or NULL if the buffer is
     49      *          invalid.
     50      */
     51     static sk_sp<SkTextBlob> MakeFromBuffer(SkReadBuffer&);
     52 
     53     static const SkTextBlob* CreateFromBuffer(SkReadBuffer& buffer) {
     54         return MakeFromBuffer(buffer).release();
     55     }
     56 
     57     enum GlyphPositioning : uint8_t {
     58         kDefault_Positioning      = 0, // Default glyph advances -- zero scalars per glyph.
     59         kHorizontal_Positioning   = 1, // Horizontal positioning -- one scalar per glyph.
     60         kFull_Positioning         = 2  // Point positioning -- two scalars per glyph.
     61     };
     62 
     63     /**
     64      *  Serialize the typeface into a data blob, storing type uniqueID of each referenced typeface.
     65      *  During this process, each time a typeface is encountered, it is passed to the catalog,
     66      *  allowing the caller to what typeface IDs will need to be resolved in Deserialize().
     67      */
     68     sk_sp<SkData> serialize(const SkTypefaceCataloger&) const;
     69 
     70     /**
     71      *  Re-create a text blob previously serialized. Since the serialized form records the uniqueIDs
     72      *  of its typefaces, deserialization requires that the caller provide the corresponding
     73      *  SkTypefaces for those IDs.
     74      */
     75     static sk_sp<SkTextBlob> Deserialize(const void* data, size_t size, const SkTypefaceResolver&);
     76 
     77 private:
     78     friend class SkNVRefCnt<SkTextBlob>;
     79     class RunRecord;
     80 
     81     explicit SkTextBlob(const SkRect& bounds);
     82 
     83     ~SkTextBlob();
     84 
     85     // Memory for objects of this class is created with sk_malloc rather than operator new and must
     86     // be freed with sk_free.
     87     void operator delete(void* p) { sk_free(p); }
     88     void* operator new(size_t) {
     89         SkFAIL("All blobs are created by placement new.");
     90         return sk_malloc_throw(0);
     91     }
     92     void* operator new(size_t, void* p) { return p; }
     93 
     94     static unsigned ScalarsPerGlyph(GlyphPositioning pos);
     95 
     96     // Call when this blob is part of the key to a cache entry. This allows the cache
     97     // to know automatically those entries can be purged when this SkTextBlob is deleted.
     98     void notifyAddedToCache() const {
     99         fAddedToCache.store(true);
    100     }
    101 
    102     friend class GrTextBlobCache;
    103     friend class SkTextBlobBuilder;
    104     friend class SkTextBlobRunIterator;
    105 
    106     const SkRect           fBounds;
    107     const uint32_t         fUniqueID;
    108     mutable SkAtomic<bool> fAddedToCache;
    109 
    110     SkDEBUGCODE(size_t fStorageSize;)
    111 
    112     // The actual payload resides in externally-managed storage, following the object.
    113     // (see the .cpp for more details)
    114 
    115     typedef SkRefCnt INHERITED;
    116 };
    117 
    118 /** \class SkTextBlobBuilder
    119 
    120     Helper class for constructing SkTextBlobs.
    121  */
    122 class SK_API SkTextBlobBuilder {
    123 public:
    124     SkTextBlobBuilder();
    125 
    126     ~SkTextBlobBuilder();
    127 
    128     /**
    129      *  Returns an immutable SkTextBlob for the current runs/glyphs,
    130      *  or nullptr if no runs were allocated.
    131      *
    132      *  The builder is reset and can be reused.
    133      */
    134     sk_sp<SkTextBlob> make();
    135 
    136     /**
    137      *  Glyph and position buffers associated with a run.
    138      *
    139      *  A run is a sequence of glyphs sharing the same font metrics
    140      *  and positioning mode.
    141      *
    142      *  If textByteCount is 0, utf8text and clusters will be NULL (no
    143      *  character information will be associated with the glyphs).
    144      *
    145      *  utf8text will point to a buffer of size textByteCount bytes.
    146      *
    147      *  clusters (if not NULL) will point to an array of size count.
    148      *  For each glyph, give the byte-offset into the text for the
    149      *  first byte in the first character in that glyph's cluster.
    150      *  Each value in the array should be an integer less than
    151      *  textByteCount.  Values in the array should either be
    152      *  monotonically increasing (left-to-right text) or monotonically
    153      *  decreasing (right-to-left text).  This definiton is conviently
    154      *  the same as used by Harfbuzz's hb_glyph_info_t::cluster field,
    155      *  except that Harfbuzz interleaves glyphs and clusters.
    156      */
    157     struct RunBuffer {
    158         SkGlyphID* glyphs;
    159         SkScalar* pos;
    160         char* utf8text;
    161         uint32_t* clusters;
    162     };
    163 
    164     /**
    165      *  Allocates a new default-positioned run and returns its writable glyph buffer
    166      *  for direct manipulation.
    167      *
    168      *  @param font    The font to be used for this run.
    169      *  @param count   Number of glyphs.
    170      *  @param x,y     Position within the blob.
    171      *  @param textByteCount length of the original UTF-8 text that
    172      *                 corresponds to this sequence of glyphs.  If 0,
    173      *                 text will not be included in the textblob.
    174      *  @param lang    Language code, currently unimplemented.
    175      *  @param bounds  Optional run bounding box. If known in advance (!= NULL), it will
    176      *                 be used when computing the blob bounds, to avoid re-measuring.
    177      *
    178      *  @return        A writable glyph buffer, valid until the next allocRun() or
    179      *                 build() call. The buffer is guaranteed to hold @count@ glyphs.
    180      */
    181     const RunBuffer& allocRunText(const SkPaint& font,
    182                                   int count,
    183                                   SkScalar x,
    184                                   SkScalar y,
    185                                   int textByteCount,
    186                                   SkString lang,
    187                                   const SkRect* bounds = NULL);
    188     const RunBuffer& allocRun(const SkPaint& font, int count, SkScalar x, SkScalar y,
    189                               const SkRect* bounds = NULL) {
    190         return this->allocRunText(font, count, x, y, 0, SkString(), bounds);
    191     }
    192 
    193     /**
    194      *  Allocates a new horizontally-positioned run and returns its writable glyph and position
    195      *  buffers for direct manipulation.
    196      *
    197      *  @param font    The font to be used for this run.
    198      *  @param count   Number of glyphs.
    199      *  @param y       Vertical offset within the blob.
    200      *  @param textByteCount length of the original UTF-8 text that
    201      *                 corresponds to this sequence of glyphs.  If 0,
    202      *                 text will not be included in the textblob.
    203      *  @param lang    Language code, currently unimplemented.
    204      *  @param bounds  Optional run bounding box. If known in advance (!= NULL), it will
    205      *                 be used when computing the blob bounds, to avoid re-measuring.
    206      *
    207      *  @return        Writable glyph and position buffers, valid until the next allocRun()
    208      *                 or build() call. The buffers are guaranteed to hold @count@ elements.
    209      */
    210     const RunBuffer& allocRunTextPosH(const SkPaint& font, int count, SkScalar y,
    211                                       int textByteCount, SkString lang,
    212                                       const SkRect* bounds = NULL);
    213     const RunBuffer& allocRunPosH(const SkPaint& font, int count, SkScalar y,
    214                                   const SkRect* bounds = NULL) {
    215         return this->allocRunTextPosH(font, count, y, 0, SkString(), bounds);
    216     }
    217 
    218     /**
    219      *  Allocates a new fully-positioned run and returns its writable glyph and position
    220      *  buffers for direct manipulation.
    221      *
    222      *  @param font   The font to be used for this run.
    223      *  @param count  Number of glyphs.
    224      *  @param textByteCount length of the original UTF-8 text that
    225      *                 corresponds to this sequence of glyphs.  If 0,
    226      *                 text will not be included in the textblob.
    227      *  @param lang    Language code, currently unimplemented.
    228      *  @param bounds Optional run bounding box. If known in advance (!= NULL), it will
    229      *                be used when computing the blob bounds, to avoid re-measuring.
    230      *
    231      *  @return       Writable glyph and position buffers, valid until the next allocRun()
    232      *                or build() call. The glyph buffer and position buffer are
    233      *                guaranteed to hold @count@ and 2 * @count@ elements, respectively.
    234      */
    235     const RunBuffer& allocRunTextPos(const SkPaint& font, int count,
    236                                      int textByteCount, SkString lang,
    237                                      const SkRect* bounds = NULL);
    238     const RunBuffer& allocRunPos(const SkPaint& font, int count,
    239                                  const SkRect* bounds = NULL) {
    240         return this->allocRunTextPos(font, count, 0, SkString(), bounds);
    241     }
    242 
    243 private:
    244     void reserve(size_t size);
    245     void allocInternal(const SkPaint& font, SkTextBlob::GlyphPositioning positioning,
    246                        int count, int textBytes, SkPoint offset, const SkRect* bounds);
    247     bool mergeRun(const SkPaint& font, SkTextBlob::GlyphPositioning positioning,
    248                   int count, SkPoint offset);
    249     void updateDeferredBounds();
    250 
    251     static SkRect ConservativeRunBounds(const SkTextBlob::RunRecord&);
    252     static SkRect TightRunBounds(const SkTextBlob::RunRecord&);
    253 
    254     SkAutoTMalloc<uint8_t> fStorage;
    255     size_t                 fStorageSize;
    256     size_t                 fStorageUsed;
    257 
    258     SkRect                 fBounds;
    259     int                    fRunCount;
    260     bool                   fDeferredBounds;
    261     size_t                 fLastRun; // index into fStorage
    262 
    263     RunBuffer              fCurrentRunBuffer;
    264 };
    265 
    266 #endif // SkTextBlob_DEFINED
    267