1fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot/* 2fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot * Copyright 2014 Google Inc. 3fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot * 4fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot * Use of this source code is governed by a BSD-style license that can be 5fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot * found in the LICENSE file. 6fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot */ 7fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 8fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkTextBlobRunIterator.h" 9fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 10fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkReadBuffer.h" 11fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkSafeMath.h" 12fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkTypeface.h" 13fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkWriteBuffer.h" 14fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 15fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include <limits> 16fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 17fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#if SK_SUPPORT_GPU 18fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "text/GrTextBlobCache.h" 19fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#endif 20fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 21fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotnamespace { 22fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 23fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// TODO(fmalita): replace with SkFont. 24fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotclass RunFont : SkNoncopyable { 25fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotpublic: 26fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot RunFont(const SkPaint& paint) 27fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot : fSize(paint.getTextSize()) 28fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot , fScaleX(paint.getTextScaleX()) 29fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot , fTypeface(SkSafeRef(paint.getTypeface())) 30fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot , fSkewX(paint.getTextSkewX()) 31fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot , fAlign(paint.getTextAlign()) 32fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot , fHinting(paint.getHinting()) 33fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot , fFlags(paint.getFlags() & kFlagsMask) { } 34fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 35fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot void applyToPaint(SkPaint* paint) const { 36fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot paint->setTextEncoding(SkPaint::kGlyphID_TextEncoding); 37fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot paint->setTypeface(fTypeface); 38fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot paint->setTextSize(fSize); 39fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot paint->setTextScaleX(fScaleX); 40fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot paint->setTextSkewX(fSkewX); 41fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot paint->setTextAlign(static_cast<SkPaint::Align>(fAlign)); 42fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot paint->setHinting(static_cast<SkPaint::Hinting>(fHinting)); 43fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 44fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot paint->setFlags((paint->getFlags() & ~kFlagsMask) | fFlags); 45fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 46fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 47fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot bool operator==(const RunFont& other) const { 48fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot return fTypeface == other.fTypeface 49fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot && fSize == other.fSize 50fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot && fScaleX == other.fScaleX 51fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot && fSkewX == other.fSkewX 52fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot && fAlign == other.fAlign 53fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot && fHinting == other.fHinting 54fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot && fFlags == other.fFlags; 55fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 56fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 57fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot bool operator!=(const RunFont& other) const { 58fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot return !(*this == other); 59fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 60fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 61fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot uint32_t flags() const { return fFlags; } 62fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 63fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotprivate: 64fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot const static uint32_t kFlagsMask = 65fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkPaint::kAntiAlias_Flag | 66fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkPaint::kFakeBoldText_Flag | 67fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkPaint::kLinearText_Flag | 68fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkPaint::kSubpixelText_Flag | 69fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkPaint::kDevKernText_Flag | 70fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkPaint::kLCDRenderText_Flag | 71fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkPaint::kEmbeddedBitmapText_Flag | 72fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkPaint::kAutoHinting_Flag | 73fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkPaint::kVerticalText_Flag | 74fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkPaint::kGenA8FromLCD_Flag; 75fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 76fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkScalar fSize; 77fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkScalar fScaleX; 78fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 79fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot // Keep this sk_sp off the first position, to avoid interfering with SkNoncopyable 80fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot // empty baseclass optimization (http://code.google.com/p/skia/issues/detail?id=3694). 81fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot sk_sp<SkTypeface> fTypeface; 82fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkScalar fSkewX; 83fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 84fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot static_assert(SkPaint::kAlignCount < 4, "insufficient_align_bits"); 85fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot uint32_t fAlign : 2; 86fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot static_assert(SkPaint::kFull_Hinting < 4, "insufficient_hinting_bits"); 87fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot uint32_t fHinting : 2; 88fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot static_assert((kFlagsMask & 0xffff) == kFlagsMask, "insufficient_flags_bits"); 89fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot uint32_t fFlags : 16; 90fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 91fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot typedef SkNoncopyable INHERITED; 92fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}; 93fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 94fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotstruct RunFontStorageEquivalent { 95fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkScalar fSize, fScaleX; 96fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot void* fTypeface; 97fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkScalar fSkewX; 98fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot uint32_t fFlags; 99fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}; 100fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotstatic_assert(sizeof(RunFont) == sizeof(RunFontStorageEquivalent), "runfont_should_stay_packed"); 101fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 102fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot} // anonymous namespace 103fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 104fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// 105fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// Textblob data is laid out into externally-managed storage as follows: 106fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// 107fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// ----------------------------------------------------------------------------- 108fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// | SkTextBlob | RunRecord | Glyphs[] | Pos[] | RunRecord | Glyphs[] | Pos[] | ... 109fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// ----------------------------------------------------------------------------- 110fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// 111fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// Each run record describes a text blob run, and can be used to determine the (implicit) 112fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// location of the following record. 113fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// 114fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// Extended Textblob runs have more data after the Pos[] array: 115fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// 116fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// ------------------------------------------------------------------------- 117fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// ... | RunRecord | Glyphs[] | Pos[] | TextSize | Clusters[] | Text[] | ... 118fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// ------------------------------------------------------------------------- 119fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// 120fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// To determine the length of the extended run data, the TextSize must be read. 121fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// 122fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// Extended Textblob runs may be mixed with non-extended runs. 123fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 124fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team RobotSkDEBUGCODE(static const unsigned kRunRecordMagic = 0xb10bcafe;) 125fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 126fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotnamespace { 127fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotstruct RunRecordStorageEquivalent { 128fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot RunFont fFont; 129fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkPoint fOffset; 130fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot uint32_t fCount; 131fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot uint32_t fFlags; 132fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkDEBUGCODE(unsigned fMagic;) 133fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}; 134fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot} 135fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 136fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotclass SkTextBlob::RunRecord { 137fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotpublic: 138fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot RunRecord(uint32_t count, uint32_t textSize, const SkPoint& offset, const SkPaint& font, GlyphPositioning pos) 139fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot : fFont(font) 140fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot , fCount(count) 141fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot , fOffset(offset) 142fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot , fFlags(pos) { 143fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkASSERT(static_cast<unsigned>(pos) <= Flags::kPositioning_Mask); 144fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 145fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkDEBUGCODE(fMagic = kRunRecordMagic); 146fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot if (textSize > 0) { 147fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot fFlags |= kExtended_Flag; 148fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot *this->textSizePtr() = textSize; 149fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 150fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 151fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 152fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot uint32_t glyphCount() const { 153fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot return fCount; 154fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 155fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 156fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot const SkPoint& offset() const { 157fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot return fOffset; 158fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 159fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 160fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot const RunFont& font() const { 161fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot return fFont; 162fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 163fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 164fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot GlyphPositioning positioning() const { 165fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot return static_cast<GlyphPositioning>(fFlags & kPositioning_Mask); 166fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 167fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 168fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot uint16_t* glyphBuffer() const { 169fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot static_assert(SkIsAlignPtr(sizeof(RunRecord)), ""); 170fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot // Glyphs are stored immediately following the record. 171fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot return reinterpret_cast<uint16_t*>(const_cast<RunRecord*>(this) + 1); 172fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 173fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 174fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkScalar* posBuffer() const { 175fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot // Position scalars follow the (aligned) glyph buffer. 176fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot return reinterpret_cast<SkScalar*>(reinterpret_cast<uint8_t*>(this->glyphBuffer()) + 177fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkAlign4(fCount * sizeof(uint16_t))); 178fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 179fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 180fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot uint32_t textSize() const { return isExtended() ? *this->textSizePtr() : 0; } 181fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 182fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot uint32_t* clusterBuffer() const { 183fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot // clusters follow the textSize. 184fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot return isExtended() ? 1 + this->textSizePtr() : nullptr; 185fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 186fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 187fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot char* textBuffer() const { 188fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot return isExtended() 189fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot ? reinterpret_cast<char*>(this->clusterBuffer() + fCount) 190fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot : nullptr; 191fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 192fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 193fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot static size_t StorageSize(uint32_t glyphCount, uint32_t textSize, 194fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkTextBlob::GlyphPositioning positioning, 195fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkSafeMath* safe) { 196fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot static_assert(SkIsAlign4(sizeof(SkScalar)), "SkScalar size alignment"); 197fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 198fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot auto glyphSize = safe->mul(glyphCount, sizeof(uint16_t)), 199fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot posSize = safe->mul(PosCount(glyphCount, positioning, safe), sizeof(SkScalar)); 200fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 201fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot // RunRecord object + (aligned) glyph buffer + position buffer 202fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot auto size = sizeof(SkTextBlob::RunRecord); 203fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot size = safe->add(size, safe->alignUp(glyphSize, 4)); 204fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot size = safe->add(size, posSize); 205fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 206fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot if (textSize) { // Extended run. 207fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot size = safe->add(size, sizeof(uint32_t)); 208fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot size = safe->add(size, safe->mul(glyphCount, sizeof(uint32_t))); 209fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot size = safe->add(size, textSize); 210fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 211fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 212fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot return safe->alignUp(size, sizeof(void*)); 213fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 214fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 215fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot static const RunRecord* First(const SkTextBlob* blob) { 216fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot // The first record (if present) is stored following the blob object. 217fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot return reinterpret_cast<const RunRecord*>(blob + 1); 218fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 219fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 220fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot static const RunRecord* Next(const RunRecord* run) { 221fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot return SkToBool(run->fFlags & kLast_Flag) ? nullptr : NextUnchecked(run); 222fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 223fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 224fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot void validate(const uint8_t* storageTop) const { 225fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkASSERT(kRunRecordMagic == fMagic); 226fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkASSERT((uint8_t*)NextUnchecked(this) <= storageTop); 227fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 228fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkASSERT(glyphBuffer() + fCount <= (uint16_t*)posBuffer()); 229fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkASSERT(posBuffer() + fCount * ScalarsPerGlyph(positioning()) 230fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot <= (SkScalar*)NextUnchecked(this)); 231fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot if (isExtended()) { 232fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkASSERT(textSize() > 0); 233fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkASSERT(textSizePtr() < (uint32_t*)NextUnchecked(this)); 234fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkASSERT(clusterBuffer() < (uint32_t*)NextUnchecked(this)); 235fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkASSERT(textBuffer() + textSize() <= (char*)NextUnchecked(this)); 236fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 237fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot static_assert(sizeof(SkTextBlob::RunRecord) == sizeof(RunRecordStorageEquivalent), 238fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot "runrecord_should_stay_packed"); 239fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 240fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 241fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotprivate: 242fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot friend class SkTextBlobBuilder; 243fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 244fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot enum Flags { 245fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot kPositioning_Mask = 0x03, // bits 0-1 reserved for positioning 246fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot kLast_Flag = 0x04, // set for the last blob run 247fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot kExtended_Flag = 0x08, // set for runs with text/cluster info 248fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot }; 249fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 250fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot static const RunRecord* NextUnchecked(const RunRecord* run) { 251fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkSafeMath safe; 252fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot auto res = reinterpret_cast<const RunRecord*>( 253fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot reinterpret_cast<const uint8_t*>(run) 254fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot + StorageSize(run->glyphCount(), run->textSize(), run->positioning(), &safe)); 255fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkASSERT(safe); 256fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot return res; 257fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 258fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 259fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot static size_t PosCount(uint32_t glyphCount, 260fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkTextBlob::GlyphPositioning positioning, 261fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkSafeMath* safe) { 262fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot return safe->mul(glyphCount, ScalarsPerGlyph(positioning)); 263fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 264fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 265fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot uint32_t* textSizePtr() const { 266fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot // textSize follows the position buffer. 267fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkASSERT(isExtended()); 268fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkSafeMath safe; 269fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot auto res = (uint32_t*)(&this->posBuffer()[PosCount(fCount, positioning(), &safe)]); 270fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkASSERT(safe); 271fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot return res; 272fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 273fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 274fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot void grow(uint32_t count) { 275fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkScalar* initialPosBuffer = posBuffer(); 276fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot uint32_t initialCount = fCount; 277fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot fCount += count; 278fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 279fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot // Move the initial pos scalars to their new location. 280fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot size_t copySize = initialCount * sizeof(SkScalar) * ScalarsPerGlyph(positioning()); 281fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkASSERT((uint8_t*)posBuffer() + copySize <= (uint8_t*)NextUnchecked(this)); 282fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 283fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot // memmove, as the buffers may overlap 284fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot memmove(posBuffer(), initialPosBuffer, copySize); 285fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 286fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 287fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot bool isExtended() const { 288fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot return fFlags & kExtended_Flag; 289fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 290fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 291fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot RunFont fFont; 292fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot uint32_t fCount; 293fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkPoint fOffset; 294fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot uint32_t fFlags; 295fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 296fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkDEBUGCODE(unsigned fMagic;) 297fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}; 298fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 299fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotstatic int32_t gNextID = 1; 300fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotstatic int32_t next_id() { 301fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot int32_t id; 302fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot do { 303fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot id = sk_atomic_inc(&gNextID); 304fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } while (id == SK_InvalidGenID); 305fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot return id; 306fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot} 307fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 308fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team RobotSkTextBlob::SkTextBlob(const SkRect& bounds) 309fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot : fBounds(bounds) 310fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot , fUniqueID(next_id()) 311fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot , fCacheID(SK_InvalidUniqueID) {} 312fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 313fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team RobotSkTextBlob::~SkTextBlob() { 314fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#if SK_SUPPORT_GPU 315fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot if (SK_InvalidUniqueID != fCacheID.load()) { 316fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot GrTextBlobCache::PostPurgeBlobMessage(fUniqueID, fCacheID); 317fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 318fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#endif 319fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 320fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot const auto* run = RunRecord::First(this); 321fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot do { 322fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot const auto* nextRun = RunRecord::Next(run); 323fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkDEBUGCODE(run->validate((uint8_t*)this + fStorageSize);) 324fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot run->~RunRecord(); 325fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot run = nextRun; 326fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } while (run); 327fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot} 328fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 329fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotnamespace { 330fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 331fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotunion PositioningAndExtended { 332fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot int32_t intValue; 333fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot struct { 334fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkTextBlob::GlyphPositioning positioning; 335fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot uint8_t extended; 336fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot uint16_t padding; 337fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot }; 338fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}; 339fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 340fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotstatic_assert(sizeof(PositioningAndExtended) == sizeof(int32_t), ""); 341fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 342fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot} // namespace 343fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 344fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotunsigned SkTextBlob::ScalarsPerGlyph(GlyphPositioning pos) { 345fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot // GlyphPositioning values are directly mapped to scalars-per-glyph. 346fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkASSERT(pos <= 2); 347fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot return pos; 348fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot} 349fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 350fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team RobotSkTextBlobRunIterator::SkTextBlobRunIterator(const SkTextBlob* blob) 351fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot : fCurrentRun(SkTextBlob::RunRecord::First(blob)) { 352fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkDEBUGCODE(fStorageTop = (uint8_t*)blob + blob->fStorageSize;) 353fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot} 354fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 355fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotbool SkTextBlobRunIterator::done() const { 356fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot return !fCurrentRun; 357fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot} 358fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 359fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkTextBlobRunIterator::next() { 360fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkASSERT(!this->done()); 361fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 362fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot if (!this->done()) { 363fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkDEBUGCODE(fCurrentRun->validate(fStorageTop);) 364fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot fCurrentRun = SkTextBlob::RunRecord::Next(fCurrentRun); 365fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 366fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot} 367fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 368fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotuint32_t SkTextBlobRunIterator::glyphCount() const { 369fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkASSERT(!this->done()); 370fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot return fCurrentRun->glyphCount(); 371fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot} 372fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 373fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotconst uint16_t* SkTextBlobRunIterator::glyphs() const { 374fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkASSERT(!this->done()); 375fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot return fCurrentRun->glyphBuffer(); 376fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot} 377fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 378fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotconst SkScalar* SkTextBlobRunIterator::pos() const { 379fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkASSERT(!this->done()); 380fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot return fCurrentRun->posBuffer(); 381fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot} 382fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 383fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotconst SkPoint& SkTextBlobRunIterator::offset() const { 384fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkASSERT(!this->done()); 385fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot return fCurrentRun->offset(); 386fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot} 387fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 388fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team RobotSkTextBlob::GlyphPositioning SkTextBlobRunIterator::positioning() const { 389fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkASSERT(!this->done()); 390fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot return fCurrentRun->positioning(); 391fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot} 392fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 393fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkTextBlobRunIterator::applyFontToPaint(SkPaint* paint) const { 394fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkASSERT(!this->done()); 395fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 396fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot fCurrentRun->font().applyToPaint(paint); 397fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot} 398fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 399fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotuint32_t* SkTextBlobRunIterator::clusters() const { 400fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkASSERT(!this->done()); 401fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot return fCurrentRun->clusterBuffer(); 402fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot} 403fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotuint32_t SkTextBlobRunIterator::textSize() const { 404fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkASSERT(!this->done()); 405fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot return fCurrentRun->textSize(); 406fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot} 407fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotchar* SkTextBlobRunIterator::text() const { 408fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkASSERT(!this->done()); 409fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot return fCurrentRun->textBuffer(); 410fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot} 411fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 412fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 413fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotbool SkTextBlobRunIterator::isLCD() const { 414fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot return SkToBool(fCurrentRun->font().flags() & SkPaint::kLCDRenderText_Flag); 415fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot} 416fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 417fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team RobotSkTextBlobBuilder::SkTextBlobBuilder() 418fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot : fStorageSize(0) 419fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot , fStorageUsed(0) 420fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot , fRunCount(0) 421fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot , fDeferredBounds(false) 422fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot , fLastRun(0) { 423fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot fBounds.setEmpty(); 424fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot} 425fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 426fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team RobotSkTextBlobBuilder::~SkTextBlobBuilder() { 427fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot if (nullptr != fStorage.get()) { 428fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot // We are abandoning runs and must destruct the associated font data. 429fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot // The easiest way to accomplish that is to use the blob destructor. 430fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot this->make(); 431fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 432fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot} 433fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 434fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team RobotSkRect SkTextBlobBuilder::TightRunBounds(const SkTextBlob::RunRecord& run) { 435fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkRect bounds; 436fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkPaint paint; 437fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot run.font().applyToPaint(&paint); 438fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 439fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot if (SkTextBlob::kDefault_Positioning == run.positioning()) { 440fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot paint.measureText(run.glyphBuffer(), run.glyphCount() * sizeof(uint16_t), &bounds); 441fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot return bounds.makeOffset(run.offset().x(), run.offset().y()); 442fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 443fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 444fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkAutoSTArray<16, SkRect> glyphBounds(run.glyphCount()); 445fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot paint.getTextWidths(run.glyphBuffer(), 446fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot run.glyphCount() * sizeof(uint16_t), 447fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot nullptr, 448fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot glyphBounds.get()); 449fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 450fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkASSERT(SkTextBlob::kFull_Positioning == run.positioning() || 451fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkTextBlob::kHorizontal_Positioning == run.positioning()); 452fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot // kFull_Positioning => [ x, y, x, y... ] 453fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot // kHorizontal_Positioning => [ x, x, x... ] 454fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot // (const y applied by runBounds.offset(run->offset()) later) 455fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot const SkScalar horizontalConstY = 0; 456fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot const SkScalar* glyphPosX = run.posBuffer(); 457fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot const SkScalar* glyphPosY = (run.positioning() == SkTextBlob::kFull_Positioning) ? 458fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot glyphPosX + 1 : &horizontalConstY; 459fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot const unsigned posXInc = SkTextBlob::ScalarsPerGlyph(run.positioning()); 460fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot const unsigned posYInc = (run.positioning() == SkTextBlob::kFull_Positioning) ? 461fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot posXInc : 0; 462fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 463fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot bounds.setEmpty(); 464fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot for (unsigned i = 0; i < run.glyphCount(); ++i) { 465fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot bounds.join(glyphBounds[i].makeOffset(*glyphPosX, *glyphPosY)); 466fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot glyphPosX += posXInc; 467fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot glyphPosY += posYInc; 468fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 469fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 470fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkASSERT((void*)glyphPosX <= SkTextBlob::RunRecord::Next(&run)); 471fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 472fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot return bounds.makeOffset(run.offset().x(), run.offset().y()); 473fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot} 474fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 475fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team RobotSkRect SkTextBlobBuilder::ConservativeRunBounds(const SkTextBlob::RunRecord& run) { 476fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkASSERT(run.glyphCount() > 0); 477fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkASSERT(SkTextBlob::kFull_Positioning == run.positioning() || 478fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkTextBlob::kHorizontal_Positioning == run.positioning()); 479fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 480fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkPaint paint; 481fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot run.font().applyToPaint(&paint); 482fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot const SkRect fontBounds = paint.getFontBounds(); 483fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot if (fontBounds.isEmpty()) { 484fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot // Empty font bounds are likely a font bug. TightBounds has a better chance of 485fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot // producing useful results in this case. 486fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot return TightRunBounds(run); 487fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 488fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 489fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot // Compute the glyph position bbox. 490fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkRect bounds; 491fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot switch (run.positioning()) { 492fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot case SkTextBlob::kHorizontal_Positioning: { 493fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot const SkScalar* glyphPos = run.posBuffer(); 494fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkASSERT((void*)(glyphPos + run.glyphCount()) <= SkTextBlob::RunRecord::Next(&run)); 495fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 496fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkScalar minX = *glyphPos; 497fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkScalar maxX = *glyphPos; 498fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot for (unsigned i = 1; i < run.glyphCount(); ++i) { 499fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkScalar x = glyphPos[i]; 500fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot minX = SkMinScalar(x, minX); 501fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot maxX = SkMaxScalar(x, maxX); 502fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 503fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 504fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot bounds.setLTRB(minX, 0, maxX, 0); 505fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } break; 506fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot case SkTextBlob::kFull_Positioning: { 507fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot const SkPoint* glyphPosPts = reinterpret_cast<const SkPoint*>(run.posBuffer()); 508fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkASSERT((void*)(glyphPosPts + run.glyphCount()) <= SkTextBlob::RunRecord::Next(&run)); 509fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 510fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot bounds.setBounds(glyphPosPts, run.glyphCount()); 511fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } break; 512fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot default: 513fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SK_ABORT("unsupported positioning mode"); 514fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 515fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 516fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot // Expand by typeface glyph bounds. 517fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot bounds.fLeft += fontBounds.left(); 518fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot bounds.fTop += fontBounds.top(); 519fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot bounds.fRight += fontBounds.right(); 520fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot bounds.fBottom += fontBounds.bottom(); 521fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 522fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot // Offset by run position. 523fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot return bounds.makeOffset(run.offset().x(), run.offset().y()); 524fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot} 525fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 526fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkTextBlobBuilder::updateDeferredBounds() { 527fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkASSERT(!fDeferredBounds || fRunCount > 0); 528fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 529fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot if (!fDeferredBounds) { 530fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot return; 531fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 532fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 533fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkASSERT(fLastRun >= sizeof(SkTextBlob)); 534fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkTextBlob::RunRecord* run = reinterpret_cast<SkTextBlob::RunRecord*>(fStorage.get() + 535fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot fLastRun); 536fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 537fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot // FIXME: we should also use conservative bounds for kDefault_Positioning. 538fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkRect runBounds = SkTextBlob::kDefault_Positioning == run->positioning() ? 539fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot TightRunBounds(*run) : ConservativeRunBounds(*run); 540fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot fBounds.join(runBounds); 541fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot fDeferredBounds = false; 542fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot} 543fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 544fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkTextBlobBuilder::reserve(size_t size) { 545fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkSafeMath safe; 546fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 547fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot // We don't currently pre-allocate, but maybe someday... 548fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot if (safe.add(fStorageUsed, size) <= fStorageSize && safe) { 549fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot return; 550fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 551fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 552fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot if (0 == fRunCount) { 553fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkASSERT(nullptr == fStorage.get()); 554fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkASSERT(0 == fStorageSize); 555fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkASSERT(0 == fStorageUsed); 556fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 557fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot // the first allocation also includes blob storage 558fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot fStorageUsed = sizeof(SkTextBlob); 559fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 560fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 561fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot fStorageSize = safe.add(fStorageUsed, size); 562fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 563fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot // FYI: This relies on everything we store being relocatable, particularly SkPaint. 564fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot // Also, this is counting on the underlying realloc to throw when passed max(). 565fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot fStorage.realloc(safe ? fStorageSize : std::numeric_limits<size_t>::max()); 566fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot} 567fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 568fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotbool SkTextBlobBuilder::mergeRun(const SkPaint &font, SkTextBlob::GlyphPositioning positioning, 569fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot uint32_t count, SkPoint offset) { 570fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot if (0 == fLastRun) { 571fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkASSERT(0 == fRunCount); 572fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot return false; 573fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 574fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 575fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkASSERT(fLastRun >= sizeof(SkTextBlob)); 576fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkTextBlob::RunRecord* run = reinterpret_cast<SkTextBlob::RunRecord*>(fStorage.get() + 577fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot fLastRun); 578fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkASSERT(run->glyphCount() > 0); 579fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 580fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot if (run->textSize() != 0) { 581fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot return false; 582fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 583fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 584fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot if (run->positioning() != positioning 585fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot || run->font() != font 586fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot || (run->glyphCount() + count < run->glyphCount())) { 587fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot return false; 588fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 589fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 590fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot // we can merge same-font/same-positioning runs in the following cases: 591fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot // * fully positioned run following another fully positioned run 592fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot // * horizontally postioned run following another horizontally positioned run with the same 593fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot // y-offset 594fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot if (SkTextBlob::kFull_Positioning != positioning 595fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot && (SkTextBlob::kHorizontal_Positioning != positioning 596fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot || run->offset().y() != offset.y())) { 597fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot return false; 598fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 599fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 600fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkSafeMath safe; 601fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot size_t sizeDelta = 602fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkTextBlob::RunRecord::StorageSize(run->glyphCount() + count, 0, positioning, &safe) - 603fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkTextBlob::RunRecord::StorageSize(run->glyphCount() , 0, positioning, &safe); 604fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot if (!safe) { 605fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot return false; 606fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 607fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 608fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot this->reserve(sizeDelta); 609fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 610fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot // reserve may have realloced 611fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot run = reinterpret_cast<SkTextBlob::RunRecord*>(fStorage.get() + fLastRun); 612fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot uint32_t preMergeCount = run->glyphCount(); 613fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot run->grow(count); 614fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 615fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot // Callers expect the buffers to point at the newly added slice, ant not at the beginning. 616fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot fCurrentRunBuffer.glyphs = run->glyphBuffer() + preMergeCount; 617fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot fCurrentRunBuffer.pos = run->posBuffer() 618fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot + preMergeCount * SkTextBlob::ScalarsPerGlyph(positioning); 619fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 620fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot fStorageUsed += sizeDelta; 621fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 622fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkASSERT(fStorageUsed <= fStorageSize); 623fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot run->validate(fStorage.get() + fStorageUsed); 624fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 625fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot return true; 626fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot} 627fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 628fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkTextBlobBuilder::allocInternal(const SkPaint &font, 629fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkTextBlob::GlyphPositioning positioning, 630fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot int count, int textSize, SkPoint offset, 631fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot const SkRect* bounds) { 632fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot if (count <= 0 || textSize < 0 || font.getTextEncoding() != SkPaint::kGlyphID_TextEncoding) { 633fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot fCurrentRunBuffer = { nullptr, nullptr, nullptr, nullptr }; 634fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot return; 635fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 636fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 637fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot if (textSize != 0 || !this->mergeRun(font, positioning, count, offset)) { 638fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot this->updateDeferredBounds(); 639fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 640fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkSafeMath safe; 641fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot size_t runSize = SkTextBlob::RunRecord::StorageSize(count, textSize, positioning, &safe); 642fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot if (!safe) { 643fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot fCurrentRunBuffer = { nullptr, nullptr, nullptr, nullptr }; 644fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot return; 645fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 646fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 647fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot this->reserve(runSize); 648fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 649fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkASSERT(fStorageUsed >= sizeof(SkTextBlob)); 650fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkASSERT(fStorageUsed + runSize <= fStorageSize); 651fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 652fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkTextBlob::RunRecord* run = new (fStorage.get() + fStorageUsed) 653fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkTextBlob::RunRecord(count, textSize, offset, font, positioning); 654fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot fCurrentRunBuffer.glyphs = run->glyphBuffer(); 655fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot fCurrentRunBuffer.pos = run->posBuffer(); 656fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot fCurrentRunBuffer.utf8text = run->textBuffer(); 657fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot fCurrentRunBuffer.clusters = run->clusterBuffer(); 658fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 659fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot fLastRun = fStorageUsed; 660fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot fStorageUsed += runSize; 661fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot fRunCount++; 662fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 663fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkASSERT(fStorageUsed <= fStorageSize); 664fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot run->validate(fStorage.get() + fStorageUsed); 665fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 666fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkASSERT(textSize > 0 || nullptr == fCurrentRunBuffer.utf8text); 667fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkASSERT(textSize > 0 || nullptr == fCurrentRunBuffer.clusters); 668fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot if (!fDeferredBounds) { 669fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot if (bounds) { 670fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot fBounds.join(*bounds); 671fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } else { 672fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot fDeferredBounds = true; 673fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 674fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 675fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot} 676fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 677fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotconst SkTextBlobBuilder::RunBuffer& SkTextBlobBuilder::allocRunText(const SkPaint& font, int count, 678fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkScalar x, SkScalar y, 679fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot int textByteCount, 680fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkString lang, 681fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot const SkRect* bounds) { 682fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot this->allocInternal(font, SkTextBlob::kDefault_Positioning, count, textByteCount, SkPoint::Make(x, y), bounds); 683fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot return fCurrentRunBuffer; 684fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot} 685fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 686fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotconst SkTextBlobBuilder::RunBuffer& SkTextBlobBuilder::allocRunTextPosH(const SkPaint& font, int count, 687fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkScalar y, 688fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot int textByteCount, 689fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkString lang, 690fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot const SkRect* bounds) { 691fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot this->allocInternal(font, SkTextBlob::kHorizontal_Positioning, count, textByteCount, SkPoint::Make(0, y), 692fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot bounds); 693fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 694fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot return fCurrentRunBuffer; 695fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot} 696fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 697fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotconst SkTextBlobBuilder::RunBuffer& SkTextBlobBuilder::allocRunTextPos(const SkPaint& font, int count, 698fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot int textByteCount, 699fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkString lang, 700fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot const SkRect *bounds) { 701fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot this->allocInternal(font, SkTextBlob::kFull_Positioning, count, textByteCount, SkPoint::Make(0, 0), bounds); 702fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 703fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot return fCurrentRunBuffer; 704fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot} 705fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 706fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotsk_sp<SkTextBlob> SkTextBlobBuilder::make() { 707fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot if (!fRunCount) { 708fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot // We don't instantiate empty blobs. 709fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkASSERT(!fStorage.get()); 710fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkASSERT(fStorageUsed == 0); 711fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkASSERT(fStorageSize == 0); 712fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkASSERT(fLastRun == 0); 713fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkASSERT(fBounds.isEmpty()); 714fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot return nullptr; 715fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 716fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 717fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot this->updateDeferredBounds(); 718fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 719fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot // Tag the last run as such. 720fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot auto* lastRun = reinterpret_cast<SkTextBlob::RunRecord*>(fStorage.get() + fLastRun); 721fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot lastRun->fFlags |= SkTextBlob::RunRecord::kLast_Flag; 722fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 723fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkTextBlob* blob = new (fStorage.release()) SkTextBlob(fBounds); 724fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkDEBUGCODE(const_cast<SkTextBlob*>(blob)->fStorageSize = fStorageSize;) 725fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 726fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkDEBUGCODE( 727fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkSafeMath safe; 728fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot size_t validateSize = sizeof(SkTextBlob); 729fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot for (const auto* run = SkTextBlob::RunRecord::First(blob); run; 730fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot run = SkTextBlob::RunRecord::Next(run)) { 731fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot validateSize += SkTextBlob::RunRecord::StorageSize( 732fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot run->fCount, run->textSize(), run->positioning(), &safe); 733fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot run->validate(reinterpret_cast<const uint8_t*>(blob) + fStorageUsed); 734fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot fRunCount--; 735fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 736fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkASSERT(validateSize == fStorageUsed); 737fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkASSERT(fRunCount == 0); 738fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkASSERT(safe); 739fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot ) 740fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 741fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot fStorageUsed = 0; 742fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot fStorageSize = 0; 743fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot fRunCount = 0; 744fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot fLastRun = 0; 745fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot fBounds.setEmpty(); 746fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 747fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot return sk_sp<SkTextBlob>(blob); 748fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot} 749fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 750fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot/////////////////////////////////////////////////////////////////////////////////////////////////// 751fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 752fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkTextBlob::flatten(SkWriteBuffer& buffer) const { 753fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot buffer.writeRect(fBounds); 754fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 755fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkPaint runPaint; 756fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkTextBlobRunIterator it(this); 757fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot while (!it.done()) { 758fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkASSERT(it.glyphCount() > 0); 759fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 760fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot buffer.write32(it.glyphCount()); 761fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot PositioningAndExtended pe; 762fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot pe.intValue = 0; 763fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot pe.positioning = it.positioning(); 764fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkASSERT((int32_t)it.positioning() == pe.intValue); // backwards compat. 765fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 766fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot uint32_t textSize = it.textSize(); 767fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot pe.extended = textSize > 0; 768fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot buffer.write32(pe.intValue); 769fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot if (pe.extended) { 770fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot buffer.write32(textSize); 771fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 772fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot buffer.writePoint(it.offset()); 773fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot // This should go away when switching to SkFont 774fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot it.applyFontToPaint(&runPaint); 775fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot buffer.writePaint(runPaint); 776fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 777fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot buffer.writeByteArray(it.glyphs(), it.glyphCount() * sizeof(uint16_t)); 778fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot buffer.writeByteArray(it.pos(), 779fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot it.glyphCount() * sizeof(SkScalar) * ScalarsPerGlyph(it.positioning())); 780fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot if (pe.extended) { 781fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot buffer.writeByteArray(it.clusters(), sizeof(uint32_t) * it.glyphCount()); 782fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot buffer.writeByteArray(it.text(), it.textSize()); 783fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 784fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 785fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot it.next(); 786fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 787fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 788fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot // Marker for the last run (0 is not a valid glyph count). 789fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot buffer.write32(0); 790fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot} 791fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 792fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotsk_sp<SkTextBlob> SkTextBlob::MakeFromBuffer(SkReadBuffer& reader) { 793fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkRect bounds; 794fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot reader.readRect(&bounds); 795fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 796fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkTextBlobBuilder blobBuilder; 797fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot for (;;) { 798fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot int glyphCount = reader.read32(); 799fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot if (glyphCount == 0) { 800fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot // End-of-runs marker. 801fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot break; 802fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 803fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 804fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot PositioningAndExtended pe; 805fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot pe.intValue = reader.read32(); 806fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot GlyphPositioning pos = pe.positioning; 807fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot if (glyphCount <= 0 || pos > kFull_Positioning) { 808fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot return nullptr; 809fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 810fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot int textSize = pe.extended ? reader.read32() : 0; 811fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot if (textSize < 0) { 812fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot return nullptr; 813fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 814fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 815fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkPoint offset; 816fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot reader.readPoint(&offset); 817fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkPaint font; 818fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot reader.readPaint(&font); 819fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 820fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot if (!reader.isValid()) { 821fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot return nullptr; 822fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 823fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 824fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot const SkTextBlobBuilder::RunBuffer* buf = nullptr; 825fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot switch (pos) { 826fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot case kDefault_Positioning: 827fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot buf = &blobBuilder.allocRunText(font, glyphCount, offset.x(), offset.y(), 828fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot textSize, SkString(), &bounds); 829fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot break; 830fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot case kHorizontal_Positioning: 831fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot buf = &blobBuilder.allocRunTextPosH(font, glyphCount, offset.y(), 832fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot textSize, SkString(), &bounds); 833fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot break; 834fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot case kFull_Positioning: 835fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot buf = &blobBuilder.allocRunTextPos(font, glyphCount, textSize, SkString(), &bounds); 836fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot break; 837fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot default: 838fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot return nullptr; 839fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 840fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 841fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot if (!buf->glyphs || 842fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot !buf->pos || 843fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot (pe.extended && (!buf->clusters || !buf->utf8text))) { 844fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot return nullptr; 845fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 846fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 847fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot if (!reader.readByteArray(buf->glyphs, glyphCount * sizeof(uint16_t)) || 848fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot !reader.readByteArray(buf->pos, 849fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot glyphCount * sizeof(SkScalar) * ScalarsPerGlyph(pos))) { 850fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot return nullptr; 851fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 852fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 853fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot if (pe.extended) { 854fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot if (!reader.readByteArray(buf->clusters, glyphCount * sizeof(uint32_t)) || 855fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot !reader.readByteArray(buf->utf8text, textSize)) { 856fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot return nullptr; 857fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 858fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 859fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 860fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 861fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot return blobBuilder.make(); 862fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot} 863fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 864fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotsk_sp<SkData> SkTextBlob::serialize(const SkSerialProcs& procs) const { 865fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkBinaryWriteBuffer buffer; 866fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot buffer.setSerialProcs(procs); 867fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot this->flatten(buffer); 868fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 869fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot size_t total = buffer.bytesWritten(); 870fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot sk_sp<SkData> data = SkData::MakeUninitialized(total); 871fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot buffer.writeToMemory(data->writable_data()); 872fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot return data; 873fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot} 874fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 875fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotsk_sp<SkData> SkTextBlob::serialize() const { 876fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot return this->serialize(SkSerialProcs()); 877fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot} 878fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 879fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotsk_sp<SkTextBlob> SkTextBlob::Deserialize(const void* data, size_t length, 880fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot const SkDeserialProcs& procs) { 881fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkReadBuffer buffer(data, length); 882fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot buffer.setDeserialProcs(procs); 883fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot return SkTextBlob::MakeFromBuffer(buffer); 884fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot} 885fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 886fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotsk_sp<SkTextBlob> SkTextBlob::Deserialize(const void* data, size_t length) { 887fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot return SkTextBlob::Deserialize(data, length, SkDeserialProcs()); 888fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot} 889fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 890fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot/////////////////////////////////////////////////////////////////////////////////////////////////// 891fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 892fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotnamespace { 893fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot struct CatalogState { 894fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkTypefaceCatalogerProc fProc; 895fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot void* fCtx; 896fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot }; 897fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 898fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot sk_sp<SkData> catalog_typeface_proc(SkTypeface* face, void* ctx) { 899fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot CatalogState* state = static_cast<CatalogState*>(ctx); 900fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot state->fProc(face, state->fCtx); 901fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot uint32_t id = face->uniqueID(); 902fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot return SkData::MakeWithCopy(&id, sizeof(uint32_t)); 903fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 904fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot} 905fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 906fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotsk_sp<SkData> SkTextBlob::serialize(SkTypefaceCatalogerProc proc, void* ctx) const { 907fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot CatalogState state = { proc, ctx }; 908fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkSerialProcs procs; 909fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot procs.fTypefaceProc = catalog_typeface_proc; 910fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot procs.fTypefaceCtx = &state; 911fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot return this->serialize(procs); 912fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot} 913fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 914fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotnamespace { 915fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot struct ResolverState { 916fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkTypefaceResolverProc fProc; 917fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot void* fCtx; 918fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot }; 919fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 920fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot sk_sp<SkTypeface> resolver_typeface_proc(const void* data, size_t length, void* ctx) { 921fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot if (length != 4) { 922fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot return nullptr; 923fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 924fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 925fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot ResolverState* state = static_cast<ResolverState*>(ctx); 926fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot uint32_t id; 927fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot memcpy(&id, data, length); 928fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot return state->fProc(id, state->fCtx); 929fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 930fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot} 931fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 932fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotsk_sp<SkTextBlob> SkTextBlob::Deserialize(const void* data, size_t length, 933fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkTypefaceResolverProc proc, void* ctx) { 934fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot ResolverState state = { proc, ctx }; 935fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkDeserialProcs procs; 936fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot procs.fTypefaceProc = resolver_typeface_proc; 937fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot procs.fTypefaceCtx = &state; 938fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot return Deserialize(data, length, procs); 939fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot} 940