OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2013 Google Inc. | 2 * Copyright 2015 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 #include "GrBitmapTextContext.h" | 7 #include "GrAtlasTextContext.h" |
8 | 8 |
9 #include "GrAtlas.h" | 9 #include "GrAtlas.h" |
10 #include "GrBatch.h" | 10 #include "GrBatch.h" |
11 #include "GrBatchFontCache.h" | 11 #include "GrBatchFontCache.h" |
12 #include "GrBatchTarget.h" | 12 #include "GrBatchTarget.h" |
13 #include "GrDefaultGeoProcFactory.h" | 13 #include "GrDefaultGeoProcFactory.h" |
14 #include "GrDrawTarget.h" | 14 #include "GrDrawTarget.h" |
15 #include "GrFontCache.h" | |
16 #include "GrFontScaler.h" | 15 #include "GrFontScaler.h" |
17 #include "GrIndexBuffer.h" | 16 #include "GrIndexBuffer.h" |
18 #include "GrStrokeInfo.h" | 17 #include "GrStrokeInfo.h" |
19 #include "GrTexturePriv.h" | 18 #include "GrTexturePriv.h" |
20 | 19 |
21 #include "SkAutoKern.h" | 20 #include "SkAutoKern.h" |
22 #include "SkColorPriv.h" | 21 #include "SkColorPriv.h" |
23 #include "SkDraw.h" | 22 #include "SkDraw.h" |
24 #include "SkDrawFilter.h" | 23 #include "SkDrawFilter.h" |
25 #include "SkDrawProcs.h" | 24 #include "SkDrawProcs.h" |
26 #include "SkGlyphCache.h" | 25 #include "SkGlyphCache.h" |
27 #include "SkGpuDevice.h" | 26 #include "SkGpuDevice.h" |
28 #include "SkGr.h" | 27 #include "SkGr.h" |
29 #include "SkPath.h" | 28 #include "SkPath.h" |
30 #include "SkRTConf.h" | 29 #include "SkRTConf.h" |
31 #include "SkStrokeRec.h" | 30 #include "SkStrokeRec.h" |
32 #include "SkTextBlob.h" | 31 #include "SkTextBlob.h" |
33 #include "SkTextMapStateProc.h" | 32 #include "SkTextMapStateProc.h" |
34 | 33 |
35 #include "effects/GrBitmapTextGeoProc.h" | 34 #include "effects/GrBitmapTextGeoProc.h" |
36 #include "effects/GrSimpleTextureEffect.h" | 35 #include "effects/GrSimpleTextureEffect.h" |
37 | 36 |
38 SK_CONF_DECLARE(bool, c_DumpFontCache, "gpu.dumpFontCache", false, | |
39 "Dump the contents of the font cache before every purge."); | |
40 | |
41 namespace { | 37 namespace { |
42 static const size_t kLCDTextVASize = sizeof(SkPoint) + sizeof(SkIPoint16); | 38 static const size_t kLCDTextVASize = sizeof(SkPoint) + sizeof(SkIPoint16); |
43 | 39 |
44 // position + local coord | 40 // position + local coord |
45 static const size_t kColorTextVASize = sizeof(SkPoint) + sizeof(SkIPoint16); | 41 static const size_t kColorTextVASize = sizeof(SkPoint) + sizeof(SkIPoint16); |
46 | 42 |
47 static const size_t kGrayTextVASize = sizeof(SkPoint) + sizeof(GrColor) + sizeof
(SkIPoint16); | 43 static const size_t kGrayTextVASize = sizeof(SkPoint) + sizeof(GrColor) + sizeof
(SkIPoint16); |
48 | 44 |
49 static const int kVerticesPerGlyph = 4; | 45 static const int kVerticesPerGlyph = 4; |
50 static const int kIndicesPerGlyph = 6; | 46 static const int kIndicesPerGlyph = 6; |
| 47 |
| 48 static size_t get_vertex_stride(GrMaskFormat maskFormat) { |
| 49 switch (maskFormat) { |
| 50 case kA8_GrMaskFormat: |
| 51 return kGrayTextVASize; |
| 52 case kARGB_GrMaskFormat: |
| 53 return kColorTextVASize; |
| 54 default: |
| 55 return kLCDTextVASize; |
| 56 } |
| 57 } |
| 58 |
51 }; | 59 }; |
52 | 60 |
53 // TODO | 61 // TODO |
54 // More tests | 62 // More tests |
55 // move to SkCache | 63 // move to SkCache |
56 // handle textblobs where the whole run is larger than the cache size | 64 // handle textblobs where the whole run is larger than the cache size |
57 // TODO implement micro speedy hash map for fast refing of glyphs | 65 // TODO implement micro speedy hash map for fast refing of glyphs |
58 | 66 |
59 GrBitmapTextContextB::GrBitmapTextContextB(GrContext* context, | 67 GrBitmapTextContextB::GrBitmapTextContextB(GrContext* context, |
60 SkGpuDevice* gpuDevice, | 68 SkGpuDevice* gpuDevice, |
(...skipping 347 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
408 | 416 |
409 fCurrStrike = NULL; | 417 fCurrStrike = NULL; |
410 SkDrawCacheProc glyphCacheProc = skPaint.getDrawCacheProc(); | 418 SkDrawCacheProc glyphCacheProc = skPaint.getDrawCacheProc(); |
411 | 419 |
412 // Get GrFontScaler from cache | 420 // Get GrFontScaler from cache |
413 GrFontScaler* fontScaler = GetGrFontScaler(cache); | 421 GrFontScaler* fontScaler = GetGrFontScaler(cache); |
414 | 422 |
415 const char* stop = text + byteLength; | 423 const char* stop = text + byteLength; |
416 SkTextAlignProc alignProc(skPaint.getTextAlign()); | 424 SkTextAlignProc alignProc(skPaint.getTextAlign()); |
417 SkTextMapStateProc tmsProc(viewMatrix, offset, scalarsPerPosition); | 425 SkTextMapStateProc tmsProc(viewMatrix, offset, scalarsPerPosition); |
418 SkScalar halfSampleX = 0, halfSampleY = 0; | |
419 | 426 |
420 if (cache->isSubpixel()) { | 427 if (cache->isSubpixel()) { |
421 // maybe we should skip the rounding if linearText is set | 428 // maybe we should skip the rounding if linearText is set |
422 SkAxisAlignment baseline = SkComputeAxisAlignmentForHText(viewMatrix); | 429 SkAxisAlignment baseline = SkComputeAxisAlignmentForHText(viewMatrix); |
423 | 430 |
424 SkFixed fxMask = ~0; | 431 SkFixed fxMask = ~0; |
425 SkFixed fyMask = ~0; | 432 SkFixed fyMask = ~0; |
| 433 SkScalar halfSampleX = SkFixedToScalar(SkGlyph::kSubpixelRound); |
| 434 SkScalar halfSampleY = SkFixedToScalar(SkGlyph::kSubpixelRound); |
426 if (kX_SkAxisAlignment == baseline) { | 435 if (kX_SkAxisAlignment == baseline) { |
427 fyMask = 0; | 436 fyMask = 0; |
428 halfSampleY = SK_ScalarHalf; | 437 halfSampleY = SK_ScalarHalf; |
429 } else if (kY_SkAxisAlignment == baseline) { | 438 } else if (kY_SkAxisAlignment == baseline) { |
430 fxMask = 0; | 439 fxMask = 0; |
431 halfSampleX = SK_ScalarHalf; | 440 halfSampleX = SK_ScalarHalf; |
432 } | 441 } |
433 | 442 |
434 if (SkPaint::kLeft_Align == skPaint.getTextAlign()) { | 443 if (SkPaint::kLeft_Align == skPaint.getTextAlign()) { |
435 while (text < stop) { | 444 while (text < stop) { |
(...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
543 Sk48Dot16FloorToInt(fy), | 552 Sk48Dot16FloorToInt(fy), |
544 fontScaler, | 553 fontScaler, |
545 clipRect); | 554 clipRect); |
546 } | 555 } |
547 pos += scalarsPerPosition; | 556 pos += scalarsPerPosition; |
548 } | 557 } |
549 } | 558 } |
550 } | 559 } |
551 } | 560 } |
552 | 561 |
553 static size_t get_vertex_stride(GrMaskFormat maskFormat) { | |
554 switch (maskFormat) { | |
555 case kA8_GrMaskFormat: | |
556 return kGrayTextVASize; | |
557 case kARGB_GrMaskFormat: | |
558 return kColorTextVASize; | |
559 default: | |
560 return kLCDTextVASize; | |
561 } | |
562 } | |
563 | |
564 void GrBitmapTextContextB::appendGlyph(BitmapTextBlob* blob, int runIndex, GrGly
ph::PackedID packed, | 562 void GrBitmapTextContextB::appendGlyph(BitmapTextBlob* blob, int runIndex, GrGly
ph::PackedID packed, |
565 int vx, int vy, GrFontScaler* scaler, | 563 int vx, int vy, GrFontScaler* scaler, |
566 const SkIRect& clipRect) { | 564 const SkIRect& clipRect) { |
567 if (NULL == fCurrStrike) { | 565 if (NULL == fCurrStrike) { |
568 fCurrStrike = fContext->getBatchFontCache()->getStrike(scaler); | 566 fCurrStrike = fContext->getBatchFontCache()->getStrike(scaler); |
569 } | 567 } |
570 | 568 |
571 GrGlyph* glyph = fCurrStrike->getGlyph(packed, scaler); | 569 GrGlyph* glyph = fCurrStrike->getGlyph(packed, scaler); |
572 if (NULL == glyph || glyph->fBounds.isEmpty()) { | 570 if (NULL == glyph || glyph->fBounds.isEmpty()) { |
573 return; | 571 return; |
(...skipping 474 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1048 for (int i = 0; i < blob->fBigGlyphs.count(); i++) { | 1046 for (int i = 0; i < blob->fBigGlyphs.count(); i++) { |
1049 BitmapTextBlob::BigGlyph& bigGlyph = blob->fBigGlyphs[i]; | 1047 BitmapTextBlob::BigGlyph& bigGlyph = blob->fBigGlyphs[i]; |
1050 SkMatrix translate; | 1048 SkMatrix translate; |
1051 translate.setTranslate(SkIntToScalar(bigGlyph.fVx), SkIntToScalar(bigGly
ph.fVy)); | 1049 translate.setTranslate(SkIntToScalar(bigGlyph.fVx), SkIntToScalar(bigGly
ph.fVy)); |
1052 SkPath tmpPath(bigGlyph.fPath); | 1050 SkPath tmpPath(bigGlyph.fPath); |
1053 tmpPath.transform(translate); | 1051 tmpPath.transform(translate); |
1054 GrStrokeInfo strokeInfo(SkStrokeRec::kFill_InitStyle); | 1052 GrStrokeInfo strokeInfo(SkStrokeRec::kFill_InitStyle); |
1055 fContext->drawPath(rt, clip, paint, SkMatrix::I(), tmpPath, strokeInfo); | 1053 fContext->drawPath(rt, clip, paint, SkMatrix::I(), tmpPath, strokeInfo); |
1056 } | 1054 } |
1057 } | 1055 } |
1058 | |
1059 GrBitmapTextContext::GrBitmapTextContext(GrContext* context, | |
1060 SkGpuDevice* gpuDevice, | |
1061 const SkDeviceProperties& properties) | |
1062 : GrTextContext(context, gpuDevice, properties) { | |
1063 fStrike = NULL; | |
1064 | |
1065 fCurrTexture = NULL; | |
1066 fEffectTextureUniqueID = SK_InvalidUniqueID; | |
1067 | |
1068 fVertices = NULL; | |
1069 fCurrVertex = 0; | |
1070 fAllocVertexCount = 0; | |
1071 fTotalVertexCount = 0; | |
1072 | |
1073 fVertexBounds.setLargestInverted(); | |
1074 } | |
1075 | |
1076 GrBitmapTextContext* GrBitmapTextContext::Create(GrContext* context, | |
1077 SkGpuDevice* gpuDevice, | |
1078 const SkDeviceProperties& props
) { | |
1079 return SkNEW_ARGS(GrBitmapTextContext, (context, gpuDevice, props)); | |
1080 } | |
1081 | |
1082 bool GrBitmapTextContext::canDraw(const GrRenderTarget* rt, | |
1083 const GrClip& clip, | |
1084 const GrPaint& paint, | |
1085 const SkPaint& skPaint, | |
1086 const SkMatrix& viewMatrix) { | |
1087 return !SkDraw::ShouldDrawTextAsPaths(skPaint, viewMatrix); | |
1088 } | |
1089 | |
1090 inline void GrBitmapTextContext::init(GrRenderTarget* rt, const GrClip& clip, | |
1091 const GrPaint& paint, const SkPaint& skPai
nt, | |
1092 const SkIRect& regionClipBounds) { | |
1093 GrTextContext::init(rt, clip, paint, skPaint, regionClipBounds); | |
1094 | |
1095 fStrike = NULL; | |
1096 | |
1097 fCurrTexture = NULL; | |
1098 fCurrVertex = 0; | |
1099 | |
1100 fVertices = NULL; | |
1101 fAllocVertexCount = 0; | |
1102 fTotalVertexCount = 0; | |
1103 } | |
1104 | |
1105 void GrBitmapTextContext::onDrawText(GrRenderTarget* rt, const GrClip& clip, | |
1106 const GrPaint& paint, const SkPaint& skPain
t, | |
1107 const SkMatrix& viewMatrix, | |
1108 const char text[], size_t byteLength, | |
1109 SkScalar x, SkScalar y, const SkIRect& regi
onClipBounds) { | |
1110 SkASSERT(byteLength == 0 || text != NULL); | |
1111 | |
1112 // nothing to draw | |
1113 if (text == NULL || byteLength == 0 /*|| fRC->isEmpty()*/) { | |
1114 return; | |
1115 } | |
1116 | |
1117 this->init(rt, clip, paint, skPaint, regionClipBounds); | |
1118 | |
1119 SkDrawCacheProc glyphCacheProc = fSkPaint.getDrawCacheProc(); | |
1120 | |
1121 SkAutoGlyphCache autoCache(fSkPaint, &fDeviceProperties, &viewMatrix); | |
1122 SkGlyphCache* cache = autoCache.getCache(); | |
1123 GrFontScaler* fontScaler = GetGrFontScaler(cache); | |
1124 | |
1125 // transform our starting point | |
1126 { | |
1127 SkPoint loc; | |
1128 viewMatrix.mapXY(x, y, &loc); | |
1129 x = loc.fX; | |
1130 y = loc.fY; | |
1131 } | |
1132 | |
1133 // need to measure first | |
1134 int numGlyphs; | |
1135 if (fSkPaint.getTextAlign() != SkPaint::kLeft_Align) { | |
1136 SkVector stopVector; | |
1137 numGlyphs = MeasureText(cache, glyphCacheProc, text, byteLength, &stopVe
ctor); | |
1138 | |
1139 SkScalar stopX = stopVector.fX; | |
1140 SkScalar stopY = stopVector.fY; | |
1141 | |
1142 if (fSkPaint.getTextAlign() == SkPaint::kCenter_Align) { | |
1143 stopX = SkScalarHalf(stopX); | |
1144 stopY = SkScalarHalf(stopY); | |
1145 } | |
1146 x -= stopX; | |
1147 y -= stopY; | |
1148 } else { | |
1149 numGlyphs = fSkPaint.textToGlyphs(text, byteLength, NULL); | |
1150 } | |
1151 fTotalVertexCount = kVerticesPerGlyph*numGlyphs; | |
1152 | |
1153 const char* stop = text + byteLength; | |
1154 | |
1155 SkAutoKern autokern; | |
1156 | |
1157 SkFixed fxMask = ~0; | |
1158 SkFixed fyMask = ~0; | |
1159 SkScalar halfSampleX, halfSampleY; | |
1160 if (cache->isSubpixel()) { | |
1161 halfSampleX = halfSampleY = SkFixedToScalar(SkGlyph::kSubpixelRound); | |
1162 SkAxisAlignment baseline = SkComputeAxisAlignmentForHText(viewMatrix); | |
1163 if (kX_SkAxisAlignment == baseline) { | |
1164 fyMask = 0; | |
1165 halfSampleY = SK_ScalarHalf; | |
1166 } else if (kY_SkAxisAlignment == baseline) { | |
1167 fxMask = 0; | |
1168 halfSampleX = SK_ScalarHalf; | |
1169 } | |
1170 } else { | |
1171 halfSampleX = halfSampleY = SK_ScalarHalf; | |
1172 } | |
1173 | |
1174 Sk48Dot16 fx = SkScalarTo48Dot16(x + halfSampleX); | |
1175 Sk48Dot16 fy = SkScalarTo48Dot16(y + halfSampleY); | |
1176 | |
1177 // if we have RGB, then we won't have any SkShaders so no need to use a loca
lmatrix, but for | |
1178 // performance reasons we just invert here instead | |
1179 if (!viewMatrix.invert(&fLocalMatrix)) { | |
1180 SkDebugf("Cannot invert viewmatrix\n"); | |
1181 return; | |
1182 } | |
1183 | |
1184 while (text < stop) { | |
1185 const SkGlyph& glyph = glyphCacheProc(cache, &text, fx & fxMask, fy & fy
Mask); | |
1186 | |
1187 fx += autokern.adjust(glyph); | |
1188 | |
1189 if (glyph.fWidth) { | |
1190 this->appendGlyph(GrGlyph::Pack(glyph.getGlyphID(), | |
1191 glyph.getSubXFixed(), | |
1192 glyph.getSubYFixed(), | |
1193 GrGlyph::kCoverage_MaskStyle), | |
1194 Sk48Dot16FloorToInt(fx), | |
1195 Sk48Dot16FloorToInt(fy), | |
1196 fontScaler); | |
1197 } | |
1198 | |
1199 fx += glyph.fAdvanceX; | |
1200 fy += glyph.fAdvanceY; | |
1201 } | |
1202 | |
1203 this->finish(); | |
1204 } | |
1205 | |
1206 void GrBitmapTextContext::onDrawPosText(GrRenderTarget* rt, const GrClip& clip, | |
1207 const GrPaint& paint, const SkPaint& skP
aint, | |
1208 const SkMatrix& viewMatrix, | |
1209 const char text[], size_t byteLength, | |
1210 const SkScalar pos[], int scalarsPerPosi
tion, | |
1211 const SkPoint& offset, const SkIRect& re
gionClipBounds) { | |
1212 SkASSERT(byteLength == 0 || text != NULL); | |
1213 SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition); | |
1214 | |
1215 // nothing to draw | |
1216 if (text == NULL || byteLength == 0/* || fRC->isEmpty()*/) { | |
1217 return; | |
1218 } | |
1219 | |
1220 this->init(rt, clip, paint, skPaint, regionClipBounds); | |
1221 | |
1222 SkDrawCacheProc glyphCacheProc = fSkPaint.getDrawCacheProc(); | |
1223 | |
1224 SkAutoGlyphCache autoCache(fSkPaint, &fDeviceProperties, &viewMatrix); | |
1225 SkGlyphCache* cache = autoCache.getCache(); | |
1226 GrFontScaler* fontScaler = GetGrFontScaler(cache); | |
1227 | |
1228 // if we have RGB, then we won't have any SkShaders so no need to use a loca
lmatrix, but for | |
1229 // performance reasons we just invert here instead | |
1230 if (!viewMatrix.invert(&fLocalMatrix)) { | |
1231 SkDebugf("Cannot invert viewmatrix\n"); | |
1232 return; | |
1233 } | |
1234 | |
1235 int numGlyphs = fSkPaint.textToGlyphs(text, byteLength, NULL); | |
1236 fTotalVertexCount = kVerticesPerGlyph*numGlyphs; | |
1237 | |
1238 const char* stop = text + byteLength; | |
1239 SkTextAlignProc alignProc(fSkPaint.getTextAlign()); | |
1240 SkTextMapStateProc tmsProc(viewMatrix, offset, scalarsPerPosition); | |
1241 | |
1242 if (cache->isSubpixel()) { | |
1243 // maybe we should skip the rounding if linearText is set | |
1244 SkAxisAlignment baseline = SkComputeAxisAlignmentForHText(viewMatrix); | |
1245 | |
1246 SkFixed fxMask = ~0; | |
1247 SkFixed fyMask = ~0; | |
1248 SkScalar halfSampleX = SkFixedToScalar(SkGlyph::kSubpixelRound); | |
1249 SkScalar halfSampleY = SkFixedToScalar(SkGlyph::kSubpixelRound); | |
1250 if (kX_SkAxisAlignment == baseline) { | |
1251 fyMask = 0; | |
1252 halfSampleY = SK_ScalarHalf; | |
1253 } else if (kY_SkAxisAlignment == baseline) { | |
1254 fxMask = 0; | |
1255 halfSampleX = SK_ScalarHalf; | |
1256 } | |
1257 | |
1258 if (SkPaint::kLeft_Align == fSkPaint.getTextAlign()) { | |
1259 while (text < stop) { | |
1260 SkPoint tmsLoc; | |
1261 tmsProc(pos, &tmsLoc); | |
1262 Sk48Dot16 fx = SkScalarTo48Dot16(tmsLoc.fX + halfSampleX); | |
1263 Sk48Dot16 fy = SkScalarTo48Dot16(tmsLoc.fY + halfSampleY); | |
1264 | |
1265 const SkGlyph& glyph = glyphCacheProc(cache, &text, | |
1266 fx & fxMask, fy & fyMask); | |
1267 | |
1268 if (glyph.fWidth) { | |
1269 this->appendGlyph(GrGlyph::Pack(glyph.getGlyphID(), | |
1270 glyph.getSubXFixed(), | |
1271 glyph.getSubYFixed(), | |
1272 GrGlyph::kCoverage_MaskStyle
), | |
1273 Sk48Dot16FloorToInt(fx), | |
1274 Sk48Dot16FloorToInt(fy), | |
1275 fontScaler); | |
1276 } | |
1277 pos += scalarsPerPosition; | |
1278 } | |
1279 } else { | |
1280 while (text < stop) { | |
1281 const char* currentText = text; | |
1282 const SkGlyph& metricGlyph = glyphCacheProc(cache, &text, 0, 0); | |
1283 | |
1284 if (metricGlyph.fWidth) { | |
1285 SkDEBUGCODE(SkFixed prevAdvX = metricGlyph.fAdvanceX;) | |
1286 SkDEBUGCODE(SkFixed prevAdvY = metricGlyph.fAdvanceY;) | |
1287 SkPoint tmsLoc; | |
1288 tmsProc(pos, &tmsLoc); | |
1289 SkPoint alignLoc; | |
1290 alignProc(tmsLoc, metricGlyph, &alignLoc); | |
1291 | |
1292 Sk48Dot16 fx = SkScalarTo48Dot16(alignLoc.fX + halfSampleX); | |
1293 Sk48Dot16 fy = SkScalarTo48Dot16(alignLoc.fY + halfSampleY); | |
1294 | |
1295 // have to call again, now that we've been "aligned" | |
1296 const SkGlyph& glyph = glyphCacheProc(cache, ¤tText, | |
1297 fx & fxMask, fy & fyMa
sk); | |
1298 // the assumption is that the metrics haven't changed | |
1299 SkASSERT(prevAdvX == glyph.fAdvanceX); | |
1300 SkASSERT(prevAdvY == glyph.fAdvanceY); | |
1301 SkASSERT(glyph.fWidth); | |
1302 | |
1303 this->appendGlyph(GrGlyph::Pack(glyph.getGlyphID(), | |
1304 glyph.getSubXFixed(), | |
1305 glyph.getSubYFixed(), | |
1306 GrGlyph::kCoverage_MaskStyle
), | |
1307 Sk48Dot16FloorToInt(fx), | |
1308 Sk48Dot16FloorToInt(fy), | |
1309 fontScaler); | |
1310 } | |
1311 pos += scalarsPerPosition; | |
1312 } | |
1313 } | |
1314 } else { // not subpixel | |
1315 | |
1316 if (SkPaint::kLeft_Align == fSkPaint.getTextAlign()) { | |
1317 while (text < stop) { | |
1318 // the last 2 parameters are ignored | |
1319 const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0); | |
1320 | |
1321 if (glyph.fWidth) { | |
1322 SkPoint tmsLoc; | |
1323 tmsProc(pos, &tmsLoc); | |
1324 | |
1325 Sk48Dot16 fx = SkScalarTo48Dot16(tmsLoc.fX + SK_ScalarHalf); | |
1326 Sk48Dot16 fy = SkScalarTo48Dot16(tmsLoc.fY + SK_ScalarHalf); | |
1327 this->appendGlyph(GrGlyph::Pack(glyph.getGlyphID(), | |
1328 glyph.getSubXFixed(), | |
1329 glyph.getSubYFixed(), | |
1330 GrGlyph::kCoverage_MaskStyle
), | |
1331 Sk48Dot16FloorToInt(fx), | |
1332 Sk48Dot16FloorToInt(fy), | |
1333 fontScaler); | |
1334 } | |
1335 pos += scalarsPerPosition; | |
1336 } | |
1337 } else { | |
1338 while (text < stop) { | |
1339 // the last 2 parameters are ignored | |
1340 const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0); | |
1341 | |
1342 if (glyph.fWidth) { | |
1343 SkPoint tmsLoc; | |
1344 tmsProc(pos, &tmsLoc); | |
1345 | |
1346 SkPoint alignLoc; | |
1347 alignProc(tmsLoc, glyph, &alignLoc); | |
1348 | |
1349 Sk48Dot16 fx = SkScalarTo48Dot16(alignLoc.fX + SK_ScalarHalf
); | |
1350 Sk48Dot16 fy = SkScalarTo48Dot16(alignLoc.fY + SK_ScalarHalf
); | |
1351 this->appendGlyph(GrGlyph::Pack(glyph.getGlyphID(), | |
1352 glyph.getSubXFixed(), | |
1353 glyph.getSubYFixed(), | |
1354 GrGlyph::kCoverage_MaskStyle
), | |
1355 Sk48Dot16FloorToInt(fx), | |
1356 Sk48Dot16FloorToInt(fy), | |
1357 fontScaler); | |
1358 } | |
1359 pos += scalarsPerPosition; | |
1360 } | |
1361 } | |
1362 } | |
1363 | |
1364 this->finish(); | |
1365 } | |
1366 | |
1367 static void* alloc_vertices(GrDrawTarget* drawTarget, | |
1368 int numVertices, | |
1369 GrMaskFormat maskFormat) { | |
1370 if (numVertices <= 0) { | |
1371 return NULL; | |
1372 } | |
1373 | |
1374 // set up attributes | |
1375 void* vertices = NULL; | |
1376 bool success = drawTarget->reserveVertexAndIndexSpace(numVertices, | |
1377 get_vertex_stride(mask
Format), | |
1378 0, | |
1379 &vertices, | |
1380 NULL); | |
1381 GrAlwaysAssert(success); | |
1382 return vertices; | |
1383 } | |
1384 | |
1385 inline bool GrBitmapTextContext::uploadGlyph(GrGlyph* glyph, GrFontScaler* scale
r) { | |
1386 if (!fStrike->glyphTooLargeForAtlas(glyph)) { | |
1387 if (fStrike->addGlyphToAtlas(glyph, scaler)) { | |
1388 return true; | |
1389 } | |
1390 | |
1391 // try to clear out an unused plot before we flush | |
1392 if (fContext->getFontCache()->freeUnusedPlot(fStrike, glyph) && | |
1393 fStrike->addGlyphToAtlas(glyph, scaler)) { | |
1394 return true; | |
1395 } | |
1396 | |
1397 if (c_DumpFontCache) { | |
1398 #ifdef SK_DEVELOPER | |
1399 fContext->getFontCache()->dump(); | |
1400 #endif | |
1401 } | |
1402 | |
1403 // before we purge the cache, we must flush any accumulated draws | |
1404 this->flush(); | |
1405 fContext->flush(); | |
1406 | |
1407 // we should have an unused plot now | |
1408 if (fContext->getFontCache()->freeUnusedPlot(fStrike, glyph) && | |
1409 fStrike->addGlyphToAtlas(glyph, scaler)) { | |
1410 return true; | |
1411 } | |
1412 | |
1413 // we should never get here | |
1414 SkASSERT(false); | |
1415 } | |
1416 | |
1417 return false; | |
1418 } | |
1419 | |
1420 void GrBitmapTextContext::appendGlyph(GrGlyph::PackedID packed, | |
1421 int vx, int vy, | |
1422 GrFontScaler* scaler) { | |
1423 if (NULL == fDrawTarget) { | |
1424 return; | |
1425 } | |
1426 | |
1427 if (NULL == fStrike) { | |
1428 fStrike = fContext->getFontCache()->getStrike(scaler); | |
1429 } | |
1430 | |
1431 GrGlyph* glyph = fStrike->getGlyph(packed, scaler); | |
1432 if (NULL == glyph || glyph->fBounds.isEmpty()) { | |
1433 return; | |
1434 } | |
1435 | |
1436 int x = vx + glyph->fBounds.fLeft; | |
1437 int y = vy + glyph->fBounds.fTop; | |
1438 | |
1439 // keep them as ints until we've done the clip-test | |
1440 int width = glyph->fBounds.width(); | |
1441 int height = glyph->fBounds.height(); | |
1442 | |
1443 // check if we clipped out | |
1444 if (fClipRect.quickReject(x, y, x + width, y + height)) { | |
1445 return; | |
1446 } | |
1447 | |
1448 // If the glyph is too large we fall back to paths | |
1449 if (NULL == glyph->fPlot && !uploadGlyph(glyph, scaler)) { | |
1450 if (NULL == glyph->fPath) { | |
1451 SkPath* path = SkNEW(SkPath); | |
1452 if (!scaler->getGlyphPath(glyph->glyphID(), path)) { | |
1453 // flag the glyph as being dead? | |
1454 delete path; | |
1455 return; | |
1456 } | |
1457 glyph->fPath = path; | |
1458 } | |
1459 | |
1460 // flush any accumulated draws before drawing this glyph as a path. | |
1461 this->flush(); | |
1462 | |
1463 SkMatrix translate; | |
1464 translate.setTranslate(SkIntToScalar(vx), SkIntToScalar(vy)); | |
1465 SkPath tmpPath(*glyph->fPath); | |
1466 tmpPath.transform(translate); | |
1467 GrStrokeInfo strokeInfo(SkStrokeRec::kFill_InitStyle); | |
1468 fContext->drawPath(fRenderTarget, fClip, fPaint, SkMatrix::I(), tmpPath,
strokeInfo); | |
1469 | |
1470 // remove this glyph from the vertices we need to allocate | |
1471 fTotalVertexCount -= kVerticesPerGlyph; | |
1472 return; | |
1473 } | |
1474 | |
1475 SkASSERT(glyph->fPlot); | |
1476 GrDrawTarget::DrawToken drawToken = fDrawTarget->getCurrentDrawToken(); | |
1477 glyph->fPlot->setDrawToken(drawToken); | |
1478 | |
1479 // the current texture/maskformat must match what the glyph needs | |
1480 GrTexture* texture = glyph->fPlot->texture(); | |
1481 SkASSERT(texture); | |
1482 | |
1483 if (fCurrTexture != texture || fCurrVertex + kVerticesPerGlyph > fAllocVerte
xCount) { | |
1484 this->flush(); | |
1485 fCurrTexture = texture; | |
1486 fCurrTexture->ref(); | |
1487 fCurrMaskFormat = glyph->fMaskFormat; | |
1488 } | |
1489 | |
1490 if (NULL == fVertices) { | |
1491 int maxQuadVertices = kVerticesPerGlyph * fContext->getQuadIndexBuffer()
->maxQuads(); | |
1492 fAllocVertexCount = SkMin32(fTotalVertexCount, maxQuadVertices); | |
1493 fVertices = alloc_vertices(fDrawTarget, fAllocVertexCount, fCurrMaskForm
at); | |
1494 } | |
1495 | |
1496 SkRect r; | |
1497 r.fLeft = SkIntToScalar(x); | |
1498 r.fTop = SkIntToScalar(y); | |
1499 r.fRight = r.fLeft + SkIntToScalar(width); | |
1500 r.fBottom = r.fTop + SkIntToScalar(height); | |
1501 | |
1502 fVertexBounds.joinNonEmptyArg(r); | |
1503 | |
1504 int u0 = glyph->fAtlasLocation.fX; | |
1505 int v0 = glyph->fAtlasLocation.fY; | |
1506 int u1 = u0 + width; | |
1507 int v1 = v0 + height; | |
1508 | |
1509 size_t vertSize = get_vertex_stride(fCurrMaskFormat); | |
1510 intptr_t vertex = reinterpret_cast<intptr_t>(fVertices) + vertSize * fCurrVe
rtex; | |
1511 | |
1512 // V0 | |
1513 SkPoint* position = reinterpret_cast<SkPoint*>(vertex); | |
1514 position->set(r.fLeft, r.fTop); | |
1515 if (kA8_GrMaskFormat == fCurrMaskFormat) { | |
1516 SkColor* color = reinterpret_cast<SkColor*>(vertex + sizeof(SkPoint)); | |
1517 *color = fPaint.getColor(); | |
1518 } | |
1519 SkIPoint16* textureCoords = reinterpret_cast<SkIPoint16*>(vertex + vertSize
- | |
1520 sizeof(SkIPoint16)
); | |
1521 textureCoords->set(u0, v0); | |
1522 vertex += vertSize; | |
1523 | |
1524 // V1 | |
1525 position = reinterpret_cast<SkPoint*>(vertex); | |
1526 position->set(r.fLeft, r.fBottom); | |
1527 if (kA8_GrMaskFormat == fCurrMaskFormat) { | |
1528 SkColor* color = reinterpret_cast<SkColor*>(vertex + sizeof(SkPoint)); | |
1529 *color = fPaint.getColor(); | |
1530 } | |
1531 textureCoords = reinterpret_cast<SkIPoint16*>(vertex + vertSize - sizeof(Sk
IPoint16)); | |
1532 textureCoords->set(u0, v1); | |
1533 vertex += vertSize; | |
1534 | |
1535 // V2 | |
1536 position = reinterpret_cast<SkPoint*>(vertex); | |
1537 position->set(r.fRight, r.fBottom); | |
1538 if (kA8_GrMaskFormat == fCurrMaskFormat) { | |
1539 SkColor* color = reinterpret_cast<SkColor*>(vertex + sizeof(SkPoint)); | |
1540 *color = fPaint.getColor(); | |
1541 } | |
1542 textureCoords = reinterpret_cast<SkIPoint16*>(vertex + vertSize - sizeof(Sk
IPoint16)); | |
1543 textureCoords->set(u1, v1); | |
1544 vertex += vertSize; | |
1545 | |
1546 // V3 | |
1547 position = reinterpret_cast<SkPoint*>(vertex); | |
1548 position->set(r.fRight, r.fTop); | |
1549 if (kA8_GrMaskFormat == fCurrMaskFormat) { | |
1550 SkColor* color = reinterpret_cast<SkColor*>(vertex + sizeof(SkPoint)); | |
1551 *color = fPaint.getColor(); | |
1552 } | |
1553 textureCoords = reinterpret_cast<SkIPoint16*>(vertex + vertSize - sizeof(Sk
IPoint16)); | |
1554 textureCoords->set(u1, v0); | |
1555 | |
1556 fCurrVertex += 4; | |
1557 } | |
1558 | |
1559 void GrBitmapTextContext::flush() { | |
1560 if (NULL == fDrawTarget) { | |
1561 return; | |
1562 } | |
1563 | |
1564 if (fCurrVertex > 0) { | |
1565 GrPipelineBuilder pipelineBuilder; | |
1566 pipelineBuilder.setFromPaint(fPaint, fRenderTarget, fClip); | |
1567 | |
1568 // setup our sampler state for our text texture/atlas | |
1569 SkASSERT(SkIsAlign4(fCurrVertex)); | |
1570 SkASSERT(fCurrTexture); | |
1571 | |
1572 SkASSERT(fStrike); | |
1573 GrColor color = fPaint.getColor(); | |
1574 switch (fCurrMaskFormat) { | |
1575 // Color bitmap text | |
1576 case kARGB_GrMaskFormat: { | |
1577 int a = fSkPaint.getAlpha(); | |
1578 color = SkColorSetARGB(a, a, a, a); | |
1579 break; | |
1580 } | |
1581 // LCD text | |
1582 case kA565_GrMaskFormat: { | |
1583 // TODO: move supportsRGBCoverage check to setupCoverageEffect a
nd only add LCD | |
1584 // processor if the xp can support it. For now we will simply as
sume that if | |
1585 // fUseLCDText is true, then we have a known color output. | |
1586 const GrXPFactory* xpFactory = pipelineBuilder.getXPFactory(); | |
1587 if (!xpFactory->supportsRGBCoverage(0, kRGBA_GrColorComponentFla
gs)) { | |
1588 SkDebugf("LCD Text will not draw correctly.\n"); | |
1589 } | |
1590 break; | |
1591 } | |
1592 // Grayscale/BW text | |
1593 case kA8_GrMaskFormat: | |
1594 break; | |
1595 default: | |
1596 SkFAIL("Unexpected mask format."); | |
1597 } | |
1598 | |
1599 GrTextureParams params(SkShader::kClamp_TileMode, GrTextureParams::kNone
_FilterMode); | |
1600 uint32_t textureUniqueID = fCurrTexture->getUniqueID(); | |
1601 if (textureUniqueID != fEffectTextureUniqueID || | |
1602 fCachedGeometryProcessor->color() != color || | |
1603 !fCachedGeometryProcessor->localMatrix().cheapEqualTo(fLocalMatrix))
{ | |
1604 // This will be ignored in the non A8 case | |
1605 bool opaqueVertexColors = GrColorIsOpaque(fPaint.getColor()); | |
1606 fCachedGeometryProcessor.reset(GrBitmapTextGeoProc::Create(color, | |
1607 fCurrText
ure, | |
1608 params, | |
1609 fCurrMask
Format, | |
1610 opaqueVer
texColors, | |
1611 fLocalMat
rix)); | |
1612 fEffectTextureUniqueID = textureUniqueID; | |
1613 } | |
1614 | |
1615 int nGlyphs = fCurrVertex / kVerticesPerGlyph; | |
1616 fDrawTarget->setIndexSourceToBuffer(fContext->getQuadIndexBuffer()); | |
1617 fDrawTarget->drawIndexedInstances(&pipelineBuilder, | |
1618 fCachedGeometryProcessor.get(), | |
1619 kTriangles_GrPrimitiveType, | |
1620 nGlyphs, | |
1621 kVerticesPerGlyph, | |
1622 kIndicesPerGlyph, | |
1623 &fVertexBounds); | |
1624 | |
1625 fDrawTarget->resetVertexSource(); | |
1626 fVertices = NULL; | |
1627 fAllocVertexCount = 0; | |
1628 // reset to be those that are left | |
1629 fTotalVertexCount -= fCurrVertex; | |
1630 fCurrVertex = 0; | |
1631 fVertexBounds.setLargestInverted(); | |
1632 SkSafeSetNull(fCurrTexture); | |
1633 } | |
1634 } | |
1635 | |
1636 inline void GrBitmapTextContext::finish() { | |
1637 this->flush(); | |
1638 fTotalVertexCount = 0; | |
1639 | |
1640 GrTextContext::finish(); | |
1641 } | |
OLD | NEW |