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 "SkPaint.h"
12#include "SkRefCnt.h"
13#include "SkTArray.h"
14#include "SkTDArray.h"
15
16class SkReadBuffer;
17class SkWriteBuffer;
18
19/** \class SkTextBlob
20
21    SkTextBlob combines multiple text runs into an immutable, ref-counted structure.
22*/
23class SK_API SkTextBlob : public SkRefCnt {
24public:
25    /**
26     *  Returns the blob bounding box.
27     */
28    const SkRect& bounds() const { return fBounds; }
29
30    /**
31     *  Return a non-zero, unique value representing the text blob.
32     */
33    uint32_t uniqueID() const;
34
35    /**
36     *  Serialize to a buffer.
37     */
38    void flatten(SkWriteBuffer&) const;
39
40    /**
41     *  Recreate an SkTextBlob that was serialized into a buffer.
42     *
43     *  @param  SkReadBuffer Serialized blob data.
44     *  @return A new SkTextBlob representing the serialized data, or NULL if the buffer is
45     *          invalid.
46     */
47    static const SkTextBlob* CreateFromBuffer(SkReadBuffer&);
48
49private:
50    enum GlyphPositioning {
51        kDefault_Positioning      = 0, // Default glyph advances -- zero scalars per glyph.
52        kHorizontal_Positioning   = 1, // Horizontal positioning -- one scalar per glyph.
53        kFull_Positioning         = 2  // Point positioning -- two scalars per glyph.
54    };
55
56    class RunRecord;
57
58    class RunIterator {
59    public:
60        RunIterator(const SkTextBlob* blob);
61
62        bool done() const;
63        void next();
64
65        uint32_t glyphCount() const;
66        const uint16_t* glyphs() const;
67        const SkScalar* pos() const;
68        const SkPoint& offset() const;
69        void applyFontToPaint(SkPaint*) const;
70        GlyphPositioning positioning() const;
71
72    private:
73        const RunRecord* fCurrentRun;
74        int              fRemainingRuns;
75
76        SkDEBUGCODE(uint8_t* fStorageTop;)
77    };
78
79    SkTextBlob(int runCount, const SkRect& bounds);
80
81    virtual ~SkTextBlob();
82    virtual void internal_dispose() const SK_OVERRIDE;
83
84    static unsigned ScalarsPerGlyph(GlyphPositioning pos);
85
86    friend class SkBaseDevice;
87    friend class SkTextBlobBuilder;
88    friend class TextBlobTester;
89
90    const int        fRunCount;
91    const SkRect     fBounds;
92    mutable uint32_t fUniqueID;
93
94    SkDEBUGCODE(size_t fStorageSize;)
95
96    // The actual payload resides in externally-managed storage, following the object.
97    // (see the .cpp for more details)
98
99    typedef SkRefCnt INHERITED;
100};
101
102/** \class SkTextBlobBuilder
103
104    Helper class for constructing SkTextBlobs.
105 */
106class SK_API SkTextBlobBuilder {
107public:
108    SkTextBlobBuilder();
109
110    ~SkTextBlobBuilder();
111
112    /**
113     *  Returns an immutable SkTextBlob for the current runs/glyphs. The builder is reset and
114     *  can be reused.
115     */
116    const SkTextBlob* build();
117
118    /**
119     *  Glyph and position buffers associated with a run.
120     *
121     *  A run is a sequence of glyphs sharing the same font metrics and positioning mode.
122     */
123    struct RunBuffer {
124        uint16_t* glyphs;
125        SkScalar* pos;
126    };
127
128    /**
129     *  Allocates a new default-positioned run and returns its writable glyph buffer
130     *  for direct manipulation.
131     *
132     *  @param font    The font to be used for this run.
133     *  @param count   Number of glyphs.
134     *  @param x,y     Position within the blob.
135     *  @param bounds  Optional run bounding box. If known in advance (!= NULL), it will
136     *                 be used when computing the blob bounds, to avoid re-measuring.
137     *
138     *  @return        A writable glyph buffer, valid until the next allocRun() or
139     *                 build() call. The buffer is guaranteed to hold @count@ glyphs.
140     */
141    const RunBuffer& allocRun(const SkPaint& font, int count, SkScalar x, SkScalar y,
142                              const SkRect* bounds = NULL);
143
144    /**
145     *  Allocates a new horizontally-positioned run and returns its writable glyph and position
146     *  buffers for direct manipulation.
147     *
148     *  @param font    The font to be used for this run.
149     *  @param count   Number of glyphs.
150     *  @param y       Vertical offset within the blob.
151     *  @param bounds  Optional run bounding box. If known in advance (!= NULL), it will
152     *                 be used when computing the blob bounds, to avoid re-measuring.
153     *
154     *  @return        Writable glyph and position buffers, valid until the next allocRun()
155     *                 or build() call. The buffers are guaranteed to hold @count@ elements.
156     */
157    const RunBuffer& allocRunPosH(const SkPaint& font, int count, SkScalar y,
158                                  const SkRect* bounds = NULL);
159
160    /**
161     *  Allocates a new fully-positioned run and returns its writable glyph and position
162     *  buffers for direct manipulation.
163     *
164     *  @param font   The font to be used for this run.
165     *  @param count  Number of glyphs.
166     *  @param bounds Optional run bounding box. If known in advance (!= NULL), it will
167     *                be used when computing the blob bounds, to avoid re-measuring.
168     *
169     *  @return       Writable glyph and position buffers, valid until the next allocRun()
170     *                or build() call. The glyph buffer and position buffer are
171     *                guaranteed to hold @count@ and 2 * @count@ elements, respectively.
172     */
173    const RunBuffer& allocRunPos(const SkPaint& font, int count, const SkRect* bounds = NULL);
174
175private:
176    void reserve(size_t size);
177    void allocInternal(const SkPaint& font, SkTextBlob::GlyphPositioning positioning,
178                       int count, SkPoint offset, const SkRect* bounds);
179    bool mergeRun(const SkPaint& font, SkTextBlob::GlyphPositioning positioning,
180                  int count, SkPoint offset);
181    void updateDeferredBounds();
182
183    SkAutoTMalloc<uint8_t> fStorage;
184    size_t                 fStorageSize;
185    size_t                 fStorageUsed;
186
187    SkRect                 fBounds;
188    int                    fRunCount;
189    bool                   fDeferredBounds;
190    size_t                 fLastRun; // index into fStorage
191
192    RunBuffer              fCurrentRunBuffer;
193};
194
195#endif // SkTextBlob_DEFINED
196