Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(233)

Side by Side Diff: src/gpu/GrStencilAndCoverTextContext.cpp

Issue 400713003: Add a GrPathRange class (Closed) Base URL: https://skia.googlesource.com/skia.git@clupload-ispath
Patch Set: Created 6 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 /* 1 /*
2 * Copyright 2014 Google Inc. 2 * Copyright 2014 Google Inc.
3 * 3 *
4 * Use of this source code is governed by a BSD-style license that can be 4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file. 5 * found in the LICENSE file.
6 */ 6 */
7 7
8 #include "GrStencilAndCoverTextContext.h" 8 #include "GrStencilAndCoverTextContext.h"
9 #include "GrDrawTarget.h" 9 #include "GrDrawTarget.h"
10 #include "GrFontScaler.h"
11 #include "GrGpu.h" 10 #include "GrGpu.h"
12 #include "GrPath.h" 11 #include "GrPath.h"
13 #include "GrTextStrike.h" 12 #include "GrPathRange.h"
14 #include "GrTextStrike_impl.h"
15 #include "SkAutoKern.h" 13 #include "SkAutoKern.h"
16 #include "SkDraw.h" 14 #include "SkDraw.h"
17 #include "SkDrawProcs.h" 15 #include "SkDrawProcs.h"
18 #include "SkGlyphCache.h" 16 #include "SkGlyphCache.h"
19 #include "SkGpuDevice.h" 17 #include "SkGpuDevice.h"
20 #include "SkPath.h" 18 #include "SkPath.h"
21 #include "SkTextMapStateProc.h" 19 #include "SkTextMapStateProc.h"
22 20
23 static const int kMaxReservedGlyphs = 64; 21 class GrStencilAndCoverTextContext::GlyphPathRange : public GrCacheable {
22 static const int kMaxGlyphCount = 1 << 16; // Glyph IDs are uint16_t's
23 static const int kGlyphGroupSize = 16; // Glyphs get tracked in groups of 16
24 static const bool kIsWrapped = false;
25
26 public:
27 static GlyphPathRange* Create(GrContext* context,
28 SkGlyphCache* cache,
29 const SkStrokeRec& stroke) {
30 static const GrResourceKey::ResourceType gGlyphPathRangeType =
31 GrResourceKey::GenerateResourceType();
bsalomon 2014/07/17 17:27:28 I think the type should come from GrPathRange itse
Chris Dalton 2014/07/17 18:15:19 Acknowledged.
32 static const GrCacheID::Domain gGlyphPathRangeDomain = GrCacheID::Genera teDomain();
33
34 GrCacheID::Key key;
35 key.fData32[0] = cache->getDescriptor().getChecksum();
36 key.fData32[1] = cache->getScalerContext()->getTypeface()->uniqueID();
37 key.fData64[1] = GrPath::ComputeStrokeKey(stroke);
38
39 GrResourceKey resourceKey(GrCacheID(gGlyphPathRangeDomain, key), gGlyphP athRangeType, 0);
40 SkAutoTUnref<GlyphPathRange> glyphs(
41 static_cast<GlyphPathRange*>(context->findAndRefCachedResource(resou rceKey)));
42
43 if (NULL == glyphs ||
44 !glyphs->fDesc->equals(cache->getDescriptor() /*checksum collision*/ )) {
45 GrGpu* const gpu = context->getGpu();
46 // We reserve a range of kMaxGlyphCount paths because of fallbacks f onts. We
47 // can't know exactly how many glyphs we might need without preloadi ng every
48 // fallback, which we don't want to do at this point.
49 SkAutoTUnref<GrPathRange> pathRange(gpu->createPathRange(kMaxGlyphCo unt, stroke));
50 glyphs.reset(SkNEW_ARGS(GlyphPathRange, (cache->getDescriptor(), pat hRange)));
51 context->addResourceToCache(resourceKey, glyphs);
52 }
53
54 return glyphs.detach();
55 }
56
57 const GrPathRange* pathRange() const { return fPathRange.get(); }
58
59 void preloadGlyph(uint16_t glyphID, SkGlyphCache* cache) {
60 const uint16_t groupIndex = glyphID / kGlyphGroupSize;
61 const uint16_t groupByte = groupIndex >> 3;
62 const uint8_t groupBit = 1 << (groupIndex & 7);
63
64 const bool hasGlyph = fLoadedGlyphs[groupByte] & groupBit;
65 if (hasGlyph) {
66 return;
67 }
68
69 // We track which glyphs are loaded in groups of kGlyphGroupSize. To
70 // mark a glyph loaded we need to load the entire group.
71 const uint16_t groupFirstID = groupIndex * kGlyphGroupSize;
72 const uint16_t groupLastID = groupFirstID + kGlyphGroupSize - 1;
73 SkPath skPath;
74 for (int id = groupFirstID; id <= groupLastID; ++id) {
75 const SkGlyph& skGlyph = cache->getGlyphIDMetrics(id);
76 if (const SkPath* skPath = cache->findPath(skGlyph)) {
77 fPathRange->initAt(id, *skPath);
78 } // GrGpu::drawPaths will silently ignore undefined paths.
79 }
80
81 fLoadedGlyphs[groupByte] |= groupBit;
82 this->didChangeGpuMemorySize();
83 }
84
85 // GrCacheable overrides
86 virtual size_t gpuMemorySize() const SK_OVERRIDE { return fPathRange->gpuMem orySize(); }
87 virtual bool isValidOnGpu() const SK_OVERRIDE { return fPathRange->isValidOn Gpu(); }
88
89 private:
90 GlyphPathRange(const SkDescriptor& desc, GrPathRange* pathRange)
91 : fDesc(desc.copy())
92 , fPathRange(pathRange) {
93 memset(fLoadedGlyphs, 0, sizeof(fLoadedGlyphs));
94 }
95
96 ~GlyphPathRange() {
97 SkDescriptor::Free(fDesc);
98 }
99
100 static const int kMaxGroupCount = (kMaxGlyphCount + (kGlyphGroupSize - 1)) / kGlyphGroupSize;
101 SkDescriptor* const fDesc;
102 uint8_t fLoadedGlyphs[(kMaxGroupCount + 7) >> 3]; // One bit per glyph group
103 SkRefPtr<GrPathRange> fPathRange;
104
105 typedef GrCacheable INHERITED;
106 };
107
24 108
25 GrStencilAndCoverTextContext::GrStencilAndCoverTextContext( 109 GrStencilAndCoverTextContext::GrStencilAndCoverTextContext(
26 GrContext* context, const SkDeviceProperties& properties) 110 GrContext* context, const SkDeviceProperties& properties)
27 : GrTextContext(context, properties) 111 : GrTextContext(context, properties)
28 , fStroke(SkStrokeRec::kFill_InitStyle) { 112 , fStroke(SkStrokeRec::kFill_InitStyle)
113 , fPendingGlyphCount(0) {
29 } 114 }
30 115
31 GrStencilAndCoverTextContext::~GrStencilAndCoverTextContext() { 116 GrStencilAndCoverTextContext::~GrStencilAndCoverTextContext() {
32 } 117 }
33 118
34 void GrStencilAndCoverTextContext::drawText(const GrPaint& paint, 119 void GrStencilAndCoverTextContext::drawText(const GrPaint& paint,
35 const SkPaint& skPaint, 120 const SkPaint& skPaint,
36 const char text[], 121 const char text[],
37 size_t byteLength, 122 size_t byteLength,
38 SkScalar x, SkScalar y) { 123 SkScalar x, SkScalar y) {
(...skipping 27 matching lines...) Expand all
66 if (fNeedsDeviceSpaceGlyphs) { 151 if (fNeedsDeviceSpaceGlyphs) {
67 SkPoint loc; 152 SkPoint loc;
68 fGlyphTransform.mapXY(x, y, &loc); 153 fGlyphTransform.mapXY(x, y, &loc);
69 x = loc.fX; 154 x = loc.fX;
70 y = loc.fY; 155 y = loc.fY;
71 glyphCacheTransform = &fGlyphTransform; 156 glyphCacheTransform = &fGlyphTransform;
72 } 157 }
73 158
74 SkDrawCacheProc glyphCacheProc = fSkPaint.getDrawCacheProc(); 159 SkDrawCacheProc glyphCacheProc = fSkPaint.getDrawCacheProc();
75 SkAutoGlyphCache autoCache(fSkPaint, &fDeviceProperties, glyphCacheTransform ); 160 SkAutoGlyphCache autoCache(fSkPaint, &fDeviceProperties, glyphCacheTransform );
76 SkGlyphCache* cache = autoCache.getCache(); 161 fGlyphCache = autoCache.getCache();
77 GrFontScaler* scaler = GetGrFontScaler(cache); 162 fGlyphs = GlyphPathRange::Create(fContext, fGlyphCache, fStroke);
78 GrTextStrike* strike =
79 fContext->getFontCache()->getStrike(scaler, true);
80 163
81 const char* stop = text + byteLength; 164 const char* stop = text + byteLength;
82 165
83 // Measure first if needed. 166 // Measure first if needed.
84 if (fSkPaint.getTextAlign() != SkPaint::kLeft_Align) { 167 if (fSkPaint.getTextAlign() != SkPaint::kLeft_Align) {
85 SkFixed stopX = 0; 168 SkFixed stopX = 0;
86 SkFixed stopY = 0; 169 SkFixed stopY = 0;
87 170
88 const char* textPtr = text; 171 const char* textPtr = text;
89 while (textPtr < stop) { 172 while (textPtr < stop) {
90 // We don't need x, y here, since all subpixel variants will have th e 173 // We don't need x, y here, since all subpixel variants will have th e
91 // same advance. 174 // same advance.
92 const SkGlyph& glyph = glyphCacheProc(cache, &textPtr, 0, 0); 175 const SkGlyph& glyph = glyphCacheProc(fGlyphCache, &textPtr, 0, 0);
93 176
94 stopX += glyph.fAdvanceX; 177 stopX += glyph.fAdvanceX;
95 stopY += glyph.fAdvanceY; 178 stopY += glyph.fAdvanceY;
96 } 179 }
97 SkASSERT(textPtr == stop); 180 SkASSERT(textPtr == stop);
98 181
99 SkScalar alignX = SkFixedToScalar(stopX) * fTextRatio; 182 SkScalar alignX = SkFixedToScalar(stopX) * fTextRatio;
100 SkScalar alignY = SkFixedToScalar(stopY) * fTextRatio; 183 SkScalar alignY = SkFixedToScalar(stopY) * fTextRatio;
101 184
102 if (fSkPaint.getTextAlign() == SkPaint::kCenter_Align) { 185 if (fSkPaint.getTextAlign() == SkPaint::kCenter_Align) {
103 alignX = SkScalarHalf(alignX); 186 alignX = SkScalarHalf(alignX);
104 alignY = SkScalarHalf(alignY); 187 alignY = SkScalarHalf(alignY);
105 } 188 }
106 189
107 x -= alignX; 190 x -= alignX;
108 y -= alignY; 191 y -= alignY;
109 } 192 }
110 193
111 SkAutoKern autokern; 194 SkAutoKern autokern;
112 195
113 SkFixed fixedSizeRatio = SkScalarToFixed(fTextRatio); 196 SkFixed fixedSizeRatio = SkScalarToFixed(fTextRatio);
114 197
115 SkFixed fx = SkScalarToFixed(x); 198 SkFixed fx = SkScalarToFixed(x);
116 SkFixed fy = SkScalarToFixed(y); 199 SkFixed fy = SkScalarToFixed(y);
117 while (text < stop) { 200 while (text < stop) {
118 const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0); 201 const SkGlyph& glyph = glyphCacheProc(fGlyphCache, &text, 0, 0);
119 fx += SkFixedMul_portable(autokern.adjust(glyph), fixedSizeRatio); 202 fx += SkFixedMul_portable(autokern.adjust(glyph), fixedSizeRatio);
120 if (glyph.fWidth) { 203 if (glyph.fWidth) {
121 this->appendGlyph(GrGlyph::Pack(glyph.getGlyphID(), 204 this->appendGlyph(glyph.getGlyphID(), SkFixedToScalar(fx), SkFixedTo Scalar(fy));
122 glyph.getSubXFixed(),
123 glyph.getSubYFixed()),
124 SkPoint::Make(
125 SkFixedToScalar(fx),
126 SkFixedToScalar(fy)),
127 strike,
128 scaler);
129 } 205 }
130 206
131 fx += SkFixedMul_portable(glyph.fAdvanceX, fixedSizeRatio); 207 fx += SkFixedMul_portable(glyph.fAdvanceX, fixedSizeRatio);
132 fy += SkFixedMul_portable(glyph.fAdvanceY, fixedSizeRatio); 208 fy += SkFixedMul_portable(glyph.fAdvanceY, fixedSizeRatio);
133 } 209 }
134 210
135 this->finish(); 211 this->finish();
136 } 212 }
137 213
138 void GrStencilAndCoverTextContext::drawPosText(const GrPaint& paint, 214 void GrStencilAndCoverTextContext::drawPosText(const GrPaint& paint,
(...skipping 18 matching lines...) Expand all
157 // glyphs. That already uses glyph cache without device transforms. Device 233 // glyphs. That already uses glyph cache without device transforms. Device
158 // transform is not part of SkPaint::measureText API, and thus we use the 234 // transform is not part of SkPaint::measureText API, and thus we use the
159 // same glyphs as what were measured. 235 // same glyphs as what were measured.
160 fGlyphTransform.reset(); 236 fGlyphTransform.reset();
161 237
162 this->init(paint, skPaint, byteLength); 238 this->init(paint, skPaint, byteLength);
163 239
164 SkDrawCacheProc glyphCacheProc = fSkPaint.getDrawCacheProc(); 240 SkDrawCacheProc glyphCacheProc = fSkPaint.getDrawCacheProc();
165 241
166 SkAutoGlyphCache autoCache(fSkPaint, &fDeviceProperties, NULL); 242 SkAutoGlyphCache autoCache(fSkPaint, &fDeviceProperties, NULL);
167 SkGlyphCache* cache = autoCache.getCache(); 243 fGlyphCache = autoCache.getCache();
168 GrFontScaler* scaler = GetGrFontScaler(cache); 244 fGlyphs = GlyphPathRange::Create(fContext, fGlyphCache, fStroke);
169 GrTextStrike* strike =
170 fContext->getFontCache()->getStrike(scaler, true);
171 245
172 const char* stop = text + byteLength; 246 const char* stop = text + byteLength;
173 SkTextAlignProcScalar alignProc(fSkPaint.getTextAlign()); 247 SkTextAlignProcScalar alignProc(fSkPaint.getTextAlign());
174 SkTextMapStateProc tmsProc(SkMatrix::I(), constY, scalarsPerPosition); 248 SkTextMapStateProc tmsProc(SkMatrix::I(), constY, scalarsPerPosition);
175 249
176 if (SkPaint::kLeft_Align == fSkPaint.getTextAlign()) { 250 if (SkPaint::kLeft_Align == fSkPaint.getTextAlign()) {
177 while (text < stop) { 251 while (text < stop) {
178 SkPoint loc; 252 SkPoint loc;
179 tmsProc(pos, &loc); 253 tmsProc(pos, &loc);
180 const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0); 254 const SkGlyph& glyph = glyphCacheProc(fGlyphCache, &text, 0, 0);
181 if (glyph.fWidth) { 255 if (glyph.fWidth) {
182 this->appendGlyph(GrGlyph::Pack(glyph.getGlyphID(), 256 this->appendGlyph(glyph.getGlyphID(), loc.x(), loc.y());
183 glyph.getSubXFixed(),
184 glyph.getSubYFixed()),
185 loc,
186 strike,
187 scaler);
188 } 257 }
189 pos += scalarsPerPosition; 258 pos += scalarsPerPosition;
190 } 259 }
191 } else { 260 } else {
192 while (text < stop) { 261 while (text < stop) {
193 const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0); 262 const SkGlyph& glyph = glyphCacheProc(fGlyphCache, &text, 0, 0);
194 if (glyph.fWidth) { 263 if (glyph.fWidth) {
195 SkPoint tmsLoc; 264 SkPoint tmsLoc;
196 tmsProc(pos, &tmsLoc); 265 tmsProc(pos, &tmsLoc);
197 SkPoint loc; 266 SkPoint loc;
198 alignProc(tmsLoc, glyph, &loc); 267 alignProc(tmsLoc, glyph, &loc);
199 268
200 this->appendGlyph(GrGlyph::Pack(glyph.getGlyphID(), 269 this->appendGlyph(glyph.getGlyphID(), loc.x(), loc.y());
201 glyph.getSubXFixed(),
202 glyph.getSubYFixed()),
203 loc,
204 strike,
205 scaler);
206
207 } 270 }
208 pos += scalarsPerPosition; 271 pos += scalarsPerPosition;
209 } 272 }
210 } 273 }
211 274
212 this->finish(); 275 this->finish();
213 } 276 }
214 277
215 bool GrStencilAndCoverTextContext::canDraw(const SkPaint& paint) { 278 bool GrStencilAndCoverTextContext::canDraw(const SkPaint& paint) {
216 if (paint.getRasterizer()) { 279 if (paint.getRasterizer()) {
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after
298 GR_STATIC_CONST_SAME_STENCIL(kStencilPass, 361 GR_STATIC_CONST_SAME_STENCIL(kStencilPass,
299 kZero_StencilOp, 362 kZero_StencilOp,
300 kZero_StencilOp, 363 kZero_StencilOp,
301 kNotEqual_StencilFunc, 364 kNotEqual_StencilFunc,
302 0xffff, 365 0xffff,
303 0x0000, 366 0x0000,
304 0xffff); 367 0xffff);
305 368
306 *fDrawTarget->drawState()->stencil() = kStencilPass; 369 *fDrawTarget->drawState()->stencil() = kStencilPass;
307 370
308 size_t reserveAmount; 371 SkASSERT(0 == fPendingGlyphCount);
309 switch (skPaint.getTextEncoding()) {
310 default:
311 SkASSERT(false);
312 case SkPaint::kUTF8_TextEncoding:
313 reserveAmount = textByteLength;
314 break;
315 case SkPaint::kUTF16_TextEncoding:
316 reserveAmount = textByteLength / 2;
317 break;
318 case SkPaint::kUTF32_TextEncoding:
319 case SkPaint::kGlyphID_TextEncoding:
320 reserveAmount = textByteLength / 4;
321 break;
322 }
323 fPaths.setReserve(reserveAmount);
324 fTransforms.setReserve(reserveAmount);
325 } 372 }
326 373
327 inline void GrStencilAndCoverTextContext::appendGlyph(GrGlyph::PackedID glyphID, 374 inline void GrStencilAndCoverTextContext::appendGlyph(uint16_t glyphID, float x, float y) {
328 const SkPoint& pos, 375 if (fPendingGlyphCount >= kGlyphBufferSize) {
329 GrTextStrike* strike, 376 this->flush();
330 GrFontScaler* scaler) { 377 SkASSERT(0 == fPendingGlyphCount);
331 GrGlyph* glyph = strike->getGlyph(glyphID, scaler); 378 }
332 if (NULL == glyph || glyph->fBounds.isEmpty()) { 379
380 fGlyphs->preloadGlyph(glyphID, fGlyphCache);
381
382 fIndexBuffer[fPendingGlyphCount] = glyphID;
383 fTransformBuffer[6 * fPendingGlyphCount + 0] = fTextRatio;
384 fTransformBuffer[6 * fPendingGlyphCount + 1] = 0;
385 fTransformBuffer[6 * fPendingGlyphCount + 2] = x;
386 fTransformBuffer[6 * fPendingGlyphCount + 3] = 0;
387 fTransformBuffer[6 * fPendingGlyphCount + 4] = fTextRatio;
388 fTransformBuffer[6 * fPendingGlyphCount + 5] = y;
389
390 ++fPendingGlyphCount;
391 }
392
393 void GrStencilAndCoverTextContext::flush() {
394 if (0 == fPendingGlyphCount) {
333 return; 395 return;
334 } 396 }
335 397
336 if (scaler->getGlyphPath(glyph->glyphID(), &fTmpPath)) { 398 fDrawTarget->drawPaths(fGlyphs->pathRange(), fIndexBuffer, fPendingGlyphCoun t,
337 if (!fTmpPath.isEmpty()) { 399 fTransformBuffer, kAffine_GrTransformFormat,
338 *fPaths.append() = fContext->createPath(fTmpPath, fStroke); 400 SkPath::kWinding_FillType);
339 SkMatrix* t = fTransforms.append(); 401
340 t->setTranslate(pos.fX, pos.fY); 402 fPendingGlyphCount = 0;
341 t->preScale(fTextRatio, fTextRatio);
342 }
343 }
344 } 403 }
345 404
346 void GrStencilAndCoverTextContext::finish() { 405 void GrStencilAndCoverTextContext::finish() {
347 if (fPaths.count() > 0) { 406 this->flush();
348 fDrawTarget->drawPaths(static_cast<size_t>(fPaths.count()),
349 fPaths.begin(), fTransforms.begin(),
350 SkPath::kWinding_FillType, fStroke.getStyle());
351 407
352 for (int i = 0; i < fPaths.count(); ++i) { 408 SkSafeUnref(fGlyphs);
353 fPaths[i]->unref(); 409 fGlyphs = NULL;
354 } 410 fGlyphCache = NULL;
355 if (fPaths.count() > kMaxReservedGlyphs) {
356 fPaths.reset();
357 fTransforms.reset();
358 } else {
359 fPaths.rewind();
360 fTransforms.rewind();
361 }
362 }
363 fTmpPath.reset();
364 411
365 fDrawTarget->drawState()->stencil()->setDisabled(); 412 fDrawTarget->drawState()->stencil()->setDisabled();
366 fStateRestore.set(NULL); 413 fStateRestore.set(NULL);
367 if (fNeedsDeviceSpaceGlyphs) { 414 if (fNeedsDeviceSpaceGlyphs) {
368 fContext->setMatrix(fGlyphTransform); 415 fContext->setMatrix(fGlyphTransform);
369 } 416 }
370 GrTextContext::finish(); 417 GrTextContext::finish();
371 } 418 }
372 419
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698