| OLD | NEW |
| (Empty) |
| 1 /* libs/graphics/sgl/SkScalerContext.cpp | |
| 2 ** | |
| 3 ** Copyright 2006, The Android Open Source Project | |
| 4 ** | |
| 5 ** Licensed under the Apache License, Version 2.0 (the "License"); | |
| 6 ** you may not use this file except in compliance with the License. | |
| 7 ** You may obtain a copy of the License at | |
| 8 ** | |
| 9 ** http://www.apache.org/licenses/LICENSE-2.0 | |
| 10 ** | |
| 11 ** Unless required by applicable law or agreed to in writing, software | |
| 12 ** distributed under the License is distributed on an "AS IS" BASIS, | |
| 13 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| 14 ** See the License for the specific language governing permissions and | |
| 15 ** limitations under the License. | |
| 16 */ | |
| 17 | |
| 18 #include "SkScalerContext.h" | |
| 19 #include "SkDescriptor.h" | |
| 20 #include "SkDraw.h" | |
| 21 #include "SkFontHost.h" | |
| 22 #include "SkMaskFilter.h" | |
| 23 #include "SkPathEffect.h" | |
| 24 #include "SkRasterizer.h" | |
| 25 #include "SkRegion.h" | |
| 26 #include "SkStroke.h" | |
| 27 #include "SkThread.h" | |
| 28 | |
| 29 #ifdef SK_DEBUG | |
| 30 // #define TRACK_MISSING_CHARS | |
| 31 #endif | |
| 32 | |
| 33 #define ComputeBWRowBytes(width) (((unsigned)(width) + 7) >> 3) | |
| 34 | |
| 35 static const uint8_t* gBlackGammaTable; | |
| 36 static const uint8_t* gWhiteGammaTable; | |
| 37 | |
| 38 void SkGlyph::toMask(SkMask* mask) const { | |
| 39 SkASSERT(mask); | |
| 40 | |
| 41 mask->fImage = (uint8_t*)fImage; | |
| 42 mask->fBounds.set(fLeft, fTop, fLeft + fWidth, fTop + fHeight); | |
| 43 mask->fRowBytes = this->rowBytes(); | |
| 44 mask->fFormat = fMaskFormat; | |
| 45 } | |
| 46 | |
| 47 size_t SkGlyph::computeImageSize() const { | |
| 48 size_t size = this->rowBytes() * fHeight; | |
| 49 if (fMaskFormat == SkMask::k3D_Format) { | |
| 50 size *= 3; | |
| 51 } | |
| 52 return size; | |
| 53 } | |
| 54 | |
| 55 void SkGlyph::zeroMetrics() { | |
| 56 fAdvanceX = 0; | |
| 57 fAdvanceY = 0; | |
| 58 fWidth = 0; | |
| 59 fHeight = 0; | |
| 60 fTop = 0; | |
| 61 fLeft = 0; | |
| 62 fRsbDelta = 0; | |
| 63 fLsbDelta = 0; | |
| 64 } | |
| 65 | |
| 66 #ifdef SK_DEBUG | |
| 67 #define DUMP_RECx | |
| 68 #endif | |
| 69 | |
| 70 static SkFlattenable* load_flattenable(const SkDescriptor* desc, uint32_t tag) { | |
| 71 SkFlattenable* obj = NULL; | |
| 72 uint32_t len; | |
| 73 const void* data = desc->findEntry(tag, &len); | |
| 74 | |
| 75 if (data) { | |
| 76 SkFlattenableReadBuffer buffer(data, len); | |
| 77 obj = buffer.readFlattenable(); | |
| 78 SkASSERT(buffer.offset() == buffer.size()); | |
| 79 } | |
| 80 return obj; | |
| 81 } | |
| 82 | |
| 83 SkScalerContext::SkScalerContext(const SkDescriptor* desc) | |
| 84 : fPathEffect(NULL), fMaskFilter(NULL) | |
| 85 { | |
| 86 static bool gHaveGammaTables; | |
| 87 if (!gHaveGammaTables) { | |
| 88 const uint8_t* tables[2]; | |
| 89 SkFontHost::GetGammaTables(tables); | |
| 90 gBlackGammaTable = tables[0]; | |
| 91 gWhiteGammaTable = tables[1]; | |
| 92 gHaveGammaTables = true; | |
| 93 } | |
| 94 | |
| 95 fBaseGlyphCount = 0; | |
| 96 fAuxScalerContext = NULL; | |
| 97 | |
| 98 const Rec* rec = (const Rec*)desc->findEntry(kRec_SkDescriptorTag, NULL); | |
| 99 SkASSERT(rec); | |
| 100 | |
| 101 fRec = *rec; | |
| 102 | |
| 103 #ifdef DUMP_REC | |
| 104 desc->assertChecksum(); | |
| 105 SkDebugf("SkScalarContext checksum %x count %d length %d\n", desc->getChecks
um(), desc->getCount(), desc->getLength()); | |
| 106 SkDebugf(" textsize %g prescale %g preskew %g post [%g %g %g %g]\n", | |
| 107 rec->fTextSize, rec->fPreScaleX, rec->fPreSkewX, rec->fPost2x2[0][0], | |
| 108 rec->fPost2x2[0][1], rec->fPost2x2[1][0], rec->fPost2x2[1][1]); | |
| 109 SkDebugf(" frame %g miter %g hints %d framefill %d format %d join %d\n", | |
| 110 rec->fFrameWidth, rec->fMiterLimit, rec->fHints, rec->fFrameAndFill, | |
| 111 rec->fMaskFormat, rec->fStrokeJoin); | |
| 112 SkDebugf(" pathEffect %x maskFilter %x\n", desc->findEntry(kPathEffect_SkDe
scriptorTag, NULL), | |
| 113 desc->findEntry(kMaskFilter_SkDescriptorTag, NULL)); | |
| 114 #endif | |
| 115 | |
| 116 fPathEffect = (SkPathEffect*)load_flattenable(desc, kPathEffect_SkDescriptor
Tag); | |
| 117 fMaskFilter = (SkMaskFilter*)load_flattenable(desc, kMaskFilter_SkDescriptor
Tag); | |
| 118 fRasterizer = (SkRasterizer*)load_flattenable(desc, kRasterizer_SkDescriptor
Tag); | |
| 119 } | |
| 120 | |
| 121 SkScalerContext::~SkScalerContext() { | |
| 122 fPathEffect->safeUnref(); | |
| 123 fMaskFilter->safeUnref(); | |
| 124 fRasterizer->safeUnref(); | |
| 125 | |
| 126 SkDELETE(fAuxScalerContext); | |
| 127 } | |
| 128 | |
| 129 SkScalerContext* SkScalerContext::loadAuxContext() const { | |
| 130 if (NULL == fAuxScalerContext) { | |
| 131 fAuxScalerContext = SkFontHost::CreateFallbackScalerContext(fRec); | |
| 132 if (NULL != fAuxScalerContext) { | |
| 133 fAuxScalerContext->setBaseGlyphCount(this->getGlyphCount()); | |
| 134 } | |
| 135 } | |
| 136 return fAuxScalerContext; | |
| 137 } | |
| 138 | |
| 139 #ifdef TRACK_MISSING_CHARS | |
| 140 static uint8_t gMissingChars[1 << 13]; | |
| 141 #endif | |
| 142 | |
| 143 uint16_t SkScalerContext::charToGlyphID(SkUnichar uni) { | |
| 144 unsigned glyphID = this->generateCharToGlyph(uni); | |
| 145 | |
| 146 if (0 == glyphID) { // try auxcontext | |
| 147 SkScalerContext* ctx = this->loadAuxContext(); | |
| 148 if (NULL != ctx) { | |
| 149 glyphID = ctx->generateCharToGlyph(uni); | |
| 150 if (0 != glyphID) { // only fiddle with it if its not missing | |
| 151 glyphID += this->getGlyphCount(); | |
| 152 if (glyphID > 0xFFFF) { | |
| 153 glyphID = 0; | |
| 154 } | |
| 155 } | |
| 156 } | |
| 157 } | |
| 158 #ifdef TRACK_MISSING_CHARS | |
| 159 if (0 == glyphID) { | |
| 160 bool announce = false; | |
| 161 if (uni > 0xFFFF) { // we don't record these | |
| 162 announce = true; | |
| 163 } else { | |
| 164 unsigned index = uni >> 3; | |
| 165 unsigned mask = 1 << (uni & 7); | |
| 166 SkASSERT(index < SK_ARRAY_COUNT(gMissingChars)); | |
| 167 if ((gMissingChars[index] & mask) == 0) { | |
| 168 gMissingChars[index] |= mask; | |
| 169 announce = true; | |
| 170 } | |
| 171 } | |
| 172 if (announce) { | |
| 173 printf(">>> MISSING CHAR <<< 0x%04X\n", uni); | |
| 174 } | |
| 175 } | |
| 176 #endif | |
| 177 return SkToU16(glyphID); | |
| 178 } | |
| 179 | |
| 180 /* Internal routine to resolve auxContextID into a real context. | |
| 181 Only makes sense to call once the glyph has been given a | |
| 182 valid auxGlyphID. | |
| 183 */ | |
| 184 SkScalerContext* SkScalerContext::getGlyphContext(const SkGlyph& glyph) const { | |
| 185 SkScalerContext* ctx = const_cast<SkScalerContext*>(this); | |
| 186 | |
| 187 if (glyph.getGlyphID() >= this->getGlyphCount()) { | |
| 188 ctx = this->loadAuxContext(); | |
| 189 if (NULL == ctx) { // if no aux, just return us | |
| 190 ctx = const_cast<SkScalerContext*>(this); | |
| 191 } | |
| 192 } | |
| 193 return ctx; | |
| 194 } | |
| 195 | |
| 196 static int plus_minus_pin(int value, int max) { | |
| 197 SkASSERT(max >= 0); | |
| 198 | |
| 199 if (value > max) { | |
| 200 value = max; | |
| 201 } else if (value < -max) { | |
| 202 value = -max; | |
| 203 } | |
| 204 return value; | |
| 205 } | |
| 206 | |
| 207 void SkScalerContext::getAdvance(SkGlyph* glyph) { | |
| 208 // mark us as just having a valid advance | |
| 209 glyph->fMaskFormat = MASK_FORMAT_JUST_ADVANCE; | |
| 210 // we mark the format before making the call, in case the impl | |
| 211 // internally ends up calling its generateMetrics, which is OK | |
| 212 // albeit slower than strictly necessary | |
| 213 this->getGlyphContext(*glyph)->generateAdvance(glyph); | |
| 214 } | |
| 215 | |
| 216 void SkScalerContext::getMetrics(SkGlyph* glyph) { | |
| 217 this->getGlyphContext(*glyph)->generateMetrics(glyph); | |
| 218 | |
| 219 // for now we have separate cache entries for devkerning on and off | |
| 220 // in the future we might share caches, but make our measure/draw | |
| 221 // code make the distinction. Thus we zap the values if the caller | |
| 222 // has not asked for them. | |
| 223 if ((fRec.fFlags & SkScalerContext::kDevKernText_Flag) == 0) { | |
| 224 // no devkern, so zap the fields | |
| 225 glyph->fLsbDelta = glyph->fRsbDelta = 0; | |
| 226 } | |
| 227 | |
| 228 // if either dimension is empty, zap the image bounds of the glyph | |
| 229 if (0 == glyph->fWidth || 0 == glyph->fHeight) { | |
| 230 glyph->fWidth = 0; | |
| 231 glyph->fHeight = 0; | |
| 232 glyph->fTop = 0; | |
| 233 glyph->fLeft = 0; | |
| 234 glyph->fMaskFormat = 0; | |
| 235 return; | |
| 236 } | |
| 237 | |
| 238 if (fRec.fFrameWidth > 0 || fPathEffect != NULL || fRasterizer != NULL) { | |
| 239 SkPath devPath, fillPath; | |
| 240 SkMatrix fillToDevMatrix; | |
| 241 | |
| 242 this->internalGetPath(*glyph, &fillPath, &devPath, &fillToDevMatrix); | |
| 243 | |
| 244 if (fRasterizer) { | |
| 245 SkMask mask; | |
| 246 | |
| 247 if (fRasterizer->rasterize(fillPath, fillToDevMatrix, NULL, | |
| 248 fMaskFilter, &mask, | |
| 249 SkMask::kJustComputeBounds_CreateMode)) { | |
| 250 glyph->fLeft = mask.fBounds.fLeft; | |
| 251 glyph->fTop = mask.fBounds.fTop; | |
| 252 glyph->fWidth = SkToU16(mask.fBounds.width()); | |
| 253 glyph->fHeight = SkToU16(mask.fBounds.height()); | |
| 254 } else { | |
| 255 // draw nothing 'cause we failed | |
| 256 glyph->fLeft = 0; | |
| 257 glyph->fTop = 0; | |
| 258 glyph->fWidth = 0; | |
| 259 glyph->fHeight = 0; | |
| 260 return; | |
| 261 } | |
| 262 } else { | |
| 263 // just use devPath | |
| 264 SkRect r; | |
| 265 SkIRect ir; | |
| 266 | |
| 267 devPath.computeBounds(&r, SkPath::kExact_BoundsType); | |
| 268 r.roundOut(&ir); | |
| 269 | |
| 270 glyph->fLeft = ir.fLeft; | |
| 271 glyph->fTop = ir.fTop; | |
| 272 glyph->fWidth = SkToU16(ir.width()); | |
| 273 glyph->fHeight = SkToU16(ir.height()); | |
| 274 } | |
| 275 } | |
| 276 | |
| 277 glyph->fMaskFormat = fRec.fMaskFormat; | |
| 278 | |
| 279 if (fMaskFilter) { | |
| 280 SkMask src, dst; | |
| 281 SkMatrix matrix; | |
| 282 | |
| 283 glyph->toMask(&src); | |
| 284 fRec.getMatrixFrom2x2(&matrix); | |
| 285 | |
| 286 src.fImage = NULL; // only want the bounds from the filter | |
| 287 if (fMaskFilter->filterMask(&dst, src, matrix, NULL)) { | |
| 288 SkASSERT(dst.fImage == NULL); | |
| 289 glyph->fLeft = dst.fBounds.fLeft; | |
| 290 glyph->fTop = dst.fBounds.fTop; | |
| 291 glyph->fWidth = SkToU16(dst.fBounds.width()); | |
| 292 glyph->fHeight = SkToU16(dst.fBounds.height()); | |
| 293 glyph->fMaskFormat = dst.fFormat; | |
| 294 } | |
| 295 } | |
| 296 } | |
| 297 | |
| 298 void SkScalerContext::getImage(const SkGlyph& origGlyph) { | |
| 299 const SkGlyph* glyph = &origGlyph; | |
| 300 SkGlyph tmpGlyph; | |
| 301 | |
| 302 if (fMaskFilter) { // restore the prefilter bounds | |
| 303 tmpGlyph.fID = origGlyph.fID; | |
| 304 | |
| 305 // need the original bounds, sans our maskfilter | |
| 306 SkMaskFilter* mf = fMaskFilter; | |
| 307 fMaskFilter = NULL; // temp disable | |
| 308 this->getMetrics(&tmpGlyph); | |
| 309 fMaskFilter = mf; // restore | |
| 310 | |
| 311 tmpGlyph.fImage = origGlyph.fImage; | |
| 312 | |
| 313 // we need the prefilter bounds to be <= filter bounds | |
| 314 SkASSERT(tmpGlyph.fWidth <= origGlyph.fWidth); | |
| 315 SkASSERT(tmpGlyph.fHeight <= origGlyph.fHeight); | |
| 316 glyph = &tmpGlyph; | |
| 317 } | |
| 318 | |
| 319 if (fRec.fFrameWidth > 0 || fPathEffect != NULL || fRasterizer != NULL) { | |
| 320 SkPath devPath, fillPath; | |
| 321 SkMatrix fillToDevMatrix; | |
| 322 | |
| 323 this->internalGetPath(*glyph, &fillPath, &devPath, &fillToDevMatrix); | |
| 324 | |
| 325 if (fRasterizer) { | |
| 326 SkMask mask; | |
| 327 | |
| 328 glyph->toMask(&mask); | |
| 329 mask.fFormat = SkMask::kA8_Format; | |
| 330 bzero(glyph->fImage, mask.computeImageSize()); | |
| 331 | |
| 332 if (!fRasterizer->rasterize(fillPath, fillToDevMatrix, NULL, | |
| 333 fMaskFilter, &mask, | |
| 334 SkMask::kJustRenderImage_CreateMode)) { | |
| 335 return; | |
| 336 } | |
| 337 } else { | |
| 338 SkBitmap bm; | |
| 339 SkBitmap::Config config; | |
| 340 SkMatrix matrix; | |
| 341 SkRegion clip; | |
| 342 SkPaint paint; | |
| 343 SkDraw draw; | |
| 344 | |
| 345 if (SkMask::kA8_Format == fRec.fMaskFormat) { | |
| 346 config = SkBitmap::kA8_Config; | |
| 347 paint.setAntiAlias(true); | |
| 348 } else { | |
| 349 SkASSERT(SkMask::kBW_Format == fRec.fMaskFormat); | |
| 350 config = SkBitmap::kA1_Config; | |
| 351 paint.setAntiAlias(false); | |
| 352 } | |
| 353 | |
| 354 clip.setRect(0, 0, glyph->fWidth, glyph->fHeight); | |
| 355 matrix.setTranslate(-SkIntToScalar(glyph->fLeft), | |
| 356 -SkIntToScalar(glyph->fTop)); | |
| 357 bm.setConfig(config, glyph->fWidth, glyph->fHeight, | |
| 358 glyph->rowBytes()); | |
| 359 bm.setPixels(glyph->fImage); | |
| 360 bzero(glyph->fImage, bm.height() * bm.rowBytes()); | |
| 361 | |
| 362 draw.fClip = &clip; | |
| 363 draw.fMatrix = &matrix; | |
| 364 draw.fBitmap = &bm; | |
| 365 draw.fBounder = NULL; | |
| 366 draw.drawPath(devPath, paint); | |
| 367 } | |
| 368 } else { | |
| 369 this->getGlyphContext(*glyph)->generateImage(*glyph); | |
| 370 } | |
| 371 | |
| 372 if (fMaskFilter) { | |
| 373 SkMask srcM, dstM; | |
| 374 SkMatrix matrix; | |
| 375 | |
| 376 // the src glyph image shouldn't be 3D | |
| 377 SkASSERT(SkMask::k3D_Format != glyph->fMaskFormat); | |
| 378 glyph->toMask(&srcM); | |
| 379 fRec.getMatrixFrom2x2(&matrix); | |
| 380 | |
| 381 if (fMaskFilter->filterMask(&dstM, srcM, matrix, NULL)) { | |
| 382 int width = SkFastMin32(origGlyph.fWidth, dstM.fBounds.width()); | |
| 383 int height = SkFastMin32(origGlyph.fHeight, dstM.fBounds.height()); | |
| 384 int dstRB = origGlyph.rowBytes(); | |
| 385 int srcRB = dstM.fRowBytes; | |
| 386 | |
| 387 const uint8_t* src = (const uint8_t*)dstM.fImage; | |
| 388 uint8_t* dst = (uint8_t*)origGlyph.fImage; | |
| 389 | |
| 390 if (SkMask::k3D_Format == dstM.fFormat) { | |
| 391 // we have to copy 3 times as much | |
| 392 height *= 3; | |
| 393 } | |
| 394 | |
| 395 // clean out our glyph, since it may be larger than dstM | |
| 396 //bzero(dst, height * dstRB); | |
| 397 | |
| 398 while (--height >= 0) { | |
| 399 memcpy(dst, src, width); | |
| 400 src += srcRB; | |
| 401 dst += dstRB; | |
| 402 } | |
| 403 SkMask::FreeImage(dstM.fImage); | |
| 404 } | |
| 405 } | |
| 406 | |
| 407 // check to see if we should filter the alpha channel | |
| 408 | |
| 409 if (NULL == fMaskFilter && | |
| 410 fRec.fMaskFormat != SkMask::kBW_Format && | |
| 411 (fRec.fFlags & (kGammaForBlack_Flag | kGammaForWhite_Flag)) != 0) | |
| 412 { | |
| 413 const uint8_t* table = (fRec.fFlags & kGammaForBlack_Flag) ? gBlackGamma
Table : gWhiteGammaTable; | |
| 414 if (NULL != table) | |
| 415 { | |
| 416 uint8_t* dst = (uint8_t*)origGlyph.fImage; | |
| 417 unsigned rowBytes = origGlyph.rowBytes(); | |
| 418 | |
| 419 for (int y = origGlyph.fHeight - 1; y >= 0; --y) | |
| 420 { | |
| 421 for (int x = origGlyph.fWidth - 1; x >= 0; --x) | |
| 422 dst[x] = table[dst[x]]; | |
| 423 dst += rowBytes; | |
| 424 } | |
| 425 } | |
| 426 } | |
| 427 } | |
| 428 | |
| 429 void SkScalerContext::getPath(const SkGlyph& glyph, SkPath* path) | |
| 430 { | |
| 431 this->internalGetPath(glyph, NULL, path, NULL); | |
| 432 } | |
| 433 | |
| 434 void SkScalerContext::getFontMetrics(SkPaint::FontMetrics* mx, SkPaint::FontMetr
ics* my) | |
| 435 { | |
| 436 this->generateFontMetrics(mx, my); | |
| 437 } | |
| 438 | |
| 439 /////////////////////////////////////////////////////////////////////// | |
| 440 | |
| 441 void SkScalerContext::internalGetPath(const SkGlyph& glyph, SkPath* fillPath, Sk
Path* devPath, SkMatrix* fillToDevMatrix) | |
| 442 { | |
| 443 SkPath path; | |
| 444 | |
| 445 this->getGlyphContext(glyph)->generatePath(glyph, &path); | |
| 446 | |
| 447 if (fRec.fFrameWidth > 0 || fPathEffect != NULL) | |
| 448 { | |
| 449 // need the path in user-space, with only the point-size applied | |
| 450 // so that our stroking and effects will operate the same way they | |
| 451 // would if the user had extracted the path themself, and then | |
| 452 // called drawPath | |
| 453 SkPath localPath; | |
| 454 SkMatrix matrix, inverse; | |
| 455 | |
| 456 fRec.getMatrixFrom2x2(&matrix); | |
| 457 matrix.invert(&inverse); | |
| 458 path.transform(inverse, &localPath); | |
| 459 // now localPath is only affected by the paint settings, and not the can
vas matrix | |
| 460 | |
| 461 SkScalar width = fRec.fFrameWidth; | |
| 462 | |
| 463 if (fPathEffect) | |
| 464 { | |
| 465 SkPath effectPath; | |
| 466 | |
| 467 if (fPathEffect->filterPath(&effectPath, localPath, &width)) | |
| 468 localPath.swap(effectPath); | |
| 469 } | |
| 470 | |
| 471 if (width > 0) | |
| 472 { | |
| 473 SkStroke stroker; | |
| 474 SkPath outline; | |
| 475 | |
| 476 stroker.setWidth(width); | |
| 477 stroker.setMiterLimit(fRec.fMiterLimit); | |
| 478 stroker.setJoin((SkPaint::Join)fRec.fStrokeJoin); | |
| 479 stroker.setDoFill(SkToBool(fRec.fFlags & kFrameAndFill_Flag)); | |
| 480 stroker.strokePath(localPath, &outline); | |
| 481 localPath.swap(outline); | |
| 482 } | |
| 483 | |
| 484 // now return stuff to the caller | |
| 485 if (fillToDevMatrix) | |
| 486 *fillToDevMatrix = matrix; | |
| 487 | |
| 488 if (devPath) | |
| 489 localPath.transform(matrix, devPath); | |
| 490 | |
| 491 if (fillPath) | |
| 492 fillPath->swap(localPath); | |
| 493 } | |
| 494 else // nothing tricky to do | |
| 495 { | |
| 496 if (fillToDevMatrix) | |
| 497 fillToDevMatrix->reset(); | |
| 498 | |
| 499 if (devPath) | |
| 500 { | |
| 501 if (fillPath == NULL) | |
| 502 devPath->swap(path); | |
| 503 else | |
| 504 *devPath = path; | |
| 505 } | |
| 506 | |
| 507 if (fillPath) | |
| 508 fillPath->swap(path); | |
| 509 } | |
| 510 | |
| 511 if (devPath) | |
| 512 devPath->updateBoundsCache(); | |
| 513 if (fillPath) | |
| 514 fillPath->updateBoundsCache(); | |
| 515 } | |
| 516 | |
| 517 | |
| 518 void SkScalerContext::Rec::getMatrixFrom2x2(SkMatrix* dst) const | |
| 519 { | |
| 520 dst->reset(); | |
| 521 dst->setScaleX(fPost2x2[0][0]); | |
| 522 dst->setSkewX( fPost2x2[0][1]); | |
| 523 dst->setSkewY( fPost2x2[1][0]); | |
| 524 dst->setScaleY(fPost2x2[1][1]); | |
| 525 } | |
| 526 | |
| 527 void SkScalerContext::Rec::getLocalMatrix(SkMatrix* m) const | |
| 528 { | |
| 529 m->setScale(SkScalarMul(fTextSize, fPreScaleX), fTextSize); | |
| 530 if (fPreSkewX) | |
| 531 m->postSkew(fPreSkewX, 0); | |
| 532 } | |
| 533 | |
| 534 void SkScalerContext::Rec::getSingleMatrix(SkMatrix* m) const | |
| 535 { | |
| 536 this->getLocalMatrix(m); | |
| 537 | |
| 538 // now concat the device matrix | |
| 539 { | |
| 540 SkMatrix deviceMatrix; | |
| 541 this->getMatrixFrom2x2(&deviceMatrix); | |
| 542 m->postConcat(deviceMatrix); | |
| 543 } | |
| 544 } | |
| 545 | |
| 546 #include "SkFontHost.h" | |
| 547 | |
| 548 SkScalerContext* SkScalerContext::Create(const SkDescriptor* desc) | |
| 549 { | |
| 550 return SkFontHost::CreateScalerContext(desc); | |
| 551 } | |
| 552 | |
| OLD | NEW |