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 "SkReadBuffer.h"
19 #include "SkWriteBuffer.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 SkReadBuffer 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("SkScalerContext 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 SkReadBuffer 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 SkWriteBuffer androidBuffer;
151 fPaintOptionsAndroid.flatten(androidBuffer);
153 SkAutoDescriptor ad(sizeof(fRec) + androidBuffer.bytesWritten()
154 + SkDescriptor::ComputeOverhead(2));
155 SkDescriptor* desc = ad.getDesc();
158 SkScalerContext::Rec* newRec =
159 (SkScalerContext::Rec*)desc->addEntry(kRec_SkDescriptorTag,
160 sizeof(fRec), &fRec);
161 androidBuffer.writeToMemory(desc->addEntry(kAndroidOpts_SkDescriptorTag,
162 androidBuffer.bytesWritten(), NULL));
164 newRec->fFontID = newFontID;
165 desc->computeChecksum();
167 return newFace->createScalerContext(desc);
173 /* Return the next context, creating it if its not already created, but return
174 NULL if the fonthost says there are no more fonts to fallback to.
176 SkScalerContext* SkScalerContext::getNextContext() {
177 SkScalerContext* next = fNextContext;
178 // if next is null, then either it isn't cached yet, or we're at the
179 // end of our possible chain
181 next = this->allocNextContext();
185 // next's base is our base + our local count
186 next->setBaseGlyphCount(fBaseGlyphCount + this->getGlyphCount());
193 SkScalerContext* SkScalerContext::getGlyphContext(const SkGlyph& glyph) {
194 unsigned glyphID = glyph.getGlyphID();
195 SkScalerContext* ctx = this;
197 unsigned count = ctx->getGlyphCount();
198 if (glyphID < count) {
202 ctx = ctx->getNextContext();
204 // SkDebugf("--- no context for glyph %x\n", glyph.getGlyphID());
205 // just return the original context (this)
212 SkScalerContext* SkScalerContext::getContextFromChar(SkUnichar uni,
214 SkScalerContext* ctx = this;
216 const uint16_t glyph = ctx->generateCharToGlyph(uni);
218 if (NULL != glyphID) {
223 ctx = ctx->getNextContext();
231 #ifdef SK_BUILD_FOR_ANDROID
232 SkFontID SkScalerContext::findTypefaceIdForChar(SkUnichar uni) {
233 SkScalerContext* ctx = this->getContextFromChar(uni, NULL);
235 return ctx->fRec.fFontID;
241 /* This loops through all available fallback contexts (if needed) until it
242 finds some context that can handle the unichar and return it.
244 As this is somewhat expensive operation, it should only be done on the first
247 unsigned SkScalerContext::getBaseGlyphCount(SkUnichar uni) {
248 SkScalerContext* ctx = this->getContextFromChar(uni, NULL);
250 return ctx->fBaseGlyphCount;
252 SkDEBUGF(("--- no context for char %x\n", uni));
253 return this->fBaseGlyphCount;
258 /* This loops through all available fallback contexts (if needed) until it
259 finds some context that can handle the unichar. If all fail, returns 0
261 uint16_t SkScalerContext::charToGlyphID(SkUnichar uni) {
264 SkScalerContext* ctx = this->getContextFromChar(uni, &tempID);
266 return 0; // no more contexts, return missing glyph
268 // add the ctx's base, making glyphID unique for chain of contexts
269 unsigned glyphID = tempID + ctx->fBaseGlyphCount;
270 // check for overflow of 16bits, since our glyphID cannot exceed that
271 if (glyphID > 0xFFFF) {
274 return SkToU16(glyphID);
277 SkUnichar SkScalerContext::glyphIDToChar(uint16_t glyphID) {
278 SkScalerContext* ctx = this;
279 unsigned rangeEnd = 0;
281 unsigned rangeStart = rangeEnd;
283 rangeEnd += ctx->getGlyphCount();
284 if (rangeStart <= glyphID && glyphID < rangeEnd) {
285 return ctx->generateGlyphToChar(glyphID - rangeStart);
287 ctx = ctx->getNextContext();
288 } while (NULL != ctx);
292 void SkScalerContext::getAdvance(SkGlyph* glyph) {
293 // mark us as just having a valid advance
294 glyph->fMaskFormat = MASK_FORMAT_JUST_ADVANCE;
295 // we mark the format before making the call, in case the impl
296 // internally ends up calling its generateMetrics, which is OK
297 // albeit slower than strictly necessary
298 this->getGlyphContext(*glyph)->generateAdvance(glyph);
301 void SkScalerContext::getMetrics(SkGlyph* glyph) {
302 this->getGlyphContext(*glyph)->generateMetrics(glyph);
304 // for now we have separate cache entries for devkerning on and off
305 // in the future we might share caches, but make our measure/draw
306 // code make the distinction. Thus we zap the values if the caller
307 // has not asked for them.
308 if ((fRec.fFlags & SkScalerContext::kDevKernText_Flag) == 0) {
309 // no devkern, so zap the fields
310 glyph->fLsbDelta = glyph->fRsbDelta = 0;
313 // if either dimension is empty, zap the image bounds of the glyph
314 if (0 == glyph->fWidth || 0 == glyph->fHeight) {
319 glyph->fMaskFormat = 0;
323 if (fGenerateImageFromPath) {
324 SkPath devPath, fillPath;
325 SkMatrix fillToDevMatrix;
327 this->internalGetPath(*glyph, &fillPath, &devPath, &fillToDevMatrix);
332 if (fRasterizer->rasterize(fillPath, fillToDevMatrix, NULL,
334 SkMask::kJustComputeBounds_CreateMode)) {
335 glyph->fLeft = mask.fBounds.fLeft;
336 glyph->fTop = mask.fBounds.fTop;
337 glyph->fWidth = SkToU16(mask.fBounds.width());
338 glyph->fHeight = SkToU16(mask.fBounds.height());
345 devPath.getBounds().roundOut(&ir);
347 if (ir.isEmpty() || !ir.is16Bit()) {
350 glyph->fLeft = ir.fLeft;
351 glyph->fTop = ir.fTop;
352 glyph->fWidth = SkToU16(ir.width());
353 glyph->fHeight = SkToU16(ir.height());
355 if (glyph->fWidth > 0) {
356 switch (fRec.fMaskFormat) {
357 case SkMask::kLCD16_Format:
358 case SkMask::kLCD32_Format:
369 if (SkMask::kARGB32_Format != glyph->fMaskFormat) {
370 glyph->fMaskFormat = fRec.fMaskFormat;
373 // If we are going to create the mask, then we cannot keep the color
374 if ((fGenerateImageFromPath || fMaskFilter) &&
375 SkMask::kARGB32_Format == glyph->fMaskFormat) {
376 glyph->fMaskFormat = SkMask::kA8_Format;
384 fRec.getMatrixFrom2x2(&matrix);
386 src.fImage = NULL; // only want the bounds from the filter
387 if (fMaskFilter->filterMask(&dst, src, matrix, NULL)) {
388 if (dst.fBounds.isEmpty() || !dst.fBounds.is16Bit()) {
391 SkASSERT(dst.fImage == NULL);
392 glyph->fLeft = dst.fBounds.fLeft;
393 glyph->fTop = dst.fBounds.fTop;
394 glyph->fWidth = SkToU16(dst.fBounds.width());
395 glyph->fHeight = SkToU16(dst.fBounds.height());
396 glyph->fMaskFormat = dst.fFormat;
402 // draw nothing 'cause we failed
407 // put a valid value here, in case it was earlier set to
408 // MASK_FORMAT_JUST_ADVANCE
409 glyph->fMaskFormat = fRec.fMaskFormat;
412 #define SK_SHOW_TEXT_BLIT_COVERAGE 0
414 static void applyLUTToA8Mask(const SkMask& mask, const uint8_t* lut) {
415 uint8_t* SK_RESTRICT dst = (uint8_t*)mask.fImage;
416 unsigned rowBytes = mask.fRowBytes;
418 for (int y = mask.fBounds.height() - 1; y >= 0; --y) {
419 for (int x = mask.fBounds.width() - 1; x >= 0; --x) {
420 dst[x] = lut[dst[x]];
426 template<bool APPLY_PREBLEND>
427 static void pack4xHToLCD16(const SkBitmap& src, const SkMask& dst,
428 const SkMaskGamma::PreBlend& maskPreBlend) {
429 #define SAMPLES_PER_PIXEL 4
430 #define LCD_PER_PIXEL 3
431 SkASSERT(kAlpha_8_SkColorType == src.colorType());
432 SkASSERT(SkMask::kLCD16_Format == dst.fFormat);
434 const int sample_width = src.width();
435 const int height = src.height();
437 uint16_t* dstP = (uint16_t*)dst.fImage;
438 size_t dstRB = dst.fRowBytes;
439 // An N tap FIR is defined by
440 // out[n] = coeff[0]*x[n] + coeff[1]*x[n-1] + ... + coeff[N]*x[n-N]
442 // out[n] = sum(i, 0, N, coeff[i]*x[n-i])
444 // The strategy is to use one FIR (different coefficients) for each of r, g, and b.
445 // This means using every 4th FIR output value of each FIR and discarding the rest.
446 // The FIRs are aligned, and the coefficients reach 5 samples to each side of their 'center'.
447 // (For r and b this is technically incorrect, but the coeffs outside round to zero anyway.)
449 // These are in some fixed point repesentation.
450 // Adding up to more than one simulates ink spread.
451 // For implementation reasons, these should never add up to more than two.
453 // Coefficients determined by a gausian where 5 samples = 3 std deviations (0x110 'contrast').
454 // Calculated using tools/generate_fir_coeff.py
455 // With this one almost no fringing is ever seen, but it is imperceptibly blurry.
456 // The lcd smoothed text is almost imperceptibly different from gray,
457 // but is still sharper on small stems and small rounded corners than gray.
458 // This also seems to be about as wide as one can get and only have a three pixel kernel.
459 // TODO: caculate these at runtime so parameters can be adjusted (esp contrast).
460 static const unsigned int coefficients[LCD_PER_PIXEL][SAMPLES_PER_PIXEL*3] = {
461 //The red subpixel is centered inside the first sample (at 1/6 pixel), and is shifted.
462 { 0x03, 0x0b, 0x1c, 0x33, 0x40, 0x39, 0x24, 0x10, 0x05, 0x01, 0x00, 0x00, },
463 //The green subpixel is centered between two samples (at 1/2 pixel), so is symetric
464 { 0x00, 0x02, 0x08, 0x16, 0x2b, 0x3d, 0x3d, 0x2b, 0x16, 0x08, 0x02, 0x00, },
465 //The blue subpixel is centered inside the last sample (at 5/6 pixel), and is shifted.
466 { 0x00, 0x00, 0x01, 0x05, 0x10, 0x24, 0x39, 0x40, 0x33, 0x1c, 0x0b, 0x03, },
469 for (int y = 0; y < height; ++y) {
470 const uint8_t* srcP = src.getAddr8(0, y);
472 // TODO: this fir filter implementation is straight forward, but slow.
473 // It should be possible to make it much faster.
474 for (int sample_x = -4, pixel_x = 0; sample_x < sample_width + 4; sample_x += 4, ++pixel_x) {
475 int fir[LCD_PER_PIXEL] = { 0 };
476 for (int sample_index = SkMax32(0, sample_x - 4), coeff_index = sample_index - (sample_x - 4)
477 ; sample_index < SkMin32(sample_x + 8, sample_width)
478 ; ++sample_index, ++coeff_index)
480 int sample_value = srcP[sample_index];
481 for (int subpxl_index = 0; subpxl_index < LCD_PER_PIXEL; ++subpxl_index) {
482 fir[subpxl_index] += coefficients[subpxl_index][coeff_index] * sample_value;
485 for (int subpxl_index = 0; subpxl_index < LCD_PER_PIXEL; ++subpxl_index) {
486 fir[subpxl_index] /= 0x100;
487 fir[subpxl_index] = SkMin32(fir[subpxl_index], 255);
490 U8CPU r = sk_apply_lut_if<APPLY_PREBLEND>(fir[0], maskPreBlend.fR);
491 U8CPU g = sk_apply_lut_if<APPLY_PREBLEND>(fir[1], maskPreBlend.fG);
492 U8CPU b = sk_apply_lut_if<APPLY_PREBLEND>(fir[2], maskPreBlend.fB);
493 #if SK_SHOW_TEXT_BLIT_COVERAGE
494 r = SkMax32(r, 10); g = SkMax32(g, 10); b = SkMax32(b, 10);
496 dstP[pixel_x] = SkPack888ToRGB16(r, g, b);
498 dstP = (uint16_t*)((char*)dstP + dstRB);
502 template<bool APPLY_PREBLEND>
503 static void pack4xHToLCD32(const SkBitmap& src, const SkMask& dst,
504 const SkMaskGamma::PreBlend& maskPreBlend) {
505 SkASSERT(kAlpha_8_SkColorType == src.colorType());
506 SkASSERT(SkMask::kLCD32_Format == dst.fFormat);
508 const int width = dst.fBounds.width();
509 const int height = dst.fBounds.height();
510 SkPMColor* dstP = (SkPMColor*)dst.fImage;
511 size_t dstRB = dst.fRowBytes;
513 for (int y = 0; y < height; ++y) {
514 const uint8_t* srcP = src.getAddr8(0, y);
516 // TODO: need to use fir filter here as well.
517 for (int x = 0; x < width; ++x) {
518 U8CPU r = sk_apply_lut_if<APPLY_PREBLEND>(*srcP++, maskPreBlend.fR);
519 U8CPU g = sk_apply_lut_if<APPLY_PREBLEND>(*srcP++, maskPreBlend.fG);
520 U8CPU b = sk_apply_lut_if<APPLY_PREBLEND>(*srcP++, maskPreBlend.fB);
521 dstP[x] = SkPackARGB32(0xFF, r, g, b);
523 dstP = (SkPMColor*)((char*)dstP + dstRB);
527 static inline int convert_8_to_1(unsigned byte) {
528 SkASSERT(byte <= 0xFF);
532 static uint8_t pack_8_to_1(const uint8_t alpha[8]) {
534 for (int i = 0; i < 8; ++i) {
536 bits |= convert_8_to_1(alpha[i]);
541 static void packA8ToA1(const SkMask& mask, const uint8_t* src, size_t srcRB) {
542 const int height = mask.fBounds.height();
543 const int width = mask.fBounds.width();
544 const int octs = width >> 3;
545 const int leftOverBits = width & 7;
547 uint8_t* dst = mask.fImage;
548 const int dstPad = mask.fRowBytes - SkAlign8(width)/8;
549 SkASSERT(dstPad >= 0);
551 const int srcPad = srcRB - width;
552 SkASSERT(srcPad >= 0);
554 for (int y = 0; y < height; ++y) {
555 for (int i = 0; i < octs; ++i) {
556 *dst++ = pack_8_to_1(src);
559 if (leftOverBits > 0) {
562 for (int i = 0; i < leftOverBits; ++i, --shift) {
563 bits |= convert_8_to_1(*src++) << shift;
572 static void generateMask(const SkMask& mask, const SkPath& path,
573 const SkMaskGamma::PreBlend& maskPreBlend) {
576 int srcW = mask.fBounds.width();
577 int srcH = mask.fBounds.height();
580 int dstRB = mask.fRowBytes;
583 matrix.setTranslate(-SkIntToScalar(mask.fBounds.fLeft),
584 -SkIntToScalar(mask.fBounds.fTop));
586 SkBitmap::Config config = SkBitmap::kA8_Config;
587 paint.setAntiAlias(SkMask::kBW_Format != mask.fFormat);
588 switch (mask.fFormat) {
589 case SkMask::kBW_Format:
590 dstRB = 0; // signals we need a copy
592 case SkMask::kA8_Format:
594 case SkMask::kLCD16_Format:
595 case SkMask::kLCD32_Format:
596 // TODO: trigger off LCD orientation
598 matrix.setTranslate(-SkIntToScalar(mask.fBounds.fLeft + 1),
599 -SkIntToScalar(mask.fBounds.fTop));
600 matrix.postScale(SkIntToScalar(4), SK_Scalar1);
601 dstRB = 0; // signals we need a copy
604 SkDEBUGFAIL("unexpected mask format");
608 clip.setRect(SkIRect::MakeWH(dstW, dstH));
611 bm.setConfig(config, dstW, dstH, dstRB);
614 if (!bm.allocPixels()) {
615 // can't allocate offscreen, so empty the mask and return
616 sk_bzero(mask.fImage, mask.computeImageSize());
621 bm.setPixels(mask.fImage);
623 sk_bzero(bm.getPixels(), bm.getSafeSize());
627 draw.fClip = &clip.bwRgn();
628 draw.fMatrix = &matrix;
630 draw.drawPath(path, paint);
632 switch (mask.fFormat) {
633 case SkMask::kBW_Format:
634 packA8ToA1(mask, bm.getAddr8(0, 0), bm.rowBytes());
636 case SkMask::kA8_Format:
637 if (maskPreBlend.isApplicable()) {
638 applyLUTToA8Mask(mask, maskPreBlend.fG);
641 case SkMask::kLCD16_Format:
642 if (maskPreBlend.isApplicable()) {
643 pack4xHToLCD16<true>(bm, mask, maskPreBlend);
645 pack4xHToLCD16<false>(bm, mask, maskPreBlend);
648 case SkMask::kLCD32_Format:
649 if (maskPreBlend.isApplicable()) {
650 pack4xHToLCD32<true>(bm, mask, maskPreBlend);
652 pack4xHToLCD32<false>(bm, mask, maskPreBlend);
660 static void extract_alpha(const SkMask& dst,
661 const SkPMColor* srcRow, size_t srcRB) {
662 int width = dst.fBounds.width();
663 int height = dst.fBounds.height();
664 int dstRB = dst.fRowBytes;
665 uint8_t* dstRow = dst.fImage;
667 for (int y = 0; y < height; ++y) {
668 for (int x = 0; x < width; ++x) {
669 dstRow[x] = SkGetPackedA32(srcRow[x]);
671 // zero any padding on each row
672 for (int x = width; x < dstRB; ++x) {
676 srcRow = (const SkPMColor*)((const char*)srcRow + srcRB);
680 void SkScalerContext::getImage(const SkGlyph& origGlyph) {
681 const SkGlyph* glyph = &origGlyph;
684 // in case we need to call generateImage on a mask-format that is different
685 // (i.e. larger) than what our caller allocated by looking at origGlyph.
686 SkAutoMalloc tmpGlyphImageStorage;
688 // If we are going to draw-from-path, then we cannot generate color, since
689 // the path only makes a mask. This case should have been caught up in
690 // generateMetrics().
691 SkASSERT(!fGenerateImageFromPath ||
692 SkMask::kARGB32_Format != origGlyph.fMaskFormat);
694 if (fMaskFilter) { // restore the prefilter bounds
695 tmpGlyph.init(origGlyph.fID);
697 // need the original bounds, sans our maskfilter
698 SkMaskFilter* mf = fMaskFilter;
699 fMaskFilter = NULL; // temp disable
700 this->getMetrics(&tmpGlyph);
701 fMaskFilter = mf; // restore
703 // we need the prefilter bounds to be <= filter bounds
704 SkASSERT(tmpGlyph.fWidth <= origGlyph.fWidth);
705 SkASSERT(tmpGlyph.fHeight <= origGlyph.fHeight);
707 if (tmpGlyph.fMaskFormat == origGlyph.fMaskFormat) {
708 tmpGlyph.fImage = origGlyph.fImage;
710 tmpGlyphImageStorage.reset(tmpGlyph.computeImageSize());
711 tmpGlyph.fImage = tmpGlyphImageStorage.get();
716 if (fGenerateImageFromPath) {
717 SkPath devPath, fillPath;
718 SkMatrix fillToDevMatrix;
721 this->internalGetPath(*glyph, &fillPath, &devPath, &fillToDevMatrix);
722 glyph->toMask(&mask);
725 mask.fFormat = SkMask::kA8_Format;
726 sk_bzero(glyph->fImage, mask.computeImageSize());
728 if (!fRasterizer->rasterize(fillPath, fillToDevMatrix, NULL,
730 SkMask::kJustRenderImage_CreateMode)) {
733 if (fPreBlend.isApplicable()) {
734 applyLUTToA8Mask(mask, fPreBlend.fG);
737 SkASSERT(SkMask::kARGB32_Format != mask.fFormat);
738 generateMask(mask, devPath, fPreBlend);
741 this->getGlyphContext(*glyph)->generateImage(*glyph);
748 // the src glyph image shouldn't be 3D
749 SkASSERT(SkMask::k3D_Format != glyph->fMaskFormat);
751 SkAutoSMalloc<32*32> a8storage;
752 glyph->toMask(&srcM);
753 if (SkMask::kARGB32_Format == srcM.fFormat) {
754 // now we need to extract the alpha-channel from the glyph's image
755 // and copy it into a temp buffer, and then point srcM at that temp.
756 srcM.fFormat = SkMask::kA8_Format;
757 srcM.fRowBytes = SkAlign4(srcM.fBounds.width());
758 size_t size = srcM.computeImageSize();
759 a8storage.reset(size);
760 srcM.fImage = (uint8_t*)a8storage.get();
762 (const SkPMColor*)glyph->fImage, glyph->rowBytes());
765 fRec.getMatrixFrom2x2(&matrix);
767 if (fMaskFilter->filterMask(&dstM, srcM, matrix, NULL)) {
768 int width = SkFastMin32(origGlyph.fWidth, dstM.fBounds.width());
769 int height = SkFastMin32(origGlyph.fHeight, dstM.fBounds.height());
770 int dstRB = origGlyph.rowBytes();
771 int srcRB = dstM.fRowBytes;
773 const uint8_t* src = (const uint8_t*)dstM.fImage;
774 uint8_t* dst = (uint8_t*)origGlyph.fImage;
776 if (SkMask::k3D_Format == dstM.fFormat) {
777 // we have to copy 3 times as much
781 // clean out our glyph, since it may be larger than dstM
782 //sk_bzero(dst, height * dstRB);
784 while (--height >= 0) {
785 memcpy(dst, src, width);
789 SkMask::FreeImage(dstM.fImage);
791 if (fPreBlendForFilter.isApplicable()) {
792 applyLUTToA8Mask(srcM, fPreBlendForFilter.fG);
798 void SkScalerContext::getPath(const SkGlyph& glyph, SkPath* path) {
799 this->internalGetPath(glyph, NULL, path, NULL);
802 void SkScalerContext::getFontMetrics(SkPaint::FontMetrics* fm) {
803 // All of this complexity should go away when we change generateFontMetrics
804 // to just take one parameter (since it knows if it is vertical or not)
805 SkPaint::FontMetrics* mx = NULL;
806 SkPaint::FontMetrics* my = NULL;
807 if (fRec.fFlags & kVertical_Flag) {
812 this->generateFontMetrics(mx, my);
815 SkUnichar SkScalerContext::generateGlyphToChar(uint16_t glyph) {
819 ///////////////////////////////////////////////////////////////////////////////
821 void SkScalerContext::internalGetPath(const SkGlyph& glyph, SkPath* fillPath,
822 SkPath* devPath, SkMatrix* fillToDevMatrix) {
825 this->getGlyphContext(glyph)->generatePath(glyph, &path);
827 if (fRec.fFlags & SkScalerContext::kSubpixelPositioning_Flag) {
828 SkFixed dx = glyph.getSubXFixed();
829 SkFixed dy = glyph.getSubYFixed();
831 path.offset(SkFixedToScalar(dx), SkFixedToScalar(dy));
835 if (fRec.fFrameWidth > 0 || fPathEffect != NULL) {
836 // need the path in user-space, with only the point-size applied
837 // so that our stroking and effects will operate the same way they
838 // would if the user had extracted the path themself, and then
841 SkMatrix matrix, inverse;
843 fRec.getMatrixFrom2x2(&matrix);
844 if (!matrix.invert(&inverse)) {
845 // assume fillPath and devPath are already empty.
848 path.transform(inverse, &localPath);
849 // now localPath is only affected by the paint settings, and not the canvas matrix
851 SkStrokeRec rec(SkStrokeRec::kFill_InitStyle);
853 if (fRec.fFrameWidth > 0) {
854 rec.setStrokeStyle(fRec.fFrameWidth,
855 SkToBool(fRec.fFlags & kFrameAndFill_Flag));
856 // glyphs are always closed contours, so cap type is ignored,
857 // so we just pass something.
858 rec.setStrokeParams(SkPaint::kButt_Cap,
859 (SkPaint::Join)fRec.fStrokeJoin,
865 if (fPathEffect->filterPath(&effectPath, localPath, &rec, NULL)) {
866 localPath.swap(effectPath);
870 if (rec.needToApply()) {
872 if (rec.applyToPath(&strokePath, localPath)) {
873 localPath.swap(strokePath);
877 // now return stuff to the caller
878 if (fillToDevMatrix) {
879 *fillToDevMatrix = matrix;
882 localPath.transform(matrix, devPath);
885 fillPath->swap(localPath);
887 } else { // nothing tricky to do
888 if (fillToDevMatrix) {
889 fillToDevMatrix->reset();
892 if (fillPath == NULL) {
900 fillPath->swap(path);
905 devPath->updateBoundsCache();
908 fillPath->updateBoundsCache();
913 void SkScalerContextRec::getMatrixFrom2x2(SkMatrix* dst) const {
914 dst->setAll(fPost2x2[0][0], fPost2x2[0][1], 0,
915 fPost2x2[1][0], fPost2x2[1][1], 0,
916 0, 0, SkScalarToPersp(SK_Scalar1));
919 void SkScalerContextRec::getLocalMatrix(SkMatrix* m) const {
920 SkPaint::SetTextMatrix(m, fTextSize, fPreScaleX, fPreSkewX);
923 void SkScalerContextRec::getSingleMatrix(SkMatrix* m) const {
924 this->getLocalMatrix(m);
926 // now concat the device matrix
927 SkMatrix deviceMatrix;
928 this->getMatrixFrom2x2(&deviceMatrix);
929 m->postConcat(deviceMatrix);
932 SkAxisAlignment SkComputeAxisAlignmentForHText(const SkMatrix& matrix) {
933 SkASSERT(!matrix.hasPerspective());
935 if (0 == matrix[SkMatrix::kMSkewY]) {
936 return kX_SkAxisAlignment;
938 if (0 == matrix[SkMatrix::kMScaleX]) {
939 return kY_SkAxisAlignment;
941 return kNone_SkAxisAlignment;
944 ///////////////////////////////////////////////////////////////////////////////
946 #include "SkFontHost.h"
948 class SkScalerContext_Empty : public SkScalerContext {
950 SkScalerContext_Empty(SkTypeface* face, const SkDescriptor* desc)
951 : SkScalerContext(face, desc) {}
954 virtual unsigned generateGlyphCount() SK_OVERRIDE {
957 virtual uint16_t generateCharToGlyph(SkUnichar uni) SK_OVERRIDE {
960 virtual void generateAdvance(SkGlyph* glyph) SK_OVERRIDE {
961 glyph->zeroMetrics();
963 virtual void generateMetrics(SkGlyph* glyph) SK_OVERRIDE {
964 glyph->zeroMetrics();
966 virtual void generateImage(const SkGlyph& glyph) SK_OVERRIDE {}
967 virtual void generatePath(const SkGlyph& glyph, SkPath* path) SK_OVERRIDE {}
968 virtual void generateFontMetrics(SkPaint::FontMetrics* mx,
969 SkPaint::FontMetrics* my) SK_OVERRIDE {
971 sk_bzero(mx, sizeof(*mx));
974 sk_bzero(my, sizeof(*my));
979 extern SkScalerContext* SkCreateColorScalerContext(const SkDescriptor* desc);
981 SkScalerContext* SkTypeface::createScalerContext(const SkDescriptor* desc,
982 bool allowFailure) const {
983 SkScalerContext* c = this->onCreateScalerContext(desc);
985 if (!c && !allowFailure) {
986 c = SkNEW_ARGS(SkScalerContext_Empty,
987 (const_cast<SkTypeface*>(this), desc));