Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 /* | |
| 2 * Copyright 2014 Google Inc. | |
| 3 * | |
| 4 * Use of this source code is governed by a BSD-style license that can be | |
| 5 * found in the LICENSE file. | |
| 6 */ | |
| 7 | |
| 8 #include "SkTextBlob.h" | |
| 9 | |
| 10 SkTextBlob::SkTextBlob(uint16_t *glyphs, SkScalar *pos, const SkTArray<Run> *run s, | |
| 11 const SkRect& bounds) | |
| 12 : fGlyphBuffer(glyphs) | |
| 13 , fPosBuffer(pos) | |
| 14 , fRuns(runs) | |
| 15 , fBounds(bounds) { | |
| 16 } | |
| 17 | |
| 18 uint32_t SkTextBlob::uniqueID() const { | |
| 19 static int32_t gTextBlobGenerationID; // = 0; | |
| 20 | |
| 21 // loop in case our global wraps around, as we never want to return SK_Inval idGenID | |
| 22 while (SK_InvalidGenID == fUniqueID) { | |
| 23 fUniqueID = sk_atomic_inc(&gTextBlobGenerationID) + 1; | |
| 24 } | |
| 25 | |
| 26 return fUniqueID; | |
| 27 } | |
| 28 | |
| 29 SkTextBlob::RunIterator::RunIterator(const SkTextBlob* blob) | |
| 30 : fBlob(blob) | |
| 31 , fIndex(0) { | |
| 32 SkASSERT(NULL != blob); | |
| 33 } | |
| 34 | |
| 35 bool SkTextBlob::RunIterator::done() const { | |
| 36 return NULL == fBlob->fRuns.get() || fIndex >= fBlob->fRuns->count(); | |
| 37 } | |
| 38 | |
| 39 void SkTextBlob::RunIterator::next() { | |
| 40 SkASSERT(!this->done()); | |
| 41 fIndex++; | |
| 42 } | |
| 43 | |
| 44 uint32_t SkTextBlob::RunIterator::glyphCount() const { | |
| 45 SkASSERT(!this->done()); | |
| 46 return (*fBlob->fRuns)[fIndex].count; | |
| 47 } | |
| 48 | |
| 49 const uint16_t* SkTextBlob::RunIterator::glyphs() const { | |
| 50 SkASSERT(!this->done()); | |
| 51 return fBlob->fGlyphBuffer.get() + (*fBlob->fRuns)[fIndex].glyphStart; | |
| 52 } | |
| 53 | |
| 54 const SkScalar* SkTextBlob::RunIterator::pos() const { | |
| 55 SkASSERT(!this->done()); | |
| 56 return fBlob->fPosBuffer.get() + (*fBlob->fRuns)[fIndex].posStart; | |
| 57 } | |
| 58 | |
| 59 const SkPaint& SkTextBlob::RunIterator::font() const { | |
| 60 SkASSERT(!this->done()); | |
| 61 return (*fBlob->fRuns)[fIndex].font; | |
| 62 } | |
| 63 | |
| 64 SkTextBlob::GlyphPositioning SkTextBlob::RunIterator::positioning() const { | |
| 65 SkASSERT(!this->done()); | |
| 66 return (*fBlob->fRuns)[fIndex].positioning; | |
| 67 } | |
| 68 | |
| 69 SkTextBlobBuilder::SkTextBlobBuilder(unsigned runs) | |
| 70 : fRuns(NULL) | |
| 71 , fDeferredBounds(false) { | |
| 72 | |
| 73 if (runs > 0) { | |
| 74 // if the number of runs is known, size our run storage accordingly. | |
| 75 fRuns = SkNEW(SkTArray<SkTextBlob::Run>(runs)); | |
| 76 } | |
| 77 fBounds.setEmpty(); | |
| 78 } | |
| 79 | |
| 80 SkTextBlobBuilder::~SkTextBlobBuilder() { | |
| 81 // unused runs | |
| 82 SkDELETE(fRuns); | |
| 83 } | |
| 84 | |
| 85 void SkTextBlobBuilder::updateDeferredBounds() { | |
| 86 SkASSERT(!fDeferredBounds || (NULL != fRuns && !fRuns->empty())); | |
| 87 | |
| 88 if (!fDeferredBounds) { | |
| 89 return; | |
| 90 } | |
| 91 | |
| 92 // FIXME: measure the current run & union bounds | |
| 93 fDeferredBounds = false; | |
| 94 } | |
| 95 | |
| 96 void SkTextBlobBuilder::ensureRun(const SkPaint& font, SkTextBlob::GlyphPosition ing pos, | |
| 97 const SkPoint& offset) { | |
| 98 SkASSERT(SkPaint::kGlyphID_TextEncoding == font.getTextEncoding()); | |
| 99 | |
| 100 if (NULL == fRuns) { | |
| 101 fRuns = SkNEW(SkTArray<SkTextBlob::Run>()); | |
| 102 } | |
| 103 | |
| 104 // we can merge same-font/same-positioning runs in the following cases: | |
| 105 // * fully positioned run following another fully positioned run | |
| 106 // * horizontally postioned run following another horizontally positioned run with the same | |
| 107 // y-offset | |
| 108 if (!fRuns->empty() | |
| 109 && fRuns->back().positioning == pos | |
| 110 && fRuns->back().font == font | |
| 111 && (SkTextBlob::kFull_Positioning == fRuns->back().positioning | |
| 112 || (SkTextBlob::kHorizontal_Positioning == fRuns->back().positioning | |
| 113 && fRuns->back().offset.y() == offset.y()))){ | |
| 114 return; | |
| 115 } | |
| 116 | |
| 117 this->updateDeferredBounds(); | |
| 118 | |
| 119 // start a new run | |
| 120 SkTextBlob::Run& newRun = fRuns->push_back(); | |
| 121 newRun.count = 0; | |
| 122 newRun.glyphStart = fGlyphBuffer.count(); | |
| 123 newRun.posStart = fPosBuffer.count(); | |
| 124 newRun.offset = offset; | |
| 125 newRun.font = font; | |
| 126 newRun.positioning = pos; | |
| 127 } | |
| 128 | |
| 129 void SkTextBlobBuilder::alloc_internal(const SkPaint &font, | |
| 130 SkTextBlob::GlyphPositioning positioning, | |
| 131 size_t count, SkPoint offset, const SkRec t* bounds) { | |
| 132 this->ensureRun(font, positioning, offset); | |
| 133 | |
| 134 fGlyphBuffer.append(count); | |
| 135 fPosBuffer.append(count * positioning); | |
|
jbroman
2014/08/20 15:10:32
nit: It's not immediately obvious why this works (
f(malita)
2014/08/20 15:47:47
Done.
| |
| 136 | |
| 137 SkASSERT(NULL != fRuns && !fRuns->empty()); | |
| 138 fRuns->back().count += count; | |
| 139 | |
| 140 if (!fDeferredBounds) { | |
| 141 if (NULL != bounds) { | |
| 142 fBounds.join(*bounds); | |
| 143 } else { | |
| 144 fDeferredBounds = true; | |
| 145 } | |
| 146 } | |
| 147 } | |
| 148 | |
| 149 SkTextBlobBuilder::RunBuffer SkTextBlobBuilder::currentRunBuffer() { | |
| 150 SkASSERT(NULL != fRuns && !fRuns->empty()); | |
| 151 | |
| 152 RunBuffer buffer; | |
| 153 buffer.glyphs = fGlyphBuffer.isEmpty() | |
| 154 ? NULL | |
| 155 : fGlyphBuffer.begin() + fRuns->back().glyphStart; | |
| 156 buffer.pos = fPosBuffer.isEmpty() | |
| 157 ? NULL | |
| 158 : fPosBuffer.begin() + fRuns->back().posStart; | |
| 159 | |
| 160 return buffer; | |
| 161 } | |
| 162 | |
| 163 uint16_t* SkTextBlobBuilder::allocRun(const SkPaint& font, size_t count, SkPoint offset, | |
| 164 const SkRect* bounds) { | |
| 165 alloc_internal(font, SkTextBlob::kDefault_Positioning, count, offset, bounds ); | |
| 166 | |
| 167 return fGlyphBuffer.begin() + fRuns->back().glyphStart; | |
| 168 } | |
| 169 | |
| 170 SkTextBlobBuilder::RunBuffer SkTextBlobBuilder::allocRun(const SkPaint& font, si ze_t count, | |
| 171 SkScalar yOffset, const SkRect* bounds) { | |
|
robertphillips
2014/08/20 14:52:18
this->allocInternal ?
f(malita)
2014/08/20 15:47:47
Done.
| |
| 172 alloc_internal(font, SkTextBlob::kHorizontal_Positioning, count, SkPoint::Ma ke(0, yOffset), | |
| 173 bounds); | |
| 174 | |
|
robertphillips
2014/08/20 14:52:18
this-> ?
f(malita)
2014/08/20 15:47:47
Done.
| |
| 175 return currentRunBuffer(); | |
| 176 } | |
| 177 | |
| 178 SkTextBlobBuilder::RunBuffer SkTextBlobBuilder::allocRun(const SkPaint& font, si ze_t count, | |
| 179 const SkRect *bounds) { | |
| 180 alloc_internal(font, SkTextBlob::kFull_Positioning, count, SkPoint::Make(0, 0), bounds); | |
| 181 | |
|
robertphillips
2014/08/20 14:52:18
this-> ?
f(malita)
2014/08/20 15:47:47
Done.
| |
| 182 return currentRunBuffer(); | |
| 183 } | |
| 184 | |
| 185 const SkTextBlob* SkTextBlobBuilder::build() { | |
| 186 const SkTextBlob* leBlob; | |
|
jbroman
2014/08/20 15:10:32
nit: what does "le blob" mean? Why not "blob"?
f(malita)
2014/08/20 15:47:47
Done.
| |
| 187 | |
| 188 if (fGlyphBuffer.count() > 0) { | |
| 189 // we have some glyphs, construct a real blob | |
| 190 SkASSERT(NULL != fRuns && !fRuns->empty()); | |
| 191 | |
| 192 this->updateDeferredBounds(); | |
| 193 | |
| 194 // ownership of all buffers is transferred to the blob | |
| 195 leBlob = SkNEW_ARGS(SkTextBlob, (fGlyphBuffer.detach(), | |
| 196 fPosBuffer.detach(), | |
| 197 fRuns, | |
| 198 fBounds)); | |
| 199 fRuns = NULL; | |
| 200 fBounds.setEmpty(); | |
| 201 } else { | |
| 202 // empty blob | |
| 203 SkASSERT(NULL == fRuns || fRuns->empty()); | |
| 204 SkASSERT(fBounds.isEmpty()); | |
| 205 | |
| 206 leBlob = SkNEW_ARGS(SkTextBlob, (NULL, NULL, NULL, SkRect::MakeEmpty())) ; | |
| 207 } | |
| 208 | |
| 209 return leBlob; | |
| 210 } | |
| 211 | |
| OLD | NEW |