1
2 /*
3 * Copyright 2006 The Android Open Source Project
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
8
9
10 #include "SkScalerContext.h"
11 #include "SkColorPriv.h"
12 #include "SkDescriptor.h"
13 #include "SkDraw.h"
14 #include "SkFontHost.h"
15 #include "SkMaskFilter.h"
16 #include "SkPathEffect.h"
17 #include "SkRasterizer.h"
18 #include "SkRasterClip.h"
19 #include "SkStroke.h"
20 #include "SkThread.h"
21
22 #define ComputeBWRowBytes(width) (((unsigned)(width) + 7) >> 3)
23
toMask(SkMask * mask) const24 void SkGlyph::toMask(SkMask* mask) const {
25 SkASSERT(mask);
26
27 mask->fImage = (uint8_t*)fImage;
28 mask->fBounds.set(fLeft, fTop, fLeft + fWidth, fTop + fHeight);
29 mask->fRowBytes = this->rowBytes();
30 mask->fFormat = static_cast<SkMask::Format>(fMaskFormat);
31 }
32
computeImageSize() const33 size_t SkGlyph::computeImageSize() const {
34 const size_t size = this->rowBytes() * fHeight;
35
36 switch (fMaskFormat) {
37 case SkMask::k3D_Format:
38 return 3 * size;
39 default:
40 return size;
41 }
42 }
43
zeroMetrics()44 void SkGlyph::zeroMetrics() {
45 fAdvanceX = 0;
46 fAdvanceY = 0;
47 fWidth = 0;
48 fHeight = 0;
49 fTop = 0;
50 fLeft = 0;
51 fRsbDelta = 0;
52 fLsbDelta = 0;
53 }
54
55 ///////////////////////////////////////////////////////////////////////////////
56
57 #ifdef SK_DEBUG
58 #define DUMP_RECx
59 #endif
60
load_flattenable(const SkDescriptor * desc,uint32_t tag)61 static SkFlattenable* load_flattenable(const SkDescriptor* desc, uint32_t tag) {
62 SkFlattenable* obj = NULL;
63 uint32_t len;
64 const void* data = desc->findEntry(tag, &len);
65
66 if (data) {
67 SkFlattenableReadBuffer buffer(data, len);
68 obj = buffer.readFlattenable();
69 SkASSERT(buffer.offset() == buffer.size());
70 }
71 return obj;
72 }
73
SkScalerContext(const SkDescriptor * desc)74 SkScalerContext::SkScalerContext(const SkDescriptor* desc)
75 : fPathEffect(NULL), fMaskFilter(NULL)
76 {
77 fBaseGlyphCount = 0;
78 fNextContext = NULL;
79
80 const Rec* rec = (const Rec*)desc->findEntry(kRec_SkDescriptorTag, NULL);
81 SkASSERT(rec);
82
83 fRec = *rec;
84
85 #ifdef DUMP_REC
86 desc->assertChecksum();
87 SkDebugf("SkScalarContext checksum %x count %d length %d\n",
88 desc->getChecksum(), desc->getCount(), desc->getLength());
89 SkDebugf(" textsize %g prescale %g preskew %g post [%g %g %g %g]\n",
90 rec->fTextSize, rec->fPreScaleX, rec->fPreSkewX, rec->fPost2x2[0][0],
91 rec->fPost2x2[0][1], rec->fPost2x2[1][0], rec->fPost2x2[1][1]);
92 SkDebugf(" frame %g miter %g hints %d framefill %d format %d join %d\n",
93 rec->fFrameWidth, rec->fMiterLimit, rec->fHints, rec->fFrameAndFill,
94 rec->fMaskFormat, rec->fStrokeJoin);
95 SkDebugf(" pathEffect %x maskFilter %x\n",
96 desc->findEntry(kPathEffect_SkDescriptorTag, NULL),
97 desc->findEntry(kMaskFilter_SkDescriptorTag, NULL));
98 #endif
99
100 fPathEffect = (SkPathEffect*)load_flattenable(desc, kPathEffect_SkDescriptorTag);
101 fMaskFilter = (SkMaskFilter*)load_flattenable(desc, kMaskFilter_SkDescriptorTag);
102 fRasterizer = (SkRasterizer*)load_flattenable(desc, kRasterizer_SkDescriptorTag);
103
104 // initialize based on our settings. subclasses can also force this
105 fGenerateImageFromPath = fRec.fFrameWidth > 0 || fPathEffect != NULL ||
106 fRasterizer != NULL;
107 }
108
~SkScalerContext()109 SkScalerContext::~SkScalerContext() {
110 SkDELETE(fNextContext);
111
112 SkSafeUnref(fPathEffect);
113 SkSafeUnref(fMaskFilter);
114 SkSafeUnref(fRasterizer);
115 }
116
allocNextContext(const SkScalerContext::Rec & rec)117 static SkScalerContext* allocNextContext(const SkScalerContext::Rec& rec) {
118 // fonthost will determine the next possible font to search, based
119 // on the current font in fRec. It will return NULL if ctx is our
120 // last font that can be searched (i.e. ultimate fallback font)
121 uint32_t newFontID = SkFontHost::NextLogicalFont(rec.fFontID, rec.fOrigFontID);
122 if (0 == newFontID) {
123 return NULL;
124 }
125
126 SkAutoDescriptor ad(sizeof(rec) + SkDescriptor::ComputeOverhead(1));
127 SkDescriptor* desc = ad.getDesc();
128
129 desc->init();
130 SkScalerContext::Rec* newRec =
131 (SkScalerContext::Rec*)desc->addEntry(kRec_SkDescriptorTag,
132 sizeof(rec), &rec);
133 newRec->fFontID = newFontID;
134 desc->computeChecksum();
135
136 return SkFontHost::CreateScalerContext(desc);
137 }
138
139 /* Return the next context, creating it if its not already created, but return
140 NULL if the fonthost says there are no more fonts to fallback to.
141 */
getNextContext()142 SkScalerContext* SkScalerContext::getNextContext() {
143 SkScalerContext* next = fNextContext;
144 // if next is null, then either it isn't cached yet, or we're at the
145 // end of our possible chain
146 if (NULL == next) {
147 next = allocNextContext(fRec);
148 if (NULL == next) {
149 return NULL;
150 }
151 // next's base is our base + our local count
152 next->setBaseGlyphCount(fBaseGlyphCount + this->getGlyphCount());
153 // cache the answer
154 fNextContext = next;
155 }
156 return next;
157 }
158
getGlyphContext(const SkGlyph & glyph)159 SkScalerContext* SkScalerContext::getGlyphContext(const SkGlyph& glyph) {
160 unsigned glyphID = glyph.getGlyphID();
161 SkScalerContext* ctx = this;
162 for (;;) {
163 unsigned count = ctx->getGlyphCount();
164 if (glyphID < count) {
165 break;
166 }
167 glyphID -= count;
168 ctx = ctx->getNextContext();
169 if (NULL == ctx) {
170 SkDebugf("--- no context for glyph %x\n", glyph.getGlyphID());
171 // just return the original context (this)
172 return this;
173 }
174 }
175 return ctx;
176 }
177
178 #ifdef SK_BUILD_FOR_ANDROID
179 /* This loops through all available fallback contexts (if needed) until it
180 finds some context that can handle the unichar and return it.
181
182 As this is somewhat expensive operation, it should only be done on the first
183 char of a run.
184 */
getBaseGlyphCount(SkUnichar uni)185 unsigned SkScalerContext::getBaseGlyphCount(SkUnichar uni) {
186 SkScalerContext* ctx = this;
187 unsigned glyphID;
188 for (;;) {
189 glyphID = ctx->generateCharToGlyph(uni);
190 if (glyphID) {
191 break; // found it
192 }
193 ctx = ctx->getNextContext();
194 if (NULL == ctx) {
195 SkDebugf("--- no context for char %x\n", uni);
196 // just return the original context (this)
197 return this->fBaseGlyphCount;
198 }
199 }
200 return ctx->fBaseGlyphCount;
201 }
202 #endif
203
204 /* This loops through all available fallback contexts (if needed) until it
205 finds some context that can handle the unichar. If all fail, returns 0
206 */
charToGlyphID(SkUnichar uni)207 uint16_t SkScalerContext::charToGlyphID(SkUnichar uni) {
208 SkScalerContext* ctx = this;
209 unsigned glyphID;
210 for (;;) {
211 glyphID = ctx->generateCharToGlyph(uni);
212 if (glyphID) {
213 break; // found it
214 }
215 ctx = ctx->getNextContext();
216 if (NULL == ctx) {
217 return 0; // no more contexts, return missing glyph
218 }
219 }
220 // add the ctx's base, making glyphID unique for chain of contexts
221 glyphID += ctx->fBaseGlyphCount;
222 // check for overflow of 16bits, since our glyphID cannot exceed that
223 if (glyphID > 0xFFFF) {
224 glyphID = 0;
225 }
226 return SkToU16(glyphID);
227 }
228
glyphIDToChar(uint16_t glyphID)229 SkUnichar SkScalerContext::glyphIDToChar(uint16_t glyphID) {
230 SkScalerContext* ctx = this;
231 unsigned rangeEnd = 0;
232 do {
233 unsigned rangeStart = rangeEnd;
234
235 rangeEnd += ctx->getGlyphCount();
236 if (rangeStart <= glyphID && glyphID < rangeEnd) {
237 return ctx->generateGlyphToChar(glyphID - rangeStart);
238 }
239 ctx = ctx->getNextContext();
240 } while (NULL != ctx);
241 return 0;
242 }
243
getAdvance(SkGlyph * glyph)244 void SkScalerContext::getAdvance(SkGlyph* glyph) {
245 // mark us as just having a valid advance
246 glyph->fMaskFormat = MASK_FORMAT_JUST_ADVANCE;
247 // we mark the format before making the call, in case the impl
248 // internally ends up calling its generateMetrics, which is OK
249 // albeit slower than strictly necessary
250 this->getGlyphContext(*glyph)->generateAdvance(glyph);
251 }
252
getMetrics(SkGlyph * glyph)253 void SkScalerContext::getMetrics(SkGlyph* glyph) {
254 this->getGlyphContext(*glyph)->generateMetrics(glyph);
255
256 // for now we have separate cache entries for devkerning on and off
257 // in the future we might share caches, but make our measure/draw
258 // code make the distinction. Thus we zap the values if the caller
259 // has not asked for them.
260 if ((fRec.fFlags & SkScalerContext::kDevKernText_Flag) == 0) {
261 // no devkern, so zap the fields
262 glyph->fLsbDelta = glyph->fRsbDelta = 0;
263 }
264
265 // if either dimension is empty, zap the image bounds of the glyph
266 if (0 == glyph->fWidth || 0 == glyph->fHeight) {
267 glyph->fWidth = 0;
268 glyph->fHeight = 0;
269 glyph->fTop = 0;
270 glyph->fLeft = 0;
271 glyph->fMaskFormat = 0;
272 return;
273 }
274
275 if (fGenerateImageFromPath) {
276 SkPath devPath, fillPath;
277 SkMatrix fillToDevMatrix;
278
279 this->internalGetPath(*glyph, &fillPath, &devPath, &fillToDevMatrix);
280
281 if (fRasterizer) {
282 SkMask mask;
283
284 if (fRasterizer->rasterize(fillPath, fillToDevMatrix, NULL,
285 fMaskFilter, &mask,
286 SkMask::kJustComputeBounds_CreateMode)) {
287 glyph->fLeft = mask.fBounds.fLeft;
288 glyph->fTop = mask.fBounds.fTop;
289 glyph->fWidth = SkToU16(mask.fBounds.width());
290 glyph->fHeight = SkToU16(mask.fBounds.height());
291 } else {
292 goto SK_ERROR;
293 }
294 } else {
295 // just use devPath
296 SkIRect ir;
297 devPath.getBounds().roundOut(&ir);
298
299 if (ir.isEmpty() || !ir.is16Bit()) {
300 goto SK_ERROR;
301 }
302 glyph->fLeft = ir.fLeft;
303 glyph->fTop = ir.fTop;
304 glyph->fWidth = SkToU16(ir.width());
305 glyph->fHeight = SkToU16(ir.height());
306 }
307 }
308
309 if (SkMask::kARGB32_Format != glyph->fMaskFormat) {
310 glyph->fMaskFormat = fRec.fMaskFormat;
311 }
312
313 if (fMaskFilter) {
314 SkMask src, dst;
315 SkMatrix matrix;
316
317 glyph->toMask(&src);
318 fRec.getMatrixFrom2x2(&matrix);
319
320 src.fImage = NULL; // only want the bounds from the filter
321 if (fMaskFilter->filterMask(&dst, src, matrix, NULL)) {
322 SkASSERT(dst.fImage == NULL);
323 glyph->fLeft = dst.fBounds.fLeft;
324 glyph->fTop = dst.fBounds.fTop;
325 glyph->fWidth = SkToU16(dst.fBounds.width());
326 glyph->fHeight = SkToU16(dst.fBounds.height());
327 glyph->fMaskFormat = dst.fFormat;
328 }
329 }
330 return;
331
332 SK_ERROR:
333 // draw nothing 'cause we failed
334 glyph->fLeft = 0;
335 glyph->fTop = 0;
336 glyph->fWidth = 0;
337 glyph->fHeight = 0;
338 // put a valid value here, in case it was earlier set to
339 // MASK_FORMAT_JUST_ADVANCE
340 glyph->fMaskFormat = fRec.fMaskFormat;
341 }
342
isLCD(const SkScalerContext::Rec & rec)343 static bool isLCD(const SkScalerContext::Rec& rec) {
344 return SkMask::kLCD16_Format == rec.fMaskFormat ||
345 SkMask::kLCD32_Format == rec.fMaskFormat;
346 }
347
a8_to_rgb565(unsigned a8)348 static uint16_t a8_to_rgb565(unsigned a8) {
349 return SkPackRGB16(a8 >> 3, a8 >> 2, a8 >> 3);
350 }
351
copyToLCD16(const SkBitmap & src,const SkMask & dst)352 static void copyToLCD16(const SkBitmap& src, const SkMask& dst) {
353 SkASSERT(SkBitmap::kA8_Config == src.config());
354 SkASSERT(SkMask::kLCD16_Format == dst.fFormat);
355
356 const int width = dst.fBounds.width();
357 const int height = dst.fBounds.height();
358 const uint8_t* srcP = src.getAddr8(0, 0);
359 size_t srcRB = src.rowBytes();
360 uint16_t* dstP = (uint16_t*)dst.fImage;
361 size_t dstRB = dst.fRowBytes;
362 for (int y = 0; y < height; ++y) {
363 for (int x = 0; x < width; ++x) {
364 dstP[x] = a8_to_rgb565(srcP[x]);
365 }
366 srcP += srcRB;
367 dstP = (uint16_t*)((char*)dstP + dstRB);
368 }
369 }
370
371 #define SK_FREETYPE_LCD_LERP 160
372
lerp(int start,int end)373 static int lerp(int start, int end) {
374 SkASSERT((unsigned)SK_FREETYPE_LCD_LERP <= 256);
375 return start + ((end - start) * (SK_FREETYPE_LCD_LERP) >> 8);
376 }
377
packLCD16(unsigned r,unsigned g,unsigned b)378 static uint16_t packLCD16(unsigned r, unsigned g, unsigned b) {
379 if (SK_FREETYPE_LCD_LERP) {
380 // want (a+b+c)/3, but we approx to avoid the divide
381 unsigned ave = (5 * (r + g + b) + g) >> 4;
382 r = lerp(r, ave);
383 g = lerp(g, ave);
384 b = lerp(b, ave);
385 }
386 return SkPackRGB16(r >> 3, g >> 2, b >> 3);
387 }
388
pack3xHToLCD16(const SkBitmap & src,const SkMask & dst)389 static void pack3xHToLCD16(const SkBitmap& src, const SkMask& dst) {
390 SkASSERT(SkBitmap::kA8_Config == src.config());
391 SkASSERT(SkMask::kLCD16_Format == dst.fFormat);
392
393 const int width = dst.fBounds.width();
394 const int height = dst.fBounds.height();
395 uint16_t* dstP = (uint16_t*)dst.fImage;
396 size_t dstRB = dst.fRowBytes;
397 for (int y = 0; y < height; ++y) {
398 const uint8_t* srcP = src.getAddr8(0, y);
399 for (int x = 0; x < width; ++x) {
400 unsigned r = *srcP++;
401 unsigned g = *srcP++;
402 unsigned b = *srcP++;
403 dstP[x] = packLCD16(r, g, b);
404 }
405 dstP = (uint16_t*)((char*)dstP + dstRB);
406 }
407 }
408
pack3xHToLCD32(const SkBitmap & src,const SkMask & dst)409 static void pack3xHToLCD32(const SkBitmap& src, const SkMask& dst) {
410 SkASSERT(SkBitmap::kA8_Config == src.config());
411 SkASSERT(SkMask::kLCD32_Format == dst.fFormat);
412
413 const int width = dst.fBounds.width();
414 const int height = dst.fBounds.height();
415 SkPMColor* dstP = (SkPMColor*)dst.fImage;
416 size_t dstRB = dst.fRowBytes;
417 for (int y = 0; y < height; ++y) {
418 const uint8_t* srcP = src.getAddr8(0, y);
419 for (int x = 0; x < width; ++x) {
420 unsigned r = *srcP++;
421 unsigned g = *srcP++;
422 unsigned b = *srcP++;
423 unsigned a = SkMax32(SkMax32(r, g), b);
424 dstP[x] = SkPackARGB32(a, r, g, b);
425 }
426 dstP = (SkPMColor*)((char*)dstP + dstRB);
427 }
428 }
429
generateMask(const SkMask & mask,const SkPath & path)430 static void generateMask(const SkMask& mask, const SkPath& path) {
431 SkBitmap::Config config;
432 SkPaint paint;
433
434 int srcW = mask.fBounds.width();
435 int srcH = mask.fBounds.height();
436 int dstW = srcW;
437 int dstH = srcH;
438 int dstRB = mask.fRowBytes;
439
440 SkMatrix matrix;
441 matrix.setTranslate(-SkIntToScalar(mask.fBounds.fLeft),
442 -SkIntToScalar(mask.fBounds.fTop));
443
444 if (SkMask::kBW_Format == mask.fFormat) {
445 config = SkBitmap::kA1_Config;
446 paint.setAntiAlias(false);
447 } else {
448 config = SkBitmap::kA8_Config;
449 paint.setAntiAlias(true);
450 switch (mask.fFormat) {
451 case SkMask::kA8_Format:
452 break;
453 case SkMask::kLCD16_Format:
454 case SkMask::kLCD32_Format:
455 // TODO: trigger off LCD orientation
456 dstW *= 3;
457 matrix.postScale(SkIntToScalar(3), SK_Scalar1);
458 dstRB = 0; // signals we need a copy
459 break;
460 default:
461 SkDEBUGFAIL("unexpected mask format");
462 }
463 }
464
465 SkRasterClip clip;
466 clip.setRect(SkIRect::MakeWH(dstW, dstH));
467
468 SkBitmap bm;
469 bm.setConfig(config, dstW, dstH, dstRB);
470
471 if (0 == dstRB) {
472 bm.allocPixels();
473 bm.lockPixels();
474 } else {
475 bm.setPixels(mask.fImage);
476 }
477 sk_bzero(bm.getPixels(), bm.getSafeSize());
478
479 SkDraw draw;
480 sk_bzero(&draw, sizeof(draw));
481 draw.fRC = &clip;
482 draw.fClip = &clip.bwRgn();
483 draw.fMatrix = &matrix;
484 draw.fBitmap = &bm;
485 draw.drawPath(path, paint);
486
487 if (0 == dstRB) {
488 switch (mask.fFormat) {
489 case SkMask::kLCD16_Format:
490 pack3xHToLCD16(bm, mask);
491 break;
492 case SkMask::kLCD32_Format:
493 pack3xHToLCD32(bm, mask);
494 break;
495 default:
496 SkDEBUGFAIL("bad format for copyback");
497 }
498 }
499 }
500
getImage(const SkGlyph & origGlyph)501 void SkScalerContext::getImage(const SkGlyph& origGlyph) {
502 const SkGlyph* glyph = &origGlyph;
503 SkGlyph tmpGlyph;
504
505 if (fMaskFilter) { // restore the prefilter bounds
506 tmpGlyph.init(origGlyph.fID);
507
508 // need the original bounds, sans our maskfilter
509 SkMaskFilter* mf = fMaskFilter;
510 fMaskFilter = NULL; // temp disable
511 this->getMetrics(&tmpGlyph);
512 fMaskFilter = mf; // restore
513
514 tmpGlyph.fImage = origGlyph.fImage;
515
516 // we need the prefilter bounds to be <= filter bounds
517 SkASSERT(tmpGlyph.fWidth <= origGlyph.fWidth);
518 SkASSERT(tmpGlyph.fHeight <= origGlyph.fHeight);
519 glyph = &tmpGlyph;
520 }
521
522 if (fGenerateImageFromPath) {
523 SkPath devPath, fillPath;
524 SkMatrix fillToDevMatrix;
525 SkMask mask;
526
527 this->internalGetPath(*glyph, &fillPath, &devPath, &fillToDevMatrix);
528 glyph->toMask(&mask);
529
530 if (fRasterizer) {
531 mask.fFormat = SkMask::kA8_Format;
532 sk_bzero(glyph->fImage, mask.computeImageSize());
533
534 if (!fRasterizer->rasterize(fillPath, fillToDevMatrix, NULL,
535 fMaskFilter, &mask,
536 SkMask::kJustRenderImage_CreateMode)) {
537 return;
538 }
539 } else {
540 generateMask(mask, devPath);
541 }
542 } else {
543 this->getGlyphContext(*glyph)->generateImage(*glyph);
544 }
545
546 if (fMaskFilter) {
547 SkMask srcM, dstM;
548 SkMatrix matrix;
549
550 // the src glyph image shouldn't be 3D
551 SkASSERT(SkMask::k3D_Format != glyph->fMaskFormat);
552 glyph->toMask(&srcM);
553 fRec.getMatrixFrom2x2(&matrix);
554
555 if (fMaskFilter->filterMask(&dstM, srcM, matrix, NULL)) {
556 int width = SkFastMin32(origGlyph.fWidth, dstM.fBounds.width());
557 int height = SkFastMin32(origGlyph.fHeight, dstM.fBounds.height());
558 int dstRB = origGlyph.rowBytes();
559 int srcRB = dstM.fRowBytes;
560
561 const uint8_t* src = (const uint8_t*)dstM.fImage;
562 uint8_t* dst = (uint8_t*)origGlyph.fImage;
563
564 if (SkMask::k3D_Format == dstM.fFormat) {
565 // we have to copy 3 times as much
566 height *= 3;
567 }
568
569 // clean out our glyph, since it may be larger than dstM
570 //sk_bzero(dst, height * dstRB);
571
572 while (--height >= 0) {
573 memcpy(dst, src, width);
574 src += srcRB;
575 dst += dstRB;
576 }
577 SkMask::FreeImage(dstM.fImage);
578 }
579 }
580 }
581
getPath(const SkGlyph & glyph,SkPath * path)582 void SkScalerContext::getPath(const SkGlyph& glyph, SkPath* path) {
583 this->internalGetPath(glyph, NULL, path, NULL);
584 }
585
getFontMetrics(SkPaint::FontMetrics * mx,SkPaint::FontMetrics * my)586 void SkScalerContext::getFontMetrics(SkPaint::FontMetrics* mx,
587 SkPaint::FontMetrics* my) {
588 this->generateFontMetrics(mx, my);
589 }
590
generateGlyphToChar(uint16_t glyph)591 SkUnichar SkScalerContext::generateGlyphToChar(uint16_t glyph) {
592 return 0;
593 }
594
595 ///////////////////////////////////////////////////////////////////////////////
596
internalGetPath(const SkGlyph & glyph,SkPath * fillPath,SkPath * devPath,SkMatrix * fillToDevMatrix)597 void SkScalerContext::internalGetPath(const SkGlyph& glyph, SkPath* fillPath,
598 SkPath* devPath, SkMatrix* fillToDevMatrix) {
599 SkPath path;
600
601 this->getGlyphContext(glyph)->generatePath(glyph, &path);
602
603 if (fRec.fFlags & SkScalerContext::kSubpixelPositioning_Flag) {
604 SkFixed dx = glyph.getSubXFixed();
605 SkFixed dy = glyph.getSubYFixed();
606 if (dx | dy) {
607 path.offset(SkFixedToScalar(dx), SkFixedToScalar(dy));
608 }
609 }
610
611 if (fRec.fFrameWidth > 0 || fPathEffect != NULL) {
612 // need the path in user-space, with only the point-size applied
613 // so that our stroking and effects will operate the same way they
614 // would if the user had extracted the path themself, and then
615 // called drawPath
616 SkPath localPath;
617 SkMatrix matrix, inverse;
618
619 fRec.getMatrixFrom2x2(&matrix);
620 matrix.invert(&inverse);
621 path.transform(inverse, &localPath);
622 // now localPath is only affected by the paint settings, and not the canvas matrix
623
624 SkScalar width = fRec.fFrameWidth;
625
626 if (fPathEffect) {
627 SkPath effectPath;
628
629 if (fPathEffect->filterPath(&effectPath, localPath, &width)) {
630 localPath.swap(effectPath);
631 }
632 }
633
634 if (width > 0) {
635 SkStroke stroker;
636 SkPath outline;
637
638 stroker.setWidth(width);
639 stroker.setMiterLimit(fRec.fMiterLimit);
640 stroker.setJoin((SkPaint::Join)fRec.fStrokeJoin);
641 stroker.setDoFill(SkToBool(fRec.fFlags & kFrameAndFill_Flag));
642 stroker.strokePath(localPath, &outline);
643 localPath.swap(outline);
644 }
645
646 // now return stuff to the caller
647 if (fillToDevMatrix) {
648 *fillToDevMatrix = matrix;
649 }
650 if (devPath) {
651 localPath.transform(matrix, devPath);
652 }
653 if (fillPath) {
654 fillPath->swap(localPath);
655 }
656 } else { // nothing tricky to do
657 if (fillToDevMatrix) {
658 fillToDevMatrix->reset();
659 }
660 if (devPath) {
661 if (fillPath == NULL) {
662 devPath->swap(path);
663 } else {
664 *devPath = path;
665 }
666 }
667
668 if (fillPath) {
669 fillPath->swap(path);
670 }
671 }
672
673 if (devPath) {
674 devPath->updateBoundsCache();
675 }
676 if (fillPath) {
677 fillPath->updateBoundsCache();
678 }
679 }
680
681
getMatrixFrom2x2(SkMatrix * dst) const682 void SkScalerContext::Rec::getMatrixFrom2x2(SkMatrix* dst) const {
683 dst->reset();
684 dst->setScaleX(fPost2x2[0][0]);
685 dst->setSkewX( fPost2x2[0][1]);
686 dst->setSkewY( fPost2x2[1][0]);
687 dst->setScaleY(fPost2x2[1][1]);
688 }
689
getLocalMatrix(SkMatrix * m) const690 void SkScalerContext::Rec::getLocalMatrix(SkMatrix* m) const {
691 m->setScale(SkScalarMul(fTextSize, fPreScaleX), fTextSize);
692 if (fPreSkewX) {
693 m->postSkew(fPreSkewX, 0);
694 }
695 }
696
getSingleMatrix(SkMatrix * m) const697 void SkScalerContext::Rec::getSingleMatrix(SkMatrix* m) const {
698 this->getLocalMatrix(m);
699
700 // now concat the device matrix
701 SkMatrix deviceMatrix;
702 this->getMatrixFrom2x2(&deviceMatrix);
703 m->postConcat(deviceMatrix);
704 }
705
SkComputeAxisAlignmentForHText(const SkMatrix & matrix)706 SkAxisAlignment SkComputeAxisAlignmentForHText(const SkMatrix& matrix) {
707 SkASSERT(!matrix.hasPerspective());
708
709 if (0 == matrix[SkMatrix::kMSkewY]) {
710 return kX_SkAxisAlignment;
711 }
712 if (0 == matrix[SkMatrix::kMScaleX]) {
713 return kY_SkAxisAlignment;
714 }
715 return kNone_SkAxisAlignment;
716 }
717
718 ///////////////////////////////////////////////////////////////////////////////
719
720 #include "SkFontHost.h"
721
722 class SkScalerContext_Empty : public SkScalerContext {
723 public:
SkScalerContext_Empty(const SkDescriptor * desc)724 SkScalerContext_Empty(const SkDescriptor* desc) : SkScalerContext(desc) {}
725
726 protected:
generateGlyphCount()727 virtual unsigned generateGlyphCount() {
728 return 0;
729 }
generateCharToGlyph(SkUnichar uni)730 virtual uint16_t generateCharToGlyph(SkUnichar uni) {
731 return 0;
732 }
generateAdvance(SkGlyph * glyph)733 virtual void generateAdvance(SkGlyph* glyph) {
734 glyph->zeroMetrics();
735 }
generateMetrics(SkGlyph * glyph)736 virtual void generateMetrics(SkGlyph* glyph) {
737 glyph->zeroMetrics();
738 }
generateImage(const SkGlyph & glyph)739 virtual void generateImage(const SkGlyph& glyph) {}
generatePath(const SkGlyph & glyph,SkPath * path)740 virtual void generatePath(const SkGlyph& glyph, SkPath* path) {}
generateFontMetrics(SkPaint::FontMetrics * mx,SkPaint::FontMetrics * my)741 virtual void generateFontMetrics(SkPaint::FontMetrics* mx,
742 SkPaint::FontMetrics* my) {
743 if (mx) {
744 sk_bzero(mx, sizeof(*mx));
745 }
746 if (my) {
747 sk_bzero(my, sizeof(*my));
748 }
749 }
750 };
751
752 extern SkScalerContext* SkCreateColorScalerContext(const SkDescriptor* desc);
753
Create(const SkDescriptor * desc)754 SkScalerContext* SkScalerContext::Create(const SkDescriptor* desc) {
755 SkScalerContext* c = NULL; //SkCreateColorScalerContext(desc);
756 if (NULL == c) {
757 c = SkFontHost::CreateScalerContext(desc);
758 }
759 if (NULL == c) {
760 c = SkNEW_ARGS(SkScalerContext_Empty, (desc));
761 }
762 return c;
763 }
764
765