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 |