| 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 |