SkTextBlob

Initial implementation.

R=bungeman@google.com, jbroman@chromium.org, mtklein@google.com, reed@google.com, robertphillips@google.com

Author: fmalita@chromium.org

Review URL: https://codereview.chromium.org/473633002
diff --git a/include/core/SkTextBlob.h b/include/core/SkTextBlob.h
new file mode 100644
index 0000000..c78fb24
--- /dev/null
+++ b/include/core/SkTextBlob.h
@@ -0,0 +1,179 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkTextBlob_DEFINED
+#define SkTextBlob_DEFINED
+
+#include "SkPaint.h"
+#include "SkRefCnt.h"
+#include "SkTArray.h"
+#include "SkTDArray.h"
+
+/** \class SkTextBlob
+
+    SkTextBlob combines multiple text runs into an immutable, ref-counted structure.
+*/
+class SkTextBlob : public SkRefCnt {
+public:
+    /**
+     *  Returns the blob bounding box.
+     */
+    const SkRect& bounds() const { return fBounds; }
+
+    /**
+     *  Return a non-zero, unique value representing the text blob.
+     */
+    uint32_t uniqueID() const;
+
+private:
+    enum GlyphPositioning {
+        kDefault_Positioning      = 0, // Default glyph advances -- zero scalars per glyph.
+        kHorizontal_Positioning   = 1, // Horizontal positioning -- one scalar per glyph.
+        kFull_Positioning         = 2  // Point positioning -- two scalars per glyph.
+    };
+
+    class RunIterator {
+    public:
+        RunIterator(const SkTextBlob* blob);
+
+        bool done() const;
+        void next();
+
+        uint32_t glyphCount() const;
+        const uint16_t* glyphs() const;
+        const SkScalar* pos() const;
+        const SkPoint& offset() const;
+        const SkPaint& font() const;
+        GlyphPositioning positioning() const;
+
+    private:
+        const SkTextBlob* fBlob;
+        int               fIndex;
+    };
+
+    // A run is a sequence of glyphs sharing the same font metrics and positioning mode.
+    struct Run {
+        uint32_t         count;
+        uint32_t         glyphStart; // index into fGlyphBuffer
+        uint32_t         posStart;   // index into fPosBuffer
+        SkPoint          offset;     // run offset (unsued for fully positioned glyphs)
+        SkPaint          font;
+        GlyphPositioning positioning;
+    };
+
+    SkTextBlob(uint16_t* glyphs, SkScalar* pos, const SkTArray<Run>* runs, const SkRect& bounds);
+
+    friend class SkCanvas;
+    friend class SkTextBlobBuilder;
+
+    const SkAutoTMalloc<uint16_t>       fGlyphBuffer;
+    const SkAutoTMalloc<SkScalar>       fPosBuffer;
+
+    // SkTArray required here for run font destruction.
+    SkAutoTDelete<const SkTArray<Run> > fRuns;
+    const SkRect                        fBounds;
+
+    mutable uint32_t                    fUniqueID;
+
+    typedef SkRefCnt INHERITED;
+};
+
+/** \class SkTextBlobBuilder
+
+    Helper class for constructing SkTextBlobs.
+ */
+class SkTextBlobBuilder {
+public:
+    /**
+     *  @param runs The number of runs to be added, if known. This is a storage hint and
+     *              not a limit.
+     */
+    SkTextBlobBuilder(unsigned runs = 0);
+
+    ~SkTextBlobBuilder();
+
+    /**
+     *  Returns an immutable SkTextBlob for the current runs/glyphs. The builder is reset and
+     *  can be reused.
+     */
+    const SkTextBlob* build();
+
+    /**
+     *  Glyph and position buffers associated with a run.
+     *
+     *  A run is a sequence of glyphs sharing the same font metrics and positioning mode.
+     */
+    struct RunBuffer {
+        uint16_t* glyphs;
+        SkScalar* pos;
+    };
+
+    /**
+     *  Allocates a new default-positioned run and returns its writable glyph buffer
+     *  for direct manipulation.
+     *
+     *  @param font    The font to be used for this run.
+     *  @param count   Number of glyphs.
+     *  @param x,y     Position within the blob.
+     *  @param bounds  Optional run bounding box. If known in advance (!= NULL), it will
+     *                 be used when computing the blob bounds, to avoid re-measuring.
+     *
+     *  @return        A writable glyph buffer, valid until the next allocRun() or
+     *                 build() call. The buffer is guaranteed to hold @count@ glyphs.
+     */
+    const RunBuffer& allocRun(const SkPaint& font, int count, SkScalar x, SkScalar y,
+                              const SkRect* bounds = NULL);
+
+    /**
+     *  Allocates a new horizontally-positioned run and returns its writable glyph and position
+     *  buffers for direct manipulation.
+     *
+     *  @param font    The font to be used for this run.
+     *  @param count   Number of glyphs.
+     *  @param y       Vertical offset within the blob.
+     *  @param bounds  Optional run bounding box. If known in advance (!= NULL), it will
+     *                 be used when computing the blob bounds, to avoid re-measuring.
+     *
+     *  @return        Writable glyph and position buffers, valid until the next allocRun()
+     *                 or build() call. The buffers are guaranteed to hold @count@ elements.
+     */
+    const RunBuffer& allocRunPosH(const SkPaint& font, int count, SkScalar y,
+                                  const SkRect* bounds = NULL);
+
+    /**
+     *  Allocates a new fully-positioned run and returns its writable glyph and position
+     *  buffers for direct manipulation.
+     *
+     *  @param font   The font to be used for this run.
+     *  @param count  Number of glyphs.
+     *  @param bounds Optional run bounding box. If known in advance (!= NULL), it will
+     *                be used when computing the blob bounds, to avoid re-measuring.
+     *
+     *  @return       Writable glyph and position buffers, valid until the next allocRun()
+     *                or build() call. The glyph buffer and position buffer are
+     *                guaranteed to hold @count@ and 2 * @count@ elements, respectively.
+     */
+    const RunBuffer& allocRunPos(const SkPaint& font, int count, const SkRect* bounds = NULL);
+
+private:
+    void allocInternal(const SkPaint& font, SkTextBlob::GlyphPositioning positioning,
+                       int count, SkPoint offset, const SkRect* bounds);
+    void ensureRun(const SkPaint& font, SkTextBlob::GlyphPositioning positioning,
+                   const SkPoint& offset);
+    void updateDeferredBounds();
+
+    SkTDArray<uint16_t>        fGlyphBuffer;
+    SkTDArray<SkScalar>        fPosBuffer;
+    SkTArray<SkTextBlob::Run>* fRuns;
+
+    SkRect                     fBounds;
+    bool                       fDeferredBounds;
+
+    RunBuffer                  fCurrentRunBuffer;
+};
+
+#endif // SkTextBlob_DEFINED