3 * Copyright 2006 The Android Open Source Project
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
10 #include "SkScalerContext.h"
11 #include "SkColorPriv.h"
12 #include "SkDescriptor.h"
14 #include "SkFontHost.h"
16 #include "SkMaskFilter.h"
17 #include "SkMaskGamma.h"
18 #include "SkOrderedReadBuffer.h"
19 #include "SkOrderedWriteBuffer.h"
20 #include "SkPathEffect.h"
21 #include "SkRasterizer.h"
22 #include "SkRasterClip.h"
26 #ifdef SK_BUILD_FOR_ANDROID
27 #include "SkTypeface_android.h"
30 #define ComputeBWRowBytes(width) (((unsigned)(width) + 7) >> 3)
32 void SkGlyph::toMask(SkMask* mask) const {
35 mask->fImage = (uint8_t*)fImage;
36 mask->fBounds.set(fLeft, fTop, fLeft + fWidth, fTop + fHeight);
37 mask->fRowBytes = this->rowBytes();
38 mask->fFormat = static_cast<SkMask::Format>(fMaskFormat);
41 size_t SkGlyph::computeImageSize() const {
42 const size_t size = this->rowBytes() * fHeight;
44 switch (fMaskFormat) {
45 case SkMask::k3D_Format:
52 void SkGlyph::zeroMetrics() {
63 ///////////////////////////////////////////////////////////////////////////////
69 static SkFlattenable* load_flattenable(const SkDescriptor* desc, uint32_t tag,
70 SkFlattenable::Type ft) {
71 SkFlattenable* obj = NULL;
73 const void* data = desc->findEntry(tag, &len);
76 SkOrderedReadBuffer buffer(data, len);
77 obj = buffer.readFlattenable(ft);
78 SkASSERT(buffer.offset() == buffer.size());
83 SkScalerContext::SkScalerContext(SkTypeface* typeface, const SkDescriptor* desc)
84 : fRec(*static_cast<const Rec*>(desc->findEntry(kRec_SkDescriptorTag, NULL)))
87 , fTypeface(SkRef(typeface))
88 , fPathEffect(static_cast<SkPathEffect*>(load_flattenable(desc, kPathEffect_SkDescriptorTag,
89 SkFlattenable::kSkPathEffect_Type)))
90 , fMaskFilter(static_cast<SkMaskFilter*>(load_flattenable(desc, kMaskFilter_SkDescriptorTag,
91 SkFlattenable::kSkMaskFilter_Type)))
92 , fRasterizer(static_cast<SkRasterizer*>(load_flattenable(desc, kRasterizer_SkDescriptorTag,
93 SkFlattenable::kSkRasterizer_Type)))
94 // Initialize based on our settings. Subclasses can also force this.
95 , fGenerateImageFromPath(fRec.fFrameWidth > 0 || fPathEffect != NULL || fRasterizer != NULL)
99 , fPreBlend(fMaskFilter ? SkMaskGamma::PreBlend() : SkScalerContext::GetMaskPreBlend(fRec))
100 , fPreBlendForFilter(fMaskFilter ? SkScalerContext::GetMaskPreBlend(fRec)
101 : SkMaskGamma::PreBlend())
104 desc->assertChecksum();
105 SkDebugf("SkScalarContext checksum %x count %d length %d\n",
106 desc->getChecksum(), desc->getCount(), desc->getLength());
107 SkDebugf(" textsize %g prescale %g preskew %g post [%g %g %g %g]\n",
108 rec->fTextSize, rec->fPreScaleX, rec->fPreSkewX, rec->fPost2x2[0][0],
109 rec->fPost2x2[0][1], rec->fPost2x2[1][0], rec->fPost2x2[1][1]);
110 SkDebugf(" frame %g miter %g hints %d framefill %d format %d join %d\n",
111 rec->fFrameWidth, rec->fMiterLimit, rec->fHints, rec->fFrameAndFill,
112 rec->fMaskFormat, rec->fStrokeJoin);
113 SkDebugf(" pathEffect %x maskFilter %x\n",
114 desc->findEntry(kPathEffect_SkDescriptorTag, NULL),
115 desc->findEntry(kMaskFilter_SkDescriptorTag, NULL));
117 #ifdef SK_BUILD_FOR_ANDROID
119 const void* data = desc->findEntry(kAndroidOpts_SkDescriptorTag, &len);
121 SkOrderedReadBuffer buffer(data, len);
122 fPaintOptionsAndroid.unflatten(buffer);
123 SkASSERT(buffer.offset() == buffer.size());
128 SkScalerContext::~SkScalerContext() {
129 SkDELETE(fNextContext);
131 SkSafeUnref(fPathEffect);
132 SkSafeUnref(fMaskFilter);
133 SkSafeUnref(fRasterizer);
136 // Return the context associated with the next logical typeface, or NULL if
137 // there are no more entries in the fallback chain.
138 SkScalerContext* SkScalerContext::allocNextContext() const {
139 #ifdef SK_BUILD_FOR_ANDROID
140 SkTypeface* newFace = SkAndroidNextLogicalTypeface(fRec.fFontID,
142 fPaintOptionsAndroid);
147 SkAutoTUnref<SkTypeface> aur(newFace);
148 uint32_t newFontID = newFace->uniqueID();
150 SkOrderedWriteBuffer androidBuffer;
151 fPaintOptionsAndroid.flatten(androidBuffer);
153 SkAutoDescriptor ad(sizeof(fRec) + androidBuffer.size() + SkDescriptor::ComputeOverhead(2));
154 SkDescriptor* desc = ad.getDesc();
157 SkScalerContext::Rec* newRec =
158 (SkScalerContext::Rec*)desc->addEntry(kRec_SkDescriptorTag,
159 sizeof(fRec), &fRec);
160 androidBuffer.writeToMemory(desc->addEntry(kAndroidOpts_SkDescriptorTag,
161 androidBuffer.size(), NULL));
163 newRec->fFontID = newFontID;
164 desc->computeChecksum();
166 return newFace->createScalerContext(desc);
172 /* Return the next context, creating it if its not already created, but return
173 NULL if the fonthost says there are no more fonts to fallback to.
175 SkScalerContext* SkScalerContext::getNextContext() {
176 SkScalerContext* next = fNextContext;
177 // if next is null, then either it isn't cached yet, or we're at the
178 // end of our possible chain
180 next = this->allocNextContext();
184 // next's base is our base + our local count
185 next->setBaseGlyphCount(fBaseGlyphCount + this->getGlyphCount());
192 SkScalerContext* SkScalerContext::getGlyphContext(const SkGlyph& glyph) {
193 unsigned glyphID = glyph.getGlyphID();
194 SkScalerContext* ctx = this;
196 unsigned count = ctx->getGlyphCount();
197 if (glyphID < count) {
201 ctx = ctx->getNextContext();
203 // SkDebugf("--- no context for glyph %x\n", glyph.getGlyphID());
204 // just return the original context (this)
211 SkScalerContext* SkScalerContext::getContextFromChar(SkUnichar uni,
213 SkScalerContext* ctx = this;
215 const uint16_t glyph = ctx->generateCharToGlyph(uni);
217 if (NULL != glyphID) {
222 ctx = ctx->getNextContext();
230 #ifdef SK_BUILD_FOR_ANDROID
231 SkFontID SkScalerContext::findTypefaceIdForChar(SkUnichar uni) {
232 SkScalerContext* ctx = this->getContextFromChar(uni, NULL);
234 return ctx->fRec.fFontID;
240 /* This loops through all available fallback contexts (if needed) until it
241 finds some context that can handle the unichar and return it.
243 As this is somewhat expensive operation, it should only be done on the first
246 unsigned SkScalerContext::getBaseGlyphCount(SkUnichar uni) {
247 SkScalerContext* ctx = this->getContextFromChar(uni, NULL);
249 return ctx->fBaseGlyphCount;
251 SkDEBUGF(("--- no context for char %x\n", uni));
252 return this->fBaseGlyphCount;
257 /* This loops through all available fallback contexts (if needed) until it
258 finds some context that can handle the unichar. If all fail, returns 0
260 uint16_t SkScalerContext::charToGlyphID(SkUnichar uni) {
263 SkScalerContext* ctx = this->getContextFromChar(uni, &tempID);
265 return 0; // no more contexts, return missing glyph
267 // add the ctx's base, making glyphID unique for chain of contexts
268 unsigned glyphID = tempID + ctx->fBaseGlyphCount;
269 // check for overflow of 16bits, since our glyphID cannot exceed that
270 if (glyphID > 0xFFFF) {
273 return SkToU16(glyphID);
276 SkUnichar SkScalerContext::glyphIDToChar(uint16_t glyphID) {
277 SkScalerContext* ctx = this;
278 unsigned rangeEnd = 0;
280 unsigned rangeStart = rangeEnd;
282 rangeEnd += ctx->getGlyphCount();
283 if (rangeStart <= glyphID && glyphID < rangeEnd) {
284 return ctx->generateGlyphToChar(glyphID - rangeStart);
286 ctx = ctx->getNextContext();
287 } while (NULL != ctx);
291 void SkScalerContext::getAdvance(SkGlyph* glyph) {
292 // mark us as just having a valid advance
293 glyph->fMaskFormat = MASK_FORMAT_JUST_ADVANCE;
294 // we mark the format before making the call, in case the impl
295 // internally ends up calling its generateMetrics, which is OK
296 // albeit slower than strictly necessary
297 this->getGlyphContext(*glyph)->generateAdvance(glyph);
300 void SkScalerContext::getMetrics(SkGlyph* glyph) {
301 this->getGlyphContext(*glyph)->generateMetrics(glyph);
303 // for now we have separate cache entries for devkerning on and off
304 // in the future we might share caches, but make our measure/draw
305 // code make the distinction. Thus we zap the values if the caller
306 // has not asked for them.
307 if ((fRec.fFlags & SkScalerContext::kDevKernText_Flag) == 0) {
308 // no devkern, so zap the fields
309 glyph->fLsbDelta = glyph->fRsbDelta = 0;
312 // if either dimension is empty, zap the image bounds of the glyph
313 if (0 == glyph->fWidth || 0 == glyph->fHeight) {
318 glyph->fMaskFormat = 0;
322 if (fGenerateImageFromPath) {
323 SkPath devPath, fillPath;
324 SkMatrix fillToDevMatrix;
326 this->internalGetPath(*glyph, &fillPath, &devPath, &fillToDevMatrix);
331 if (fRasterizer->rasterize(fillPath, fillToDevMatrix, NULL,
333 SkMask::kJustComputeBounds_CreateMode)) {
334 glyph->fLeft = mask.fBounds.fLeft;
335 glyph->fTop = mask.fBounds.fTop;
336 glyph->fWidth = SkToU16(mask.fBounds.width());
337 glyph->fHeight = SkToU16(mask.fBounds.height());
344 devPath.getBounds().roundOut(&ir);
346 if (ir.isEmpty() || !ir.is16Bit()) {
349 glyph->fLeft = ir.fLeft;
350 glyph->fTop = ir.fTop;
351 glyph->fWidth = SkToU16(ir.width());
352 glyph->fHeight = SkToU16(ir.height());
354 if (glyph->fWidth > 0) {
355 switch (fRec.fMaskFormat) {
356 case SkMask::kLCD16_Format:
357 case SkMask::kLCD32_Format:
368 if (SkMask::kARGB32_Format != glyph->fMaskFormat) {
369 glyph->fMaskFormat = fRec.fMaskFormat;
372 // If we are going to create the mask, then we cannot keep the color
373 if ((fGenerateImageFromPath || fMaskFilter) &&
374 SkMask::kARGB32_Format == glyph->fMaskFormat) {
375 glyph->fMaskFormat = SkMask::kA8_Format;
383 fRec.getMatrixFrom2x2(&matrix);
385 src.fImage = NULL; // only want the bounds from the filter
386 if (fMaskFilter->filterMask(&dst, src, matrix, NULL)) {
387 if (dst.fBounds.isEmpty() || !dst.fBounds.is16Bit()) {
390 SkASSERT(dst.fImage == NULL);
391 glyph->fLeft = dst.fBounds.fLeft;
392 glyph->fTop = dst.fBounds.fTop;
393 glyph->fWidth = SkToU16(dst.fBounds.width());
394 glyph->fHeight = SkToU16(dst.fBounds.height());
395 glyph->fMaskFormat = dst.fFormat;
401 // draw nothing 'cause we failed
406 // put a valid value here, in case it was earlier set to
407 // MASK_FORMAT_JUST_ADVANCE
408 glyph->fMaskFormat = fRec.fMaskFormat;
411 #define SK_SHOW_TEXT_BLIT_COVERAGE 0
413 static void applyLUTToA8Mask(const SkMask& mask, const uint8_t* lut) {
414 uint8_t* SK_RESTRICT dst = (uint8_t*)mask.fImage;
415 unsigned rowBytes = mask.fRowBytes;
417 for (int y = mask.fBounds.height() - 1; y >= 0; --y) {
418 for (int x = mask.fBounds.width() - 1; x >= 0; --x) {
419 dst[x] = lut[dst[x]];
425 template<bool APPLY_PREBLEND>
426 static void pack4xHToLCD16(const SkBitmap& src, const SkMask& dst,
427 const SkMaskGamma::PreBlend& maskPreBlend) {
428 #define SAMPLES_PER_PIXEL 4
429 #define LCD_PER_PIXEL 3
430 SkASSERT(SkBitmap::kA8_Config == src.config());
431 SkASSERT(SkMask::kLCD16_Format == dst.fFormat);
433 const int sample_width = src.width();
434 const int height = src.height();
436 uint16_t* dstP = (uint16_t*)dst.fImage;
437 size_t dstRB = dst.fRowBytes;
438 // An N tap FIR is defined by
439 // out[n] = coeff[0]*x[n] + coeff[1]*x[n-1] + ... + coeff[N]*x[n-N]
441 // out[n] = sum(i, 0, N, coeff[i]*x[n-i])
443 // The strategy is to use one FIR (different coefficients) for each of r, g, and b.
444 // This means using every 4th FIR output value of each FIR and discarding the rest.
445 // The FIRs are aligned, and the coefficients reach 5 samples to each side of their 'center'.
446 // (For r and b this is technically incorrect, but the coeffs outside round to zero anyway.)
448 // These are in some fixed point repesentation.
449 // Adding up to more than one simulates ink spread.
450 // For implementation reasons, these should never add up to more than two.
452 // Coefficients determined by a gausian where 5 samples = 3 std deviations (0x110 'contrast').
453 // Calculated using tools/generate_fir_coeff.py
454 // With this one almost no fringing is ever seen, but it is imperceptibly blurry.
455 // The lcd smoothed text is almost imperceptibly different from gray,
456 // but is still sharper on small stems and small rounded corners than gray.
457 // This also seems to be about as wide as one can get and only have a three pixel kernel.
458 // TODO: caculate these at runtime so parameters can be adjusted (esp contrast).
459 static const unsigned int coefficients[LCD_PER_PIXEL][SAMPLES_PER_PIXEL*3] = {
460 //The red subpixel is centered inside the first sample (at 1/6 pixel), and is shifted.
461 { 0x03, 0x0b, 0x1c, 0x33, 0x40, 0x39, 0x24, 0x10, 0x05, 0x01, 0x00, 0x00, },
462 //The green subpixel is centered between two samples (at 1/2 pixel), so is symetric
463 { 0x00, 0x02, 0x08, 0x16, 0x2b, 0x3d, 0x3d, 0x2b, 0x16, 0x08, 0x02, 0x00, },
464 //The blue subpixel is centered inside the last sample (at 5/6 pixel), and is shifted.
465 { 0x00, 0x00, 0x01, 0x05, 0x10, 0x24, 0x39, 0x40, 0x33, 0x1c, 0x0b, 0x03, },
468 for (int y = 0; y < height; ++y) {
469 const uint8_t* srcP = src.getAddr8(0, y);
471 // TODO: this fir filter implementation is straight forward, but slow.
472 // It should be possible to make it much faster.
473 for (int sample_x = -4, pixel_x = 0; sample_x < sample_width + 4; sample_x += 4, ++pixel_x) {
474 int fir[LCD_PER_PIXEL] = { 0 };
475 for (int sample_index = SkMax32(0, sample_x - 4), coeff_index = sample_index - (sample_x - 4)
476 ; sample_index < SkMin32(sample_x + 8, sample_width)
477 ; ++sample_index, ++coeff_index)
479 int sample_value = srcP[sample_index];
480 for (int subpxl_index = 0; subpxl_index < LCD_PER_PIXEL; ++subpxl_index) {
481 fir[subpxl_index] += coefficients[subpxl_index][coeff_index] * sample_value;
484 for (int subpxl_index = 0; subpxl_index < LCD_PER_PIXEL; ++subpxl_index) {
485 fir[subpxl_index] /= 0x100;
486 fir[subpxl_index] = SkMin32(fir[subpxl_index], 255);
489 U8CPU r = sk_apply_lut_if<APPLY_PREBLEND>(fir[0], maskPreBlend.fR);
490 U8CPU g = sk_apply_lut_if<APPLY_PREBLEND>(fir[1], maskPreBlend.fG);
491 U8CPU b = sk_apply_lut_if<APPLY_PREBLEND>(fir[2], maskPreBlend.fB);
492 #if SK_SHOW_TEXT_BLIT_COVERAGE
493 r = SkMax32(r, 10); g = SkMax32(g, 10); b = SkMax32(b, 10);
495 dstP[pixel_x] = SkPack888ToRGB16(r, g, b);
497 dstP = (uint16_t*)((char*)dstP + dstRB);
501 template<bool APPLY_PREBLEND>
502 static void pack4xHToLCD32(const SkBitmap& src, const SkMask& dst,
503 const SkMaskGamma::PreBlend& maskPreBlend) {
504 SkASSERT(SkBitmap::kA8_Config == src.config());
505 SkASSERT(SkMask::kLCD32_Format == dst.fFormat);
507 const int width = dst.fBounds.width();
508 const int height = dst.fBounds.height();
509 SkPMColor* dstP = (SkPMColor*)dst.fImage;
510 size_t dstRB = dst.fRowBytes;
512 for (int y = 0; y < height; ++y) {
513 const uint8_t* srcP = src.getAddr8(0, y);
515 // TODO: need to use fir filter here as well.
516 for (int x = 0; x < width; ++x) {
517 U8CPU r = sk_apply_lut_if<APPLY_PREBLEND>(*srcP++, maskPreBlend.fR);
518 U8CPU g = sk_apply_lut_if<APPLY_PREBLEND>(*srcP++, maskPreBlend.fG);
519 U8CPU b = sk_apply_lut_if<APPLY_PREBLEND>(*srcP++, maskPreBlend.fB);
520 dstP[x] = SkPackARGB32(0xFF, r, g, b);
522 dstP = (SkPMColor*)((char*)dstP + dstRB);
526 static inline int convert_8_to_1(unsigned byte) {
527 SkASSERT(byte <= 0xFF);
531 static uint8_t pack_8_to_1(const uint8_t alpha[8]) {
533 for (int i = 0; i < 8; ++i) {
535 bits |= convert_8_to_1(alpha[i]);
540 static void packA8ToA1(const SkMask& mask, const uint8_t* src, size_t srcRB) {
541 const int height = mask.fBounds.height();
542 const int width = mask.fBounds.width();
543 const int octs = width >> 3;
544 const int leftOverBits = width & 7;
546 uint8_t* dst = mask.fImage;
547 const int dstPad = mask.fRowBytes - SkAlign8(width)/8;
548 SkASSERT(dstPad >= 0);
550 const int srcPad = srcRB - width;
551 SkASSERT(srcPad >= 0);
553 for (int y = 0; y < height; ++y) {
554 for (int i = 0; i < octs; ++i) {
555 *dst++ = pack_8_to_1(src);
558 if (leftOverBits > 0) {
561 for (int i = 0; i < leftOverBits; ++i, --shift) {
562 bits |= convert_8_to_1(*src++) << shift;
571 static void generateMask(const SkMask& mask, const SkPath& path,
572 const SkMaskGamma::PreBlend& maskPreBlend) {
575 int srcW = mask.fBounds.width();
576 int srcH = mask.fBounds.height();
579 int dstRB = mask.fRowBytes;
582 matrix.setTranslate(-SkIntToScalar(mask.fBounds.fLeft),
583 -SkIntToScalar(mask.fBounds.fTop));
585 SkBitmap::Config config = SkBitmap::kA8_Config;
586 paint.setAntiAlias(SkMask::kBW_Format != mask.fFormat);
587 switch (mask.fFormat) {
588 case SkMask::kBW_Format:
589 dstRB = 0; // signals we need a copy
591 case SkMask::kA8_Format:
593 case SkMask::kLCD16_Format:
594 case SkMask::kLCD32_Format:
595 // TODO: trigger off LCD orientation
597 matrix.setTranslate(-SkIntToScalar(mask.fBounds.fLeft + 1),
598 -SkIntToScalar(mask.fBounds.fTop));
599 matrix.postScale(SkIntToScalar(4), SK_Scalar1);
600 dstRB = 0; // signals we need a copy
603 SkDEBUGFAIL("unexpected mask format");
607 clip.setRect(SkIRect::MakeWH(dstW, dstH));
610 bm.setConfig(config, dstW, dstH, dstRB);
613 if (!bm.allocPixels()) {
614 // can't allocate offscreen, so empty the mask and return
615 sk_bzero(mask.fImage, mask.computeImageSize());
620 bm.setPixels(mask.fImage);
622 sk_bzero(bm.getPixels(), bm.getSafeSize());
626 draw.fClip = &clip.bwRgn();
627 draw.fMatrix = &matrix;
629 draw.drawPath(path, paint);
631 switch (mask.fFormat) {
632 case SkMask::kBW_Format:
633 packA8ToA1(mask, bm.getAddr8(0, 0), bm.rowBytes());
635 case SkMask::kA8_Format:
636 if (maskPreBlend.isApplicable()) {
637 applyLUTToA8Mask(mask, maskPreBlend.fG);
640 case SkMask::kLCD16_Format:
641 if (maskPreBlend.isApplicable()) {
642 pack4xHToLCD16<true>(bm, mask, maskPreBlend);
644 pack4xHToLCD16<false>(bm, mask, maskPreBlend);
647 case SkMask::kLCD32_Format:
648 if (maskPreBlend.isApplicable()) {
649 pack4xHToLCD32<true>(bm, mask, maskPreBlend);
651 pack4xHToLCD32<false>(bm, mask, maskPreBlend);
659 static void extract_alpha(const SkMask& dst,
660 const SkPMColor* srcRow, size_t srcRB) {
661 int width = dst.fBounds.width();
662 int height = dst.fBounds.height();
663 int dstRB = dst.fRowBytes;
664 uint8_t* dstRow = dst.fImage;
666 for (int y = 0; y < height; ++y) {
667 for (int x = 0; x < width; ++x) {
668 dstRow[x] = SkGetPackedA32(srcRow[x]);
670 // zero any padding on each row
671 for (int x = width; x < dstRB; ++x) {
675 srcRow = (const SkPMColor*)((const char*)srcRow + srcRB);
679 void SkScalerContext::getImage(const SkGlyph& origGlyph) {
680 const SkGlyph* glyph = &origGlyph;
683 // in case we need to call generateImage on a mask-format that is different
684 // (i.e. larger) than what our caller allocated by looking at origGlyph.
685 SkAutoMalloc tmpGlyphImageStorage;
687 // If we are going to draw-from-path, then we cannot generate color, since
688 // the path only makes a mask. This case should have been caught up in
689 // generateMetrics().
690 SkASSERT(!fGenerateImageFromPath ||
691 SkMask::kARGB32_Format != origGlyph.fMaskFormat);
693 if (fMaskFilter) { // restore the prefilter bounds
694 tmpGlyph.init(origGlyph.fID);
696 // need the original bounds, sans our maskfilter
697 SkMaskFilter* mf = fMaskFilter;
698 fMaskFilter = NULL; // temp disable
699 this->getMetrics(&tmpGlyph);
700 fMaskFilter = mf; // restore
702 // we need the prefilter bounds to be <= filter bounds
703 SkASSERT(tmpGlyph.fWidth <= origGlyph.fWidth);
704 SkASSERT(tmpGlyph.fHeight <= origGlyph.fHeight);
706 if (tmpGlyph.fMaskFormat == origGlyph.fMaskFormat) {
707 tmpGlyph.fImage = origGlyph.fImage;
709 tmpGlyphImageStorage.reset(tmpGlyph.computeImageSize());
710 tmpGlyph.fImage = tmpGlyphImageStorage.get();
715 if (fGenerateImageFromPath) {
716 SkPath devPath, fillPath;
717 SkMatrix fillToDevMatrix;
720 this->internalGetPath(*glyph, &fillPath, &devPath, &fillToDevMatrix);
721 glyph->toMask(&mask);
724 mask.fFormat = SkMask::kA8_Format;
725 sk_bzero(glyph->fImage, mask.computeImageSize());
727 if (!fRasterizer->rasterize(fillPath, fillToDevMatrix, NULL,
729 SkMask::kJustRenderImage_CreateMode)) {
732 if (fPreBlend.isApplicable()) {
733 applyLUTToA8Mask(mask, fPreBlend.fG);
736 SkASSERT(SkMask::kARGB32_Format != mask.fFormat);
737 generateMask(mask, devPath, fPreBlend);
740 this->getGlyphContext(*glyph)->generateImage(*glyph);
747 // the src glyph image shouldn't be 3D
748 SkASSERT(SkMask::k3D_Format != glyph->fMaskFormat);
750 SkAutoSMalloc<32*32> a8storage;
751 glyph->toMask(&srcM);
752 if (SkMask::kARGB32_Format == srcM.fFormat) {
753 // now we need to extract the alpha-channel from the glyph's image
754 // and copy it into a temp buffer, and then point srcM at that temp.
755 srcM.fFormat = SkMask::kA8_Format;
756 srcM.fRowBytes = SkAlign4(srcM.fBounds.width());
757 size_t size = srcM.computeImageSize();
758 a8storage.reset(size);
759 srcM.fImage = (uint8_t*)a8storage.get();
761 (const SkPMColor*)glyph->fImage, glyph->rowBytes());
764 fRec.getMatrixFrom2x2(&matrix);
766 if (fMaskFilter->filterMask(&dstM, srcM, matrix, NULL)) {
767 int width = SkFastMin32(origGlyph.fWidth, dstM.fBounds.width());
768 int height = SkFastMin32(origGlyph.fHeight, dstM.fBounds.height());
769 int dstRB = origGlyph.rowBytes();
770 int srcRB = dstM.fRowBytes;
772 const uint8_t* src = (const uint8_t*)dstM.fImage;
773 uint8_t* dst = (uint8_t*)origGlyph.fImage;
775 if (SkMask::k3D_Format == dstM.fFormat) {
776 // we have to copy 3 times as much
780 // clean out our glyph, since it may be larger than dstM
781 //sk_bzero(dst, height * dstRB);
783 while (--height >= 0) {
784 memcpy(dst, src, width);
788 SkMask::FreeImage(dstM.fImage);
790 if (fPreBlendForFilter.isApplicable()) {
791 applyLUTToA8Mask(srcM, fPreBlendForFilter.fG);
797 void SkScalerContext::getPath(const SkGlyph& glyph, SkPath* path) {
798 this->internalGetPath(glyph, NULL, path, NULL);
801 void SkScalerContext::getFontMetrics(SkPaint::FontMetrics* fm) {
802 // All of this complexity should go away when we change generateFontMetrics
803 // to just take one parameter (since it knows if it is vertical or not)
804 SkPaint::FontMetrics* mx = NULL;
805 SkPaint::FontMetrics* my = NULL;
806 if (fRec.fFlags & kVertical_Flag) {
811 this->generateFontMetrics(mx, my);
814 SkUnichar SkScalerContext::generateGlyphToChar(uint16_t glyph) {
818 ///////////////////////////////////////////////////////////////////////////////
820 void SkScalerContext::internalGetPath(const SkGlyph& glyph, SkPath* fillPath,
821 SkPath* devPath, SkMatrix* fillToDevMatrix) {
824 this->getGlyphContext(glyph)->generatePath(glyph, &path);
826 if (fRec.fFlags & SkScalerContext::kSubpixelPositioning_Flag) {
827 SkFixed dx = glyph.getSubXFixed();
828 SkFixed dy = glyph.getSubYFixed();
830 path.offset(SkFixedToScalar(dx), SkFixedToScalar(dy));
834 if (fRec.fFrameWidth > 0 || fPathEffect != NULL) {
835 // need the path in user-space, with only the point-size applied
836 // so that our stroking and effects will operate the same way they
837 // would if the user had extracted the path themself, and then
840 SkMatrix matrix, inverse;
842 fRec.getMatrixFrom2x2(&matrix);
843 if (!matrix.invert(&inverse)) {
844 // assume fillPath and devPath are already empty.
847 path.transform(inverse, &localPath);
848 // now localPath is only affected by the paint settings, and not the canvas matrix
850 SkStrokeRec rec(SkStrokeRec::kFill_InitStyle);
852 if (fRec.fFrameWidth > 0) {
853 rec.setStrokeStyle(fRec.fFrameWidth,
854 SkToBool(fRec.fFlags & kFrameAndFill_Flag));
855 // glyphs are always closed contours, so cap type is ignored,
856 // so we just pass something.
857 rec.setStrokeParams(SkPaint::kButt_Cap,
858 (SkPaint::Join)fRec.fStrokeJoin,
864 if (fPathEffect->filterPath(&effectPath, localPath, &rec, NULL)) {
865 localPath.swap(effectPath);
869 if (rec.needToApply()) {
871 if (rec.applyToPath(&strokePath, localPath)) {
872 localPath.swap(strokePath);
876 // now return stuff to the caller
877 if (fillToDevMatrix) {
878 *fillToDevMatrix = matrix;
881 localPath.transform(matrix, devPath);
884 fillPath->swap(localPath);
886 } else { // nothing tricky to do
887 if (fillToDevMatrix) {
888 fillToDevMatrix->reset();
891 if (fillPath == NULL) {
899 fillPath->swap(path);
904 devPath->updateBoundsCache();
907 fillPath->updateBoundsCache();
912 void SkScalerContextRec::getMatrixFrom2x2(SkMatrix* dst) const {
913 dst->setAll(fPost2x2[0][0], fPost2x2[0][1], 0,
914 fPost2x2[1][0], fPost2x2[1][1], 0,
915 0, 0, SkScalarToPersp(SK_Scalar1));
918 void SkScalerContextRec::getLocalMatrix(SkMatrix* m) const {
919 SkPaint::SetTextMatrix(m, fTextSize, fPreScaleX, fPreSkewX);
922 void SkScalerContextRec::getSingleMatrix(SkMatrix* m) const {
923 this->getLocalMatrix(m);
925 // now concat the device matrix
926 SkMatrix deviceMatrix;
927 this->getMatrixFrom2x2(&deviceMatrix);
928 m->postConcat(deviceMatrix);
931 SkAxisAlignment SkComputeAxisAlignmentForHText(const SkMatrix& matrix) {
932 SkASSERT(!matrix.hasPerspective());
934 if (0 == matrix[SkMatrix::kMSkewY]) {
935 return kX_SkAxisAlignment;
937 if (0 == matrix[SkMatrix::kMScaleX]) {
938 return kY_SkAxisAlignment;
940 return kNone_SkAxisAlignment;
943 ///////////////////////////////////////////////////////////////////////////////
945 #include "SkFontHost.h"
947 class SkScalerContext_Empty : public SkScalerContext {
949 SkScalerContext_Empty(SkTypeface* face, const SkDescriptor* desc)
950 : SkScalerContext(face, desc) {}
953 virtual unsigned generateGlyphCount() SK_OVERRIDE {
956 virtual uint16_t generateCharToGlyph(SkUnichar uni) SK_OVERRIDE {
959 virtual void generateAdvance(SkGlyph* glyph) SK_OVERRIDE {
960 glyph->zeroMetrics();
962 virtual void generateMetrics(SkGlyph* glyph) SK_OVERRIDE {
963 glyph->zeroMetrics();
965 virtual void generateImage(const SkGlyph& glyph) SK_OVERRIDE {}
966 virtual void generatePath(const SkGlyph& glyph, SkPath* path) SK_OVERRIDE {}
967 virtual void generateFontMetrics(SkPaint::FontMetrics* mx,
968 SkPaint::FontMetrics* my) SK_OVERRIDE {
970 sk_bzero(mx, sizeof(*mx));
973 sk_bzero(my, sizeof(*my));
978 extern SkScalerContext* SkCreateColorScalerContext(const SkDescriptor* desc);
980 SkScalerContext* SkTypeface::createScalerContext(const SkDescriptor* desc,
981 bool allowFailure) const {
982 SkScalerContext* c = this->onCreateScalerContext(desc);
984 if (!c && !allowFailure) {
985 c = SkNEW_ARGS(SkScalerContext_Empty,
986 (const_cast<SkTypeface*>(this), desc));