• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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