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