1685cfc0ee13d7c355ae2f4f3d225ad45e945763fepoger@google.com 2685cfc0ee13d7c355ae2f4f3d225ad45e945763fepoger@google.com/* 3685cfc0ee13d7c355ae2f4f3d225ad45e945763fepoger@google.com * Copyright 2006 The Android Open Source Project 4685cfc0ee13d7c355ae2f4f3d225ad45e945763fepoger@google.com * 5685cfc0ee13d7c355ae2f4f3d225ad45e945763fepoger@google.com * Use of this source code is governed by a BSD-style license that can be 6685cfc0ee13d7c355ae2f4f3d225ad45e945763fepoger@google.com * found in the LICENSE file. 7685cfc0ee13d7c355ae2f4f3d225ad45e945763fepoger@google.com */ 8685cfc0ee13d7c355ae2f4f3d225ad45e945763fepoger@google.com 9bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 10bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#include "SkScalerContext.h" 11c775c0b52526f14d8c82896c4dc654f4e5268f42agl@chromium.org#include "SkColorPriv.h" 12bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#include "SkDescriptor.h" 13bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#include "SkDraw.h" 14bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#include "SkFontHost.h" 151ef6e7aa2ca040bc9a47708d832f21e22ae474acbungeman@google.com#include "SkGlyph.h" 16bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#include "SkMaskFilter.h" 178ebb786eca7079fed1c2d9521e2bf9604bb5825dbungeman@google.com#include "SkMaskGamma.h" 18d02e825bf79c38dad5fb7c02dfc301ad4dfabeaadjsollen@google.com#include "SkOrderedReadBuffer.h" 19b0565b5b69b975e16cfd982ed9e2fab3dab8072cdjsollen@google.com#include "SkOrderedWriteBuffer.h" 20bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#include "SkPathEffect.h" 21bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#include "SkRasterizer.h" 2226f5a398c38318eb7eab44f72e024ef784d247fareed@google.com#include "SkRasterClip.h" 23bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#include "SkStroke.h" 24bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#include "SkThread.h" 25bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 26cc7164e248610379e481bcb5ab8f6bd52007cb49reed@google.com#ifdef SK_BUILD_FOR_ANDROID 27cc7164e248610379e481bcb5ab8f6bd52007cb49reed@google.com #include "SkTypeface_android.h" 28cc7164e248610379e481bcb5ab8f6bd52007cb49reed@google.com#endif 2918723ff03ab6a08cd02c5ae008ae6775d13b3281robertphillips@google.com 30bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#define ComputeBWRowBytes(width) (((unsigned)(width) + 7) >> 3) 31bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 32bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.comvoid SkGlyph::toMask(SkMask* mask) const { 33bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com SkASSERT(mask); 34bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 35bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com mask->fImage = (uint8_t*)fImage; 36bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com mask->fBounds.set(fLeft, fTop, fLeft + fWidth, fTop + fHeight); 37bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com mask->fRowBytes = this->rowBytes(); 3817f6e4bba20b6542cdf0a4fb0442a7f330003ee4reed@android.com mask->fFormat = static_cast<SkMask::Format>(fMaskFormat); 39bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com} 40bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 41bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.comsize_t SkGlyph::computeImageSize() const { 42c775c0b52526f14d8c82896c4dc654f4e5268f42agl@chromium.org const size_t size = this->rowBytes() * fHeight; 43c775c0b52526f14d8c82896c4dc654f4e5268f42agl@chromium.org 44c775c0b52526f14d8c82896c4dc654f4e5268f42agl@chromium.org switch (fMaskFormat) { 4502a9b1d3258a7a0d74344e5c84313b36fcd2a8c2reed@google.com case SkMask::k3D_Format: 4602a9b1d3258a7a0d74344e5c84313b36fcd2a8c2reed@google.com return 3 * size; 4702a9b1d3258a7a0d74344e5c84313b36fcd2a8c2reed@google.com default: 4802a9b1d3258a7a0d74344e5c84313b36fcd2a8c2reed@google.com return size; 49bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } 50bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com} 51bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 52efc74b8af0ee522065266db255e9bc48c8ceaceereed@android.comvoid SkGlyph::zeroMetrics() { 53efc74b8af0ee522065266db255e9bc48c8ceaceereed@android.com fAdvanceX = 0; 54efc74b8af0ee522065266db255e9bc48c8ceaceereed@android.com fAdvanceY = 0; 55efc74b8af0ee522065266db255e9bc48c8ceaceereed@android.com fWidth = 0; 56efc74b8af0ee522065266db255e9bc48c8ceaceereed@android.com fHeight = 0; 57efc74b8af0ee522065266db255e9bc48c8ceaceereed@android.com fTop = 0; 58efc74b8af0ee522065266db255e9bc48c8ceaceereed@android.com fLeft = 0; 59efc74b8af0ee522065266db255e9bc48c8ceaceereed@android.com fRsbDelta = 0; 60efc74b8af0ee522065266db255e9bc48c8ceaceereed@android.com fLsbDelta = 0; 61efc74b8af0ee522065266db255e9bc48c8ceaceereed@android.com} 62efc74b8af0ee522065266db255e9bc48c8ceaceereed@android.com 63efc74b8af0ee522065266db255e9bc48c8ceaceereed@android.com/////////////////////////////////////////////////////////////////////////////// 64efc74b8af0ee522065266db255e9bc48c8ceaceereed@android.com 65bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#ifdef SK_DEBUG 66bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com #define DUMP_RECx 67bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#endif 68bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 69bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.comstatic SkFlattenable* load_flattenable(const SkDescriptor* desc, uint32_t tag) { 70bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com SkFlattenable* obj = NULL; 71bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com uint32_t len; 72bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com const void* data = desc->findEntry(tag, &len); 73bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 74bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com if (data) { 75d02e825bf79c38dad5fb7c02dfc301ad4dfabeaadjsollen@google.com SkOrderedReadBuffer buffer(data, len); 76bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com obj = buffer.readFlattenable(); 77bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com SkASSERT(buffer.offset() == buffer.size()); 78bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } 79bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com return obj; 80bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com} 81bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 828e01453029702b114d4eb939e4fbe7fd33b57b50reed@google.comSkScalerContext::SkScalerContext(SkTypeface* typeface, const SkDescriptor* desc) 838ebb786eca7079fed1c2d9521e2bf9604bb5825dbungeman@google.com : fRec(*static_cast<const Rec*>(desc->findEntry(kRec_SkDescriptorTag, NULL))) 84ec0f292459a7b5fb0300c83e456714033ab802fbbungeman@google.com 858ebb786eca7079fed1c2d9521e2bf9604bb5825dbungeman@google.com , fBaseGlyphCount(0) 868e01453029702b114d4eb939e4fbe7fd33b57b50reed@google.com , fTypeface(SkRef(typeface)) 878ebb786eca7079fed1c2d9521e2bf9604bb5825dbungeman@google.com , fPathEffect(static_cast<SkPathEffect*>(load_flattenable(desc, kPathEffect_SkDescriptorTag))) 888ebb786eca7079fed1c2d9521e2bf9604bb5825dbungeman@google.com , fMaskFilter(static_cast<SkMaskFilter*>(load_flattenable(desc, kMaskFilter_SkDescriptorTag))) 898ebb786eca7079fed1c2d9521e2bf9604bb5825dbungeman@google.com , fRasterizer(static_cast<SkRasterizer*>(load_flattenable(desc, kRasterizer_SkDescriptorTag))) 90ec0f292459a7b5fb0300c83e456714033ab802fbbungeman@google.com 91ec0f292459a7b5fb0300c83e456714033ab802fbbungeman@google.com // Initialize based on our settings. Subclasses can also force this. 928ebb786eca7079fed1c2d9521e2bf9604bb5825dbungeman@google.com , fGenerateImageFromPath(fRec.fFrameWidth > 0 || fPathEffect != NULL || fRasterizer != NULL) 93ec0f292459a7b5fb0300c83e456714033ab802fbbungeman@google.com 948ebb786eca7079fed1c2d9521e2bf9604bb5825dbungeman@google.com , fNextContext(NULL) 95ec0f292459a7b5fb0300c83e456714033ab802fbbungeman@google.com 96ec0f292459a7b5fb0300c83e456714033ab802fbbungeman@google.com , fPreBlend(fMaskFilter ? SkMaskGamma::PreBlend() : SkScalerContext::GetMaskPreBlend(fRec)) 97ec0f292459a7b5fb0300c83e456714033ab802fbbungeman@google.com , fPreBlendForFilter(fMaskFilter ? SkScalerContext::GetMaskPreBlend(fRec) 98ec0f292459a7b5fb0300c83e456714033ab802fbbungeman@google.com : SkMaskGamma::PreBlend()) 99bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com{ 100bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#ifdef DUMP_REC 101bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com desc->assertChecksum(); 10202a9b1d3258a7a0d74344e5c84313b36fcd2a8c2reed@google.com SkDebugf("SkScalarContext checksum %x count %d length %d\n", 10302a9b1d3258a7a0d74344e5c84313b36fcd2a8c2reed@google.com desc->getChecksum(), desc->getCount(), desc->getLength()); 104bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com SkDebugf(" textsize %g prescale %g preskew %g post [%g %g %g %g]\n", 105bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com rec->fTextSize, rec->fPreScaleX, rec->fPreSkewX, rec->fPost2x2[0][0], 106bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com rec->fPost2x2[0][1], rec->fPost2x2[1][0], rec->fPost2x2[1][1]); 107bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com SkDebugf(" frame %g miter %g hints %d framefill %d format %d join %d\n", 108bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com rec->fFrameWidth, rec->fMiterLimit, rec->fHints, rec->fFrameAndFill, 109bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com rec->fMaskFormat, rec->fStrokeJoin); 11002a9b1d3258a7a0d74344e5c84313b36fcd2a8c2reed@google.com SkDebugf(" pathEffect %x maskFilter %x\n", 11102a9b1d3258a7a0d74344e5c84313b36fcd2a8c2reed@google.com desc->findEntry(kPathEffect_SkDescriptorTag, NULL), 112bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com desc->findEntry(kMaskFilter_SkDescriptorTag, NULL)); 113bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#endif 1143a2896926de7270052847f19fa69135c08e1a36fcommit-bot@chromium.org#ifdef SK_BUILD_FOR_ANDROID 1153a2896926de7270052847f19fa69135c08e1a36fcommit-bot@chromium.org uint32_t len; 1163a2896926de7270052847f19fa69135c08e1a36fcommit-bot@chromium.org const void* data = desc->findEntry(kAndroidOpts_SkDescriptorTag, &len); 1173a2896926de7270052847f19fa69135c08e1a36fcommit-bot@chromium.org if (data) { 1183a2896926de7270052847f19fa69135c08e1a36fcommit-bot@chromium.org SkOrderedReadBuffer buffer(data, len); 1193a2896926de7270052847f19fa69135c08e1a36fcommit-bot@chromium.org fPaintOptionsAndroid.unflatten(buffer); 1203a2896926de7270052847f19fa69135c08e1a36fcommit-bot@chromium.org SkASSERT(buffer.offset() == buffer.size()); 1213a2896926de7270052847f19fa69135c08e1a36fcommit-bot@chromium.org } 1223a2896926de7270052847f19fa69135c08e1a36fcommit-bot@chromium.org#endif 123bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com} 124bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 125bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.comSkScalerContext::~SkScalerContext() { 1267f78761dbe9c208f0763a39d94c44dcf602a182breed@android.com SkDELETE(fNextContext); 1277f78761dbe9c208f0763a39d94c44dcf602a182breed@android.com 128919114813d58933c9d9433b141e0222c34b700b1reed@google.com SkSafeUnref(fPathEffect); 129919114813d58933c9d9433b141e0222c34b700b1reed@google.com SkSafeUnref(fMaskFilter); 130919114813d58933c9d9433b141e0222c34b700b1reed@google.com SkSafeUnref(fRasterizer); 131bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com} 132bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 1338e01453029702b114d4eb939e4fbe7fd33b57b50reed@google.com// Return the context associated with the next logical typeface, or NULL if 1348e01453029702b114d4eb939e4fbe7fd33b57b50reed@google.com// there are no more entries in the fallback chain. 1357c91f91079e4350bf43a571255ab014f033c786areed@google.comSkScalerContext* SkScalerContext::allocNextContext() const { 1365d7697907f9ff73a88f47c70715564b23178524breed@google.com#ifdef SK_BUILD_FOR_ANDROID 137cc7164e248610379e481bcb5ab8f6bd52007cb49reed@google.com SkTypeface* newFace = SkAndroidNextLogicalTypeface(fRec.fFontID, 1383a2896926de7270052847f19fa69135c08e1a36fcommit-bot@chromium.org fRec.fOrigFontID, 1393a2896926de7270052847f19fa69135c08e1a36fcommit-bot@chromium.org fPaintOptionsAndroid); 1408e01453029702b114d4eb939e4fbe7fd33b57b50reed@google.com if (0 == newFace) { 1417f78761dbe9c208f0763a39d94c44dcf602a182breed@android.com return NULL; 142bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } 143cc8868bd44e24dd8a5f44dd02263e02b836d9b6fskia.committer@gmail.com 1448e01453029702b114d4eb939e4fbe7fd33b57b50reed@google.com SkAutoTUnref<SkTypeface> aur(newFace); 1458e01453029702b114d4eb939e4fbe7fd33b57b50reed@google.com uint32_t newFontID = newFace->uniqueID(); 146bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 147b0565b5b69b975e16cfd982ed9e2fab3dab8072cdjsollen@google.com SkOrderedWriteBuffer androidBuffer(128); 148b0565b5b69b975e16cfd982ed9e2fab3dab8072cdjsollen@google.com fPaintOptionsAndroid.flatten(androidBuffer); 149b0565b5b69b975e16cfd982ed9e2fab3dab8072cdjsollen@google.com 150b0565b5b69b975e16cfd982ed9e2fab3dab8072cdjsollen@google.com SkAutoDescriptor ad(sizeof(fRec) + androidBuffer.size() + SkDescriptor::ComputeOverhead(2)); 1517f78761dbe9c208f0763a39d94c44dcf602a182breed@android.com SkDescriptor* desc = ad.getDesc(); 152bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 1537f78761dbe9c208f0763a39d94c44dcf602a182breed@android.com desc->init(); 1547f78761dbe9c208f0763a39d94c44dcf602a182breed@android.com SkScalerContext::Rec* newRec = 1557f78761dbe9c208f0763a39d94c44dcf602a182breed@android.com (SkScalerContext::Rec*)desc->addEntry(kRec_SkDescriptorTag, 1567c91f91079e4350bf43a571255ab014f033c786areed@google.com sizeof(fRec), &fRec); 157b0565b5b69b975e16cfd982ed9e2fab3dab8072cdjsollen@google.com androidBuffer.writeToMemory(desc->addEntry(kAndroidOpts_SkDescriptorTag, 158b0565b5b69b975e16cfd982ed9e2fab3dab8072cdjsollen@google.com androidBuffer.size(), NULL)); 159b0565b5b69b975e16cfd982ed9e2fab3dab8072cdjsollen@google.com 1607f78761dbe9c208f0763a39d94c44dcf602a182breed@android.com newRec->fFontID = newFontID; 1617f78761dbe9c208f0763a39d94c44dcf602a182breed@android.com desc->computeChecksum(); 1627f78761dbe9c208f0763a39d94c44dcf602a182breed@android.com 1638e01453029702b114d4eb939e4fbe7fd33b57b50reed@google.com return newFace->createScalerContext(desc); 1645d7697907f9ff73a88f47c70715564b23178524breed@google.com#else 1655d7697907f9ff73a88f47c70715564b23178524breed@google.com return NULL; 1665d7697907f9ff73a88f47c70715564b23178524breed@google.com#endif 1677f78761dbe9c208f0763a39d94c44dcf602a182breed@android.com} 1687f78761dbe9c208f0763a39d94c44dcf602a182breed@android.com 1697f78761dbe9c208f0763a39d94c44dcf602a182breed@android.com/* Return the next context, creating it if its not already created, but return 1707f78761dbe9c208f0763a39d94c44dcf602a182breed@android.com NULL if the fonthost says there are no more fonts to fallback to. 1717f78761dbe9c208f0763a39d94c44dcf602a182breed@android.com */ 1727f78761dbe9c208f0763a39d94c44dcf602a182breed@android.comSkScalerContext* SkScalerContext::getNextContext() { 1737f78761dbe9c208f0763a39d94c44dcf602a182breed@android.com SkScalerContext* next = fNextContext; 1747f78761dbe9c208f0763a39d94c44dcf602a182breed@android.com // if next is null, then either it isn't cached yet, or we're at the 1757f78761dbe9c208f0763a39d94c44dcf602a182breed@android.com // end of our possible chain 1767f78761dbe9c208f0763a39d94c44dcf602a182breed@android.com if (NULL == next) { 1777c91f91079e4350bf43a571255ab014f033c786areed@google.com next = this->allocNextContext(); 1787f78761dbe9c208f0763a39d94c44dcf602a182breed@android.com if (NULL == next) { 1797f78761dbe9c208f0763a39d94c44dcf602a182breed@android.com return NULL; 180bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } 1817f78761dbe9c208f0763a39d94c44dcf602a182breed@android.com // next's base is our base + our local count 1827f78761dbe9c208f0763a39d94c44dcf602a182breed@android.com next->setBaseGlyphCount(fBaseGlyphCount + this->getGlyphCount()); 1837f78761dbe9c208f0763a39d94c44dcf602a182breed@android.com // cache the answer 1847f78761dbe9c208f0763a39d94c44dcf602a182breed@android.com fNextContext = next; 185bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } 1867f78761dbe9c208f0763a39d94c44dcf602a182breed@android.com return next; 1877f78761dbe9c208f0763a39d94c44dcf602a182breed@android.com} 1887f78761dbe9c208f0763a39d94c44dcf602a182breed@android.com 1897f78761dbe9c208f0763a39d94c44dcf602a182breed@android.comSkScalerContext* SkScalerContext::getGlyphContext(const SkGlyph& glyph) { 1907f78761dbe9c208f0763a39d94c44dcf602a182breed@android.com unsigned glyphID = glyph.getGlyphID(); 1917f78761dbe9c208f0763a39d94c44dcf602a182breed@android.com SkScalerContext* ctx = this; 1927f78761dbe9c208f0763a39d94c44dcf602a182breed@android.com for (;;) { 1937f78761dbe9c208f0763a39d94c44dcf602a182breed@android.com unsigned count = ctx->getGlyphCount(); 1947f78761dbe9c208f0763a39d94c44dcf602a182breed@android.com if (glyphID < count) { 1957f78761dbe9c208f0763a39d94c44dcf602a182breed@android.com break; 196bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } 1977f78761dbe9c208f0763a39d94c44dcf602a182breed@android.com glyphID -= count; 1987f78761dbe9c208f0763a39d94c44dcf602a182breed@android.com ctx = ctx->getNextContext(); 1997f78761dbe9c208f0763a39d94c44dcf602a182breed@android.com if (NULL == ctx) { 2005e1d374692c567a07696f9452c6e7024b5c69262scroggo@google.com// SkDebugf("--- no context for glyph %x\n", glyph.getGlyphID()); 2017f78761dbe9c208f0763a39d94c44dcf602a182breed@android.com // just return the original context (this) 2027f78761dbe9c208f0763a39d94c44dcf602a182breed@android.com return this; 203bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } 204bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } 2057f78761dbe9c208f0763a39d94c44dcf602a182breed@android.com return ctx; 206bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com} 207bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 20833845832e136c8d77dae6887fb58c2a15c32d789djsollen@google.comSkScalerContext* SkScalerContext::getContextFromChar(SkUnichar uni, 20933845832e136c8d77dae6887fb58c2a15c32d789djsollen@google.com uint16_t* glyphID) { 21033845832e136c8d77dae6887fb58c2a15c32d789djsollen@google.com SkScalerContext* ctx = this; 21133845832e136c8d77dae6887fb58c2a15c32d789djsollen@google.com for (;;) { 21233845832e136c8d77dae6887fb58c2a15c32d789djsollen@google.com const uint16_t glyph = ctx->generateCharToGlyph(uni); 21333845832e136c8d77dae6887fb58c2a15c32d789djsollen@google.com if (glyph) { 21433845832e136c8d77dae6887fb58c2a15c32d789djsollen@google.com if (NULL != glyphID) { 21533845832e136c8d77dae6887fb58c2a15c32d789djsollen@google.com *glyphID = glyph; 21633845832e136c8d77dae6887fb58c2a15c32d789djsollen@google.com } 21733845832e136c8d77dae6887fb58c2a15c32d789djsollen@google.com break; // found it 21833845832e136c8d77dae6887fb58c2a15c32d789djsollen@google.com } 21933845832e136c8d77dae6887fb58c2a15c32d789djsollen@google.com ctx = ctx->getNextContext(); 22033845832e136c8d77dae6887fb58c2a15c32d789djsollen@google.com if (NULL == ctx) { 22133845832e136c8d77dae6887fb58c2a15c32d789djsollen@google.com return NULL; 22233845832e136c8d77dae6887fb58c2a15c32d789djsollen@google.com } 22333845832e136c8d77dae6887fb58c2a15c32d789djsollen@google.com } 22433845832e136c8d77dae6887fb58c2a15c32d789djsollen@google.com return ctx; 22533845832e136c8d77dae6887fb58c2a15c32d789djsollen@google.com} 22633845832e136c8d77dae6887fb58c2a15c32d789djsollen@google.com 227f2e6b589ab62dc52807e27d02fed14d0bd77e82fdjsollen@google.com#ifdef SK_BUILD_FOR_ANDROID 22833845832e136c8d77dae6887fb58c2a15c32d789djsollen@google.comSkFontID SkScalerContext::findTypefaceIdForChar(SkUnichar uni) { 22933845832e136c8d77dae6887fb58c2a15c32d789djsollen@google.com SkScalerContext* ctx = this->getContextFromChar(uni, NULL); 23033845832e136c8d77dae6887fb58c2a15c32d789djsollen@google.com if (NULL != ctx) { 23133845832e136c8d77dae6887fb58c2a15c32d789djsollen@google.com return ctx->fRec.fFontID; 23233845832e136c8d77dae6887fb58c2a15c32d789djsollen@google.com } else { 23333845832e136c8d77dae6887fb58c2a15c32d789djsollen@google.com return 0; 23433845832e136c8d77dae6887fb58c2a15c32d789djsollen@google.com } 23533845832e136c8d77dae6887fb58c2a15c32d789djsollen@google.com} 23633845832e136c8d77dae6887fb58c2a15c32d789djsollen@google.com 237f2e6b589ab62dc52807e27d02fed14d0bd77e82fdjsollen@google.com/* This loops through all available fallback contexts (if needed) until it 238f2e6b589ab62dc52807e27d02fed14d0bd77e82fdjsollen@google.com finds some context that can handle the unichar and return it. 239f2e6b589ab62dc52807e27d02fed14d0bd77e82fdjsollen@google.com 240f2e6b589ab62dc52807e27d02fed14d0bd77e82fdjsollen@google.com As this is somewhat expensive operation, it should only be done on the first 241f2e6b589ab62dc52807e27d02fed14d0bd77e82fdjsollen@google.com char of a run. 242f2e6b589ab62dc52807e27d02fed14d0bd77e82fdjsollen@google.com */ 243f2e6b589ab62dc52807e27d02fed14d0bd77e82fdjsollen@google.comunsigned SkScalerContext::getBaseGlyphCount(SkUnichar uni) { 24433845832e136c8d77dae6887fb58c2a15c32d789djsollen@google.com SkScalerContext* ctx = this->getContextFromChar(uni, NULL); 24533845832e136c8d77dae6887fb58c2a15c32d789djsollen@google.com if (NULL != ctx) { 24633845832e136c8d77dae6887fb58c2a15c32d789djsollen@google.com return ctx->fBaseGlyphCount; 24733845832e136c8d77dae6887fb58c2a15c32d789djsollen@google.com } else { 24833845832e136c8d77dae6887fb58c2a15c32d789djsollen@google.com SkDEBUGF(("--- no context for char %x\n", uni)); 24933845832e136c8d77dae6887fb58c2a15c32d789djsollen@google.com return this->fBaseGlyphCount; 250f2e6b589ab62dc52807e27d02fed14d0bd77e82fdjsollen@google.com } 251f2e6b589ab62dc52807e27d02fed14d0bd77e82fdjsollen@google.com} 252f2e6b589ab62dc52807e27d02fed14d0bd77e82fdjsollen@google.com#endif 253f2e6b589ab62dc52807e27d02fed14d0bd77e82fdjsollen@google.com 2547f78761dbe9c208f0763a39d94c44dcf602a182breed@android.com/* This loops through all available fallback contexts (if needed) until it 2557f78761dbe9c208f0763a39d94c44dcf602a182breed@android.com finds some context that can handle the unichar. If all fail, returns 0 2567f78761dbe9c208f0763a39d94c44dcf602a182breed@android.com */ 2577f78761dbe9c208f0763a39d94c44dcf602a182breed@android.comuint16_t SkScalerContext::charToGlyphID(SkUnichar uni) { 25833845832e136c8d77dae6887fb58c2a15c32d789djsollen@google.com 25933845832e136c8d77dae6887fb58c2a15c32d789djsollen@google.com uint16_t tempID; 26033845832e136c8d77dae6887fb58c2a15c32d789djsollen@google.com SkScalerContext* ctx = this->getContextFromChar(uni, &tempID); 26133845832e136c8d77dae6887fb58c2a15c32d789djsollen@google.com if (NULL == ctx) { 26233845832e136c8d77dae6887fb58c2a15c32d789djsollen@google.com return 0; // no more contexts, return missing glyph 263bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } 2647f78761dbe9c208f0763a39d94c44dcf602a182breed@android.com // add the ctx's base, making glyphID unique for chain of contexts 26533845832e136c8d77dae6887fb58c2a15c32d789djsollen@google.com unsigned glyphID = tempID + ctx->fBaseGlyphCount; 2667f78761dbe9c208f0763a39d94c44dcf602a182breed@android.com // check for overflow of 16bits, since our glyphID cannot exceed that 2677f78761dbe9c208f0763a39d94c44dcf602a182breed@android.com if (glyphID > 0xFFFF) { 2687f78761dbe9c208f0763a39d94c44dcf602a182breed@android.com glyphID = 0; 2697f78761dbe9c208f0763a39d94c44dcf602a182breed@android.com } 2707f78761dbe9c208f0763a39d94c44dcf602a182breed@android.com return SkToU16(glyphID); 271bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com} 272bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 273739245e986d7a78b96129f559363b7ab6fb0a21creed@android.comSkUnichar SkScalerContext::glyphIDToChar(uint16_t glyphID) { 274739245e986d7a78b96129f559363b7ab6fb0a21creed@android.com SkScalerContext* ctx = this; 275739245e986d7a78b96129f559363b7ab6fb0a21creed@android.com unsigned rangeEnd = 0; 276739245e986d7a78b96129f559363b7ab6fb0a21creed@android.com do { 277739245e986d7a78b96129f559363b7ab6fb0a21creed@android.com unsigned rangeStart = rangeEnd; 278739245e986d7a78b96129f559363b7ab6fb0a21creed@android.com 279739245e986d7a78b96129f559363b7ab6fb0a21creed@android.com rangeEnd += ctx->getGlyphCount(); 280739245e986d7a78b96129f559363b7ab6fb0a21creed@android.com if (rangeStart <= glyphID && glyphID < rangeEnd) { 281739245e986d7a78b96129f559363b7ab6fb0a21creed@android.com return ctx->generateGlyphToChar(glyphID - rangeStart); 282739245e986d7a78b96129f559363b7ab6fb0a21creed@android.com } 283739245e986d7a78b96129f559363b7ab6fb0a21creed@android.com ctx = ctx->getNextContext(); 284739245e986d7a78b96129f559363b7ab6fb0a21creed@android.com } while (NULL != ctx); 285739245e986d7a78b96129f559363b7ab6fb0a21creed@android.com return 0; 286739245e986d7a78b96129f559363b7ab6fb0a21creed@android.com} 287739245e986d7a78b96129f559363b7ab6fb0a21creed@android.com 288bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.comvoid SkScalerContext::getAdvance(SkGlyph* glyph) { 289bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com // mark us as just having a valid advance 290bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com glyph->fMaskFormat = MASK_FORMAT_JUST_ADVANCE; 291bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com // we mark the format before making the call, in case the impl 292bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com // internally ends up calling its generateMetrics, which is OK 293bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com // albeit slower than strictly necessary 294bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com this->getGlyphContext(*glyph)->generateAdvance(glyph); 295bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com} 296bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 297bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.comvoid SkScalerContext::getMetrics(SkGlyph* glyph) { 298bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com this->getGlyphContext(*glyph)->generateMetrics(glyph); 299bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 300bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com // for now we have separate cache entries for devkerning on and off 301bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com // in the future we might share caches, but make our measure/draw 302bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com // code make the distinction. Thus we zap the values if the caller 303bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com // has not asked for them. 304bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com if ((fRec.fFlags & SkScalerContext::kDevKernText_Flag) == 0) { 305bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com // no devkern, so zap the fields 306bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com glyph->fLsbDelta = glyph->fRsbDelta = 0; 307bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } 308bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 309bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com // if either dimension is empty, zap the image bounds of the glyph 310bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com if (0 == glyph->fWidth || 0 == glyph->fHeight) { 311bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com glyph->fWidth = 0; 312bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com glyph->fHeight = 0; 313bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com glyph->fTop = 0; 314bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com glyph->fLeft = 0; 315bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com glyph->fMaskFormat = 0; 316bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com return; 317bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } 318919114813d58933c9d9433b141e0222c34b700b1reed@google.com 319ff10324db62df86ecc52bfc1baa14fc4d8ab849areed@google.com if (fGenerateImageFromPath) { 320bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com SkPath devPath, fillPath; 321bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com SkMatrix fillToDevMatrix; 322bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 323bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com this->internalGetPath(*glyph, &fillPath, &devPath, &fillToDevMatrix); 324bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 325bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com if (fRasterizer) { 326bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com SkMask mask; 327bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 328bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com if (fRasterizer->rasterize(fillPath, fillToDevMatrix, NULL, 329bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com fMaskFilter, &mask, 330bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com SkMask::kJustComputeBounds_CreateMode)) { 331bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com glyph->fLeft = mask.fBounds.fLeft; 332bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com glyph->fTop = mask.fBounds.fTop; 333bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com glyph->fWidth = SkToU16(mask.fBounds.width()); 334bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com glyph->fHeight = SkToU16(mask.fBounds.height()); 335bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } else { 33641aa25d7d04bb3713c6afca42636613dc1a7dbf4senorblanco@chromium.org goto SK_ERROR; 337bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } 338bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } else { 339bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com // just use devPath 340bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com SkIRect ir; 341155c4e804736576f9352aa60d70669ac3e3f9d52reed@android.com devPath.getBounds().roundOut(&ir); 342919114813d58933c9d9433b141e0222c34b700b1reed@google.com 34341308ff545b8133f3ace8341e7737b068abeded1reed@android.com if (ir.isEmpty() || !ir.is16Bit()) { 34441aa25d7d04bb3713c6afca42636613dc1a7dbf4senorblanco@chromium.org goto SK_ERROR; 345f2dbd4db2b41bf7ec551faa37627054c18c4a503reed@android.com } 346bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com glyph->fLeft = ir.fLeft; 347bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com glyph->fTop = ir.fTop; 348bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com glyph->fWidth = SkToU16(ir.width()); 349bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com glyph->fHeight = SkToU16(ir.height()); 350a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com 351a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com if (glyph->fWidth > 0) { 352a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com switch (fRec.fMaskFormat) { 353a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com case SkMask::kLCD16_Format: 354a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com case SkMask::kLCD32_Format: 355a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com glyph->fWidth += 2; 356a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com glyph->fLeft -= 1; 357a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com break; 358a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com default: 359a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com break; 360a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com } 361a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com } 362bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } 363bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } 364bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 36518723ff03ab6a08cd02c5ae008ae6775d13b3281robertphillips@google.com if (SkMask::kARGB32_Format != glyph->fMaskFormat) { 36618723ff03ab6a08cd02c5ae008ae6775d13b3281robertphillips@google.com glyph->fMaskFormat = fRec.fMaskFormat; 36718723ff03ab6a08cd02c5ae008ae6775d13b3281robertphillips@google.com } 368bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 3696d450fe32babea3eb42b8b76d594bdc0be37529areed@google.com // If we are going to create the mask, then we cannot keep the color 3706d450fe32babea3eb42b8b76d594bdc0be37529areed@google.com if ((fGenerateImageFromPath || fMaskFilter) && 3716d450fe32babea3eb42b8b76d594bdc0be37529areed@google.com SkMask::kARGB32_Format == glyph->fMaskFormat) { 3726d450fe32babea3eb42b8b76d594bdc0be37529areed@google.com glyph->fMaskFormat = SkMask::kA8_Format; 3736d450fe32babea3eb42b8b76d594bdc0be37529areed@google.com } 3746d450fe32babea3eb42b8b76d594bdc0be37529areed@google.com 375bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com if (fMaskFilter) { 376bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com SkMask src, dst; 377bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com SkMatrix matrix; 378bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 379bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com glyph->toMask(&src); 380bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com fRec.getMatrixFrom2x2(&matrix); 381bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 382bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com src.fImage = NULL; // only want the bounds from the filter 383bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com if (fMaskFilter->filterMask(&dst, src, matrix, NULL)) { 38426a498d01d899ea9af78ee70df710ddbb4d9370creed@google.com if (dst.fBounds.isEmpty() || !dst.fBounds.is16Bit()) { 38526a498d01d899ea9af78ee70df710ddbb4d9370creed@google.com goto SK_ERROR; 38626a498d01d899ea9af78ee70df710ddbb4d9370creed@google.com } 387bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com SkASSERT(dst.fImage == NULL); 388bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com glyph->fLeft = dst.fBounds.fLeft; 389bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com glyph->fTop = dst.fBounds.fTop; 390bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com glyph->fWidth = SkToU16(dst.fBounds.width()); 391bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com glyph->fHeight = SkToU16(dst.fBounds.height()); 392bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com glyph->fMaskFormat = dst.fFormat; 393bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } 394bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } 395f2dbd4db2b41bf7ec551faa37627054c18c4a503reed@android.com return; 396919114813d58933c9d9433b141e0222c34b700b1reed@google.com 39741aa25d7d04bb3713c6afca42636613dc1a7dbf4senorblanco@chromium.orgSK_ERROR: 398f2dbd4db2b41bf7ec551faa37627054c18c4a503reed@android.com // draw nothing 'cause we failed 399f2dbd4db2b41bf7ec551faa37627054c18c4a503reed@android.com glyph->fLeft = 0; 400f2dbd4db2b41bf7ec551faa37627054c18c4a503reed@android.com glyph->fTop = 0; 401f2dbd4db2b41bf7ec551faa37627054c18c4a503reed@android.com glyph->fWidth = 0; 402f2dbd4db2b41bf7ec551faa37627054c18c4a503reed@android.com glyph->fHeight = 0; 40341308ff545b8133f3ace8341e7737b068abeded1reed@android.com // put a valid value here, in case it was earlier set to 40441308ff545b8133f3ace8341e7737b068abeded1reed@android.com // MASK_FORMAT_JUST_ADVANCE 40541308ff545b8133f3ace8341e7737b068abeded1reed@android.com glyph->fMaskFormat = fRec.fMaskFormat; 406bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com} 407bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 408a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com#define SK_SHOW_TEXT_BLIT_COVERAGE 0 409ec0f292459a7b5fb0300c83e456714033ab802fbbungeman@google.com 410ec0f292459a7b5fb0300c83e456714033ab802fbbungeman@google.comstatic void applyLUTToA8Mask(const SkMask& mask, const uint8_t* lut) { 411ec0f292459a7b5fb0300c83e456714033ab802fbbungeman@google.com uint8_t* SK_RESTRICT dst = (uint8_t*)mask.fImage; 412ec0f292459a7b5fb0300c83e456714033ab802fbbungeman@google.com unsigned rowBytes = mask.fRowBytes; 413ec0f292459a7b5fb0300c83e456714033ab802fbbungeman@google.com 414ec0f292459a7b5fb0300c83e456714033ab802fbbungeman@google.com for (int y = mask.fBounds.height() - 1; y >= 0; --y) { 415ec0f292459a7b5fb0300c83e456714033ab802fbbungeman@google.com for (int x = mask.fBounds.width() - 1; x >= 0; --x) { 416ec0f292459a7b5fb0300c83e456714033ab802fbbungeman@google.com dst[x] = lut[dst[x]]; 417ec0f292459a7b5fb0300c83e456714033ab802fbbungeman@google.com } 418ec0f292459a7b5fb0300c83e456714033ab802fbbungeman@google.com dst += rowBytes; 419ec0f292459a7b5fb0300c83e456714033ab802fbbungeman@google.com } 420ec0f292459a7b5fb0300c83e456714033ab802fbbungeman@google.com} 421ec0f292459a7b5fb0300c83e456714033ab802fbbungeman@google.com 4228ebb786eca7079fed1c2d9521e2bf9604bb5825dbungeman@google.comtemplate<bool APPLY_PREBLEND> 423a333d3eba46308e457f88aa62892eec86747b465bungeman@google.comstatic void pack4xHToLCD16(const SkBitmap& src, const SkMask& dst, 424ec0f292459a7b5fb0300c83e456714033ab802fbbungeman@google.com const SkMaskGamma::PreBlend& maskPreBlend) { 425a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com#define SAMPLES_PER_PIXEL 4 426a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com#define LCD_PER_PIXEL 3 427ff10324db62df86ecc52bfc1baa14fc4d8ab849areed@google.com SkASSERT(SkBitmap::kA8_Config == src.config()); 428e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com SkASSERT(SkMask::kLCD16_Format == dst.fFormat); 429935e9f4fafdfc64130e6be9ea2bb30e3bafd852armistry@google.com 430a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com const int sample_width = src.width(); 431a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com const int height = src.height(); 432a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com 433ff10324db62df86ecc52bfc1baa14fc4d8ab849areed@google.com uint16_t* dstP = (uint16_t*)dst.fImage; 434e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com size_t dstRB = dst.fRowBytes; 435a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com // An N tap FIR is defined by 436a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com // out[n] = coeff[0]*x[n] + coeff[1]*x[n-1] + ... + coeff[N]*x[n-N] 437a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com // or 438a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com // out[n] = sum(i, 0, N, coeff[i]*x[n-i]) 439a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com 440a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com // The strategy is to use one FIR (different coefficients) for each of r, g, and b. 441a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com // This means using every 4th FIR output value of each FIR and discarding the rest. 442a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com // The FIRs are aligned, and the coefficients reach 5 samples to each side of their 'center'. 443a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com // (For r and b this is technically incorrect, but the coeffs outside round to zero anyway.) 444fce1688c43b8c11084cb820721a02bce75d0d76bskia.committer@gmail.com 445a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com // These are in some fixed point repesentation. 446a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com // Adding up to more than one simulates ink spread. 447a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com // For implementation reasons, these should never add up to more than two. 448a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com 449a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com // Coefficients determined by a gausian where 5 samples = 3 std deviations (0x110 'contrast'). 450a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com // Calculated using tools/generate_fir_coeff.py 451a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com // With this one almost no fringing is ever seen, but it is imperceptibly blurry. 452a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com // The lcd smoothed text is almost imperceptibly different from gray, 453a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com // but is still sharper on small stems and small rounded corners than gray. 454a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com // This also seems to be about as wide as one can get and only have a three pixel kernel. 455a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com // TODO: caculate these at runtime so parameters can be adjusted (esp contrast). 456a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com static const unsigned int coefficients[LCD_PER_PIXEL][SAMPLES_PER_PIXEL*3] = { 457a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com //The red subpixel is centered inside the first sample (at 1/6 pixel), and is shifted. 458a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com { 0x03, 0x0b, 0x1c, 0x33, 0x40, 0x39, 0x24, 0x10, 0x05, 0x01, 0x00, 0x00, }, 459a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com //The green subpixel is centered between two samples (at 1/2 pixel), so is symetric 460a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com { 0x00, 0x02, 0x08, 0x16, 0x2b, 0x3d, 0x3d, 0x2b, 0x16, 0x08, 0x02, 0x00, }, 461a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com //The blue subpixel is centered inside the last sample (at 5/6 pixel), and is shifted. 462a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com { 0x00, 0x00, 0x01, 0x05, 0x10, 0x24, 0x39, 0x40, 0x33, 0x1c, 0x0b, 0x03, }, 463a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com }; 464935e9f4fafdfc64130e6be9ea2bb30e3bafd852armistry@google.com 465e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com for (int y = 0; y < height; ++y) { 466e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com const uint8_t* srcP = src.getAddr8(0, y); 467a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com 468a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com // TODO: this fir filter implementation is straight forward, but slow. 469a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com // It should be possible to make it much faster. 470a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com for (int sample_x = -4, pixel_x = 0; sample_x < sample_width + 4; sample_x += 4, ++pixel_x) { 471a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com int fir[LCD_PER_PIXEL] = { 0 }; 472a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com for (int sample_index = SkMax32(0, sample_x - 4), coeff_index = sample_index - (sample_x - 4) 473a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com ; sample_index < SkMin32(sample_x + 8, sample_width) 474a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com ; ++sample_index, ++coeff_index) 475a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com { 476a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com int sample_value = srcP[sample_index]; 477a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com for (int subpxl_index = 0; subpxl_index < LCD_PER_PIXEL; ++subpxl_index) { 478a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com fir[subpxl_index] += coefficients[subpxl_index][coeff_index] * sample_value; 479a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com } 480a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com } 481a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com for (int subpxl_index = 0; subpxl_index < LCD_PER_PIXEL; ++subpxl_index) { 482a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com fir[subpxl_index] /= 0x100; 483a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com fir[subpxl_index] = SkMin32(fir[subpxl_index], 255); 484a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com } 485a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com 486a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com U8CPU r = sk_apply_lut_if<APPLY_PREBLEND>(fir[0], maskPreBlend.fR); 487a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com U8CPU g = sk_apply_lut_if<APPLY_PREBLEND>(fir[1], maskPreBlend.fG); 488a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com U8CPU b = sk_apply_lut_if<APPLY_PREBLEND>(fir[2], maskPreBlend.fB); 489a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com#if SK_SHOW_TEXT_BLIT_COVERAGE 490a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com r = SkMax32(r, 10); g = SkMax32(g, 10); b = SkMax32(b, 10); 491a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com#endif 492a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com dstP[pixel_x] = SkPack888ToRGB16(r, g, b); 493e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com } 494e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com dstP = (uint16_t*)((char*)dstP + dstRB); 495e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com } 496e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com} 497ff10324db62df86ecc52bfc1baa14fc4d8ab849areed@google.com 4988ebb786eca7079fed1c2d9521e2bf9604bb5825dbungeman@google.comtemplate<bool APPLY_PREBLEND> 499a333d3eba46308e457f88aa62892eec86747b465bungeman@google.comstatic void pack4xHToLCD32(const SkBitmap& src, const SkMask& dst, 500ec0f292459a7b5fb0300c83e456714033ab802fbbungeman@google.com const SkMaskGamma::PreBlend& maskPreBlend) { 501e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com SkASSERT(SkBitmap::kA8_Config == src.config()); 502e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com SkASSERT(SkMask::kLCD32_Format == dst.fFormat); 503935e9f4fafdfc64130e6be9ea2bb30e3bafd852armistry@google.com 504e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com const int width = dst.fBounds.width(); 505e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com const int height = dst.fBounds.height(); 506ff10324db62df86ecc52bfc1baa14fc4d8ab849areed@google.com SkPMColor* dstP = (SkPMColor*)dst.fImage; 507e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com size_t dstRB = dst.fRowBytes; 508935e9f4fafdfc64130e6be9ea2bb30e3bafd852armistry@google.com 509e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com for (int y = 0; y < height; ++y) { 510e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com const uint8_t* srcP = src.getAddr8(0, y); 511a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com 512a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com // TODO: need to use fir filter here as well. 513e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com for (int x = 0; x < width; ++x) { 514ec0f292459a7b5fb0300c83e456714033ab802fbbungeman@google.com U8CPU r = sk_apply_lut_if<APPLY_PREBLEND>(*srcP++, maskPreBlend.fR); 515ec0f292459a7b5fb0300c83e456714033ab802fbbungeman@google.com U8CPU g = sk_apply_lut_if<APPLY_PREBLEND>(*srcP++, maskPreBlend.fG); 516ec0f292459a7b5fb0300c83e456714033ab802fbbungeman@google.com U8CPU b = sk_apply_lut_if<APPLY_PREBLEND>(*srcP++, maskPreBlend.fB); 5178ebb786eca7079fed1c2d9521e2bf9604bb5825dbungeman@google.com dstP[x] = SkPackARGB32(0xFF, r, g, b); 518ff10324db62df86ecc52bfc1baa14fc4d8ab849areed@google.com } 519ff10324db62df86ecc52bfc1baa14fc4d8ab849areed@google.com dstP = (SkPMColor*)((char*)dstP + dstRB); 520ff10324db62df86ecc52bfc1baa14fc4d8ab849areed@google.com } 521ff10324db62df86ecc52bfc1baa14fc4d8ab849areed@google.com} 522ff10324db62df86ecc52bfc1baa14fc4d8ab849areed@google.com 523ec0f292459a7b5fb0300c83e456714033ab802fbbungeman@google.comstatic void generateMask(const SkMask& mask, const SkPath& path, 524ec0f292459a7b5fb0300c83e456714033ab802fbbungeman@google.com const SkMaskGamma::PreBlend& maskPreBlend) { 525e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com SkBitmap::Config config; 526e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com SkPaint paint; 527e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com 528e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com int srcW = mask.fBounds.width(); 529e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com int srcH = mask.fBounds.height(); 530e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com int dstW = srcW; 531e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com int dstH = srcH; 532e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com int dstRB = mask.fRowBytes; 533e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com 534e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com SkMatrix matrix; 535e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com matrix.setTranslate(-SkIntToScalar(mask.fBounds.fLeft), 536e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com -SkIntToScalar(mask.fBounds.fTop)); 537e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com 538e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com if (SkMask::kBW_Format == mask.fFormat) { 539e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com config = SkBitmap::kA1_Config; 540e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com paint.setAntiAlias(false); 541e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com } else { 542e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com config = SkBitmap::kA8_Config; 543e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com paint.setAntiAlias(true); 544e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com switch (mask.fFormat) { 545e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com case SkMask::kA8_Format: 546e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com break; 547e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com case SkMask::kLCD16_Format: 548e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com case SkMask::kLCD32_Format: 549e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com // TODO: trigger off LCD orientation 550a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com dstW = 4*dstW - 8; 551a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com matrix.setTranslate(-SkIntToScalar(mask.fBounds.fLeft + 1), 552a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com -SkIntToScalar(mask.fBounds.fTop)); 553a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com matrix.postScale(SkIntToScalar(4), SK_Scalar1); 554e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com dstRB = 0; // signals we need a copy 555e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com break; 556e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com default: 5572d7de2d243beab591671dfaf535a637b5d305735tomhudson@google.com SkDEBUGFAIL("unexpected mask format"); 558e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com } 559e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com } 560e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com 56126f5a398c38318eb7eab44f72e024ef784d247fareed@google.com SkRasterClip clip; 56226f5a398c38318eb7eab44f72e024ef784d247fareed@google.com clip.setRect(SkIRect::MakeWH(dstW, dstH)); 563e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com 564e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com SkBitmap bm; 565e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com bm.setConfig(config, dstW, dstH, dstRB); 566e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com 567e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com if (0 == dstRB) { 5689ad5278e84fc9b9dcbcee906c9a8355968b7ee3areed@google.com if (!bm.allocPixels()) { 5699ad5278e84fc9b9dcbcee906c9a8355968b7ee3areed@google.com // can't allocate offscreen, so empty the mask and return 5709ad5278e84fc9b9dcbcee906c9a8355968b7ee3areed@google.com sk_bzero(mask.fImage, mask.computeImageSize()); 5719ad5278e84fc9b9dcbcee906c9a8355968b7ee3areed@google.com return; 5729ad5278e84fc9b9dcbcee906c9a8355968b7ee3areed@google.com } 573e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com bm.lockPixels(); 574e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com } else { 575e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com bm.setPixels(mask.fImage); 576e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com } 577e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com sk_bzero(bm.getPixels(), bm.getSafeSize()); 578935e9f4fafdfc64130e6be9ea2bb30e3bafd852armistry@google.com 579e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com SkDraw draw; 58026f5a398c38318eb7eab44f72e024ef784d247fareed@google.com draw.fRC = &clip; 58126f5a398c38318eb7eab44f72e024ef784d247fareed@google.com draw.fClip = &clip.bwRgn(); 582e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com draw.fMatrix = &matrix; 583e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com draw.fBitmap = &bm; 584e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com draw.drawPath(path, paint); 585935e9f4fafdfc64130e6be9ea2bb30e3bafd852armistry@google.com 5862a6aad8454b4438f95df776bcc28f7860a650748bungeman@google.com switch (mask.fFormat) { 5872a6aad8454b4438f95df776bcc28f7860a650748bungeman@google.com case SkMask::kA8_Format: 5882a6aad8454b4438f95df776bcc28f7860a650748bungeman@google.com if (maskPreBlend.isApplicable()) { 5892a6aad8454b4438f95df776bcc28f7860a650748bungeman@google.com applyLUTToA8Mask(mask, maskPreBlend.fG); 5902a6aad8454b4438f95df776bcc28f7860a650748bungeman@google.com } 5912a6aad8454b4438f95df776bcc28f7860a650748bungeman@google.com break; 5922a6aad8454b4438f95df776bcc28f7860a650748bungeman@google.com case SkMask::kLCD16_Format: 5932a6aad8454b4438f95df776bcc28f7860a650748bungeman@google.com if (maskPreBlend.isApplicable()) { 594a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com pack4xHToLCD16<true>(bm, mask, maskPreBlend); 5952a6aad8454b4438f95df776bcc28f7860a650748bungeman@google.com } else { 596a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com pack4xHToLCD16<false>(bm, mask, maskPreBlend); 5972a6aad8454b4438f95df776bcc28f7860a650748bungeman@google.com } 5982a6aad8454b4438f95df776bcc28f7860a650748bungeman@google.com break; 5992a6aad8454b4438f95df776bcc28f7860a650748bungeman@google.com case SkMask::kLCD32_Format: 6002a6aad8454b4438f95df776bcc28f7860a650748bungeman@google.com if (maskPreBlend.isApplicable()) { 601a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com pack4xHToLCD32<true>(bm, mask, maskPreBlend); 6022a6aad8454b4438f95df776bcc28f7860a650748bungeman@google.com } else { 603a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com pack4xHToLCD32<false>(bm, mask, maskPreBlend); 6042a6aad8454b4438f95df776bcc28f7860a650748bungeman@google.com } 6052a6aad8454b4438f95df776bcc28f7860a650748bungeman@google.com break; 6062a6aad8454b4438f95df776bcc28f7860a650748bungeman@google.com default: 6072a6aad8454b4438f95df776bcc28f7860a650748bungeman@google.com break; 608e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com } 609e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com} 610e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com 6116d450fe32babea3eb42b8b76d594bdc0be37529areed@google.comstatic void extract_alpha(const SkMask& dst, 6126d450fe32babea3eb42b8b76d594bdc0be37529areed@google.com const SkPMColor* srcRow, size_t srcRB) { 6136d450fe32babea3eb42b8b76d594bdc0be37529areed@google.com int width = dst.fBounds.width(); 6146d450fe32babea3eb42b8b76d594bdc0be37529areed@google.com int height = dst.fBounds.height(); 6156d450fe32babea3eb42b8b76d594bdc0be37529areed@google.com int dstRB = dst.fRowBytes; 6166d450fe32babea3eb42b8b76d594bdc0be37529areed@google.com uint8_t* dstRow = dst.fImage; 6176d450fe32babea3eb42b8b76d594bdc0be37529areed@google.com 6186d450fe32babea3eb42b8b76d594bdc0be37529areed@google.com for (int y = 0; y < height; ++y) { 6196d450fe32babea3eb42b8b76d594bdc0be37529areed@google.com for (int x = 0; x < width; ++x) { 6206d450fe32babea3eb42b8b76d594bdc0be37529areed@google.com dstRow[x] = SkGetPackedA32(srcRow[x]); 6216d450fe32babea3eb42b8b76d594bdc0be37529areed@google.com } 6226d450fe32babea3eb42b8b76d594bdc0be37529areed@google.com // zero any padding on each row 6236d450fe32babea3eb42b8b76d594bdc0be37529areed@google.com for (int x = width; x < dstRB; ++x) { 6246d450fe32babea3eb42b8b76d594bdc0be37529areed@google.com dstRow[x] = 0; 6256d450fe32babea3eb42b8b76d594bdc0be37529areed@google.com } 6266d450fe32babea3eb42b8b76d594bdc0be37529areed@google.com dstRow += dstRB; 6276d450fe32babea3eb42b8b76d594bdc0be37529areed@google.com srcRow = (const SkPMColor*)((const char*)srcRow + srcRB); 6286d450fe32babea3eb42b8b76d594bdc0be37529areed@google.com } 6296d450fe32babea3eb42b8b76d594bdc0be37529areed@google.com} 6306d450fe32babea3eb42b8b76d594bdc0be37529areed@google.com 631bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.comvoid SkScalerContext::getImage(const SkGlyph& origGlyph) { 632bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com const SkGlyph* glyph = &origGlyph; 633bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com SkGlyph tmpGlyph; 634935e9f4fafdfc64130e6be9ea2bb30e3bafd852armistry@google.com 6356d450fe32babea3eb42b8b76d594bdc0be37529areed@google.com // in case we need to call generateImage on a mask-format that is different 6366d450fe32babea3eb42b8b76d594bdc0be37529areed@google.com // (i.e. larger) than what our caller allocated by looking at origGlyph. 6376d450fe32babea3eb42b8b76d594bdc0be37529areed@google.com SkAutoMalloc tmpGlyphImageStorage; 6386d450fe32babea3eb42b8b76d594bdc0be37529areed@google.com 6396d450fe32babea3eb42b8b76d594bdc0be37529areed@google.com // If we are going to draw-from-path, then we cannot generate color, since 6406d450fe32babea3eb42b8b76d594bdc0be37529areed@google.com // the path only makes a mask. This case should have been caught up in 6416d450fe32babea3eb42b8b76d594bdc0be37529areed@google.com // generateMetrics(). 6426d450fe32babea3eb42b8b76d594bdc0be37529areed@google.com SkASSERT(!fGenerateImageFromPath || 6436d450fe32babea3eb42b8b76d594bdc0be37529areed@google.com SkMask::kARGB32_Format != origGlyph.fMaskFormat); 6446d450fe32babea3eb42b8b76d594bdc0be37529areed@google.com 645bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com if (fMaskFilter) { // restore the prefilter bounds 646fdc8827831e99c91887497125df6a5143c126765reed@google.com tmpGlyph.init(origGlyph.fID); 647bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 648bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com // need the original bounds, sans our maskfilter 649bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com SkMaskFilter* mf = fMaskFilter; 650bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com fMaskFilter = NULL; // temp disable 651bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com this->getMetrics(&tmpGlyph); 652bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com fMaskFilter = mf; // restore 653bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 654bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com // we need the prefilter bounds to be <= filter bounds 655bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com SkASSERT(tmpGlyph.fWidth <= origGlyph.fWidth); 656bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com SkASSERT(tmpGlyph.fHeight <= origGlyph.fHeight); 6576d450fe32babea3eb42b8b76d594bdc0be37529areed@google.com 6586d450fe32babea3eb42b8b76d594bdc0be37529areed@google.com if (tmpGlyph.fMaskFormat == origGlyph.fMaskFormat) { 6596d450fe32babea3eb42b8b76d594bdc0be37529areed@google.com tmpGlyph.fImage = origGlyph.fImage; 6606d450fe32babea3eb42b8b76d594bdc0be37529areed@google.com } else { 6616d450fe32babea3eb42b8b76d594bdc0be37529areed@google.com tmpGlyphImageStorage.reset(tmpGlyph.computeImageSize()); 6626d450fe32babea3eb42b8b76d594bdc0be37529areed@google.com tmpGlyph.fImage = tmpGlyphImageStorage.get(); 6636d450fe32babea3eb42b8b76d594bdc0be37529areed@google.com } 664bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com glyph = &tmpGlyph; 665bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } 666bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 667ff10324db62df86ecc52bfc1baa14fc4d8ab849areed@google.com if (fGenerateImageFromPath) { 668bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com SkPath devPath, fillPath; 669bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com SkMatrix fillToDevMatrix; 670e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com SkMask mask; 671bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 672bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com this->internalGetPath(*glyph, &fillPath, &devPath, &fillToDevMatrix); 673e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com glyph->toMask(&mask); 674bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 675bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com if (fRasterizer) { 676bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com mask.fFormat = SkMask::kA8_Format; 6775eafe260fa3574ec71eccb5519f41b8095f56562reed@android.com sk_bzero(glyph->fImage, mask.computeImageSize()); 678919114813d58933c9d9433b141e0222c34b700b1reed@google.com 679bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com if (!fRasterizer->rasterize(fillPath, fillToDevMatrix, NULL, 680bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com fMaskFilter, &mask, 681bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com SkMask::kJustRenderImage_CreateMode)) { 682bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com return; 683bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } 684ec0f292459a7b5fb0300c83e456714033ab802fbbungeman@google.com if (fPreBlend.isApplicable()) { 685ec0f292459a7b5fb0300c83e456714033ab802fbbungeman@google.com applyLUTToA8Mask(mask, fPreBlend.fG); 6868ebb786eca7079fed1c2d9521e2bf9604bb5825dbungeman@google.com } 687bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } else { 6886d450fe32babea3eb42b8b76d594bdc0be37529areed@google.com SkASSERT(SkMask::kARGB32_Format != mask.fFormat); 689ec0f292459a7b5fb0300c83e456714033ab802fbbungeman@google.com generateMask(mask, devPath, fPreBlend); 690bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } 691bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } else { 692ec0f292459a7b5fb0300c83e456714033ab802fbbungeman@google.com this->getGlyphContext(*glyph)->generateImage(*glyph); 693bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } 694bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 695bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com if (fMaskFilter) { 696bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com SkMask srcM, dstM; 697bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com SkMatrix matrix; 698bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 699bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com // the src glyph image shouldn't be 3D 700bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com SkASSERT(SkMask::k3D_Format != glyph->fMaskFormat); 7016d450fe32babea3eb42b8b76d594bdc0be37529areed@google.com 7026d450fe32babea3eb42b8b76d594bdc0be37529areed@google.com SkAutoSMalloc<32*32> a8storage; 703bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com glyph->toMask(&srcM); 7046d450fe32babea3eb42b8b76d594bdc0be37529areed@google.com if (SkMask::kARGB32_Format == srcM.fFormat) { 7056d450fe32babea3eb42b8b76d594bdc0be37529areed@google.com // now we need to extract the alpha-channel from the glyph's image 7066d450fe32babea3eb42b8b76d594bdc0be37529areed@google.com // and copy it into a temp buffer, and then point srcM at that temp. 7076d450fe32babea3eb42b8b76d594bdc0be37529areed@google.com srcM.fFormat = SkMask::kA8_Format; 7086d450fe32babea3eb42b8b76d594bdc0be37529areed@google.com srcM.fRowBytes = SkAlign4(srcM.fBounds.width()); 7096d450fe32babea3eb42b8b76d594bdc0be37529areed@google.com size_t size = srcM.computeImageSize(); 7106d450fe32babea3eb42b8b76d594bdc0be37529areed@google.com a8storage.reset(size); 7116d450fe32babea3eb42b8b76d594bdc0be37529areed@google.com srcM.fImage = (uint8_t*)a8storage.get(); 7126d450fe32babea3eb42b8b76d594bdc0be37529areed@google.com extract_alpha(srcM, 7136d450fe32babea3eb42b8b76d594bdc0be37529areed@google.com (const SkPMColor*)glyph->fImage, glyph->rowBytes()); 7146d450fe32babea3eb42b8b76d594bdc0be37529areed@google.com } 71574546d80ff050eecbf2d3a21194f10860504e68dskia.committer@gmail.com 716bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com fRec.getMatrixFrom2x2(&matrix); 717bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 718bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com if (fMaskFilter->filterMask(&dstM, srcM, matrix, NULL)) { 719bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com int width = SkFastMin32(origGlyph.fWidth, dstM.fBounds.width()); 720bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com int height = SkFastMin32(origGlyph.fHeight, dstM.fBounds.height()); 721bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com int dstRB = origGlyph.rowBytes(); 722bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com int srcRB = dstM.fRowBytes; 723919114813d58933c9d9433b141e0222c34b700b1reed@google.com 724bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com const uint8_t* src = (const uint8_t*)dstM.fImage; 725bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com uint8_t* dst = (uint8_t*)origGlyph.fImage; 726bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 727bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com if (SkMask::k3D_Format == dstM.fFormat) { 728bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com // we have to copy 3 times as much 729bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com height *= 3; 730bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } 731bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 732bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com // clean out our glyph, since it may be larger than dstM 7335eafe260fa3574ec71eccb5519f41b8095f56562reed@android.com //sk_bzero(dst, height * dstRB); 734bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 735bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com while (--height >= 0) { 736bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com memcpy(dst, src, width); 737bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com src += srcRB; 738bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com dst += dstRB; 739bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } 740bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com SkMask::FreeImage(dstM.fImage); 7418ebb786eca7079fed1c2d9521e2bf9604bb5825dbungeman@google.com 742ec0f292459a7b5fb0300c83e456714033ab802fbbungeman@google.com if (fPreBlendForFilter.isApplicable()) { 743ec0f292459a7b5fb0300c83e456714033ab802fbbungeman@google.com applyLUTToA8Mask(srcM, fPreBlendForFilter.fG); 744ec0f292459a7b5fb0300c83e456714033ab802fbbungeman@google.com } 745bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } 746bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } 747bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com} 748bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 74902a9b1d3258a7a0d74344e5c84313b36fcd2a8c2reed@google.comvoid SkScalerContext::getPath(const SkGlyph& glyph, SkPath* path) { 750bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com this->internalGetPath(glyph, NULL, path, NULL); 751bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com} 752bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 7532f45f0074cf3f265711b74eb3a1d757ae4b2ce02reed@google.comvoid SkScalerContext::getFontMetrics(SkPaint::FontMetrics* fm) { 7542f45f0074cf3f265711b74eb3a1d757ae4b2ce02reed@google.com // All of this complexity should go away when we change generateFontMetrics 7552f45f0074cf3f265711b74eb3a1d757ae4b2ce02reed@google.com // to just take one parameter (since it knows if it is vertical or not) 7562f45f0074cf3f265711b74eb3a1d757ae4b2ce02reed@google.com SkPaint::FontMetrics* mx = NULL; 7572f45f0074cf3f265711b74eb3a1d757ae4b2ce02reed@google.com SkPaint::FontMetrics* my = NULL; 7582f45f0074cf3f265711b74eb3a1d757ae4b2ce02reed@google.com if (fRec.fFlags & kVertical_Flag) { 7592f45f0074cf3f265711b74eb3a1d757ae4b2ce02reed@google.com mx = fm; 7602f45f0074cf3f265711b74eb3a1d757ae4b2ce02reed@google.com } else { 7612f45f0074cf3f265711b74eb3a1d757ae4b2ce02reed@google.com my = fm; 7622f45f0074cf3f265711b74eb3a1d757ae4b2ce02reed@google.com } 763bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com this->generateFontMetrics(mx, my); 764bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com} 765bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 766739245e986d7a78b96129f559363b7ab6fb0a21creed@android.comSkUnichar SkScalerContext::generateGlyphToChar(uint16_t glyph) { 767739245e986d7a78b96129f559363b7ab6fb0a21creed@android.com return 0; 768739245e986d7a78b96129f559363b7ab6fb0a21creed@android.com} 769739245e986d7a78b96129f559363b7ab6fb0a21creed@android.com 77002a9b1d3258a7a0d74344e5c84313b36fcd2a8c2reed@google.com/////////////////////////////////////////////////////////////////////////////// 771bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 77202a9b1d3258a7a0d74344e5c84313b36fcd2a8c2reed@google.comvoid SkScalerContext::internalGetPath(const SkGlyph& glyph, SkPath* fillPath, 77302a9b1d3258a7a0d74344e5c84313b36fcd2a8c2reed@google.com SkPath* devPath, SkMatrix* fillToDevMatrix) { 774bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com SkPath path; 775bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 776bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com this->getGlyphContext(glyph)->generatePath(glyph, &path); 777919114813d58933c9d9433b141e0222c34b700b1reed@google.com 778e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com if (fRec.fFlags & SkScalerContext::kSubpixelPositioning_Flag) { 779e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com SkFixed dx = glyph.getSubXFixed(); 780e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com SkFixed dy = glyph.getSubYFixed(); 781e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com if (dx | dy) { 782e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com path.offset(SkFixedToScalar(dx), SkFixedToScalar(dy)); 783e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com } 784e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com } 785e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com 78602a9b1d3258a7a0d74344e5c84313b36fcd2a8c2reed@google.com if (fRec.fFrameWidth > 0 || fPathEffect != NULL) { 787bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com // need the path in user-space, with only the point-size applied 788bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com // so that our stroking and effects will operate the same way they 789bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com // would if the user had extracted the path themself, and then 790bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com // called drawPath 791bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com SkPath localPath; 792bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com SkMatrix matrix, inverse; 793bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 794bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com fRec.getMatrixFrom2x2(&matrix); 79585b2aaca4e634952568fb7c226c99fc162c034febungeman@google.com if (!matrix.invert(&inverse)) { 79685b2aaca4e634952568fb7c226c99fc162c034febungeman@google.com // assume fillPath and devPath are already empty. 79785b2aaca4e634952568fb7c226c99fc162c034febungeman@google.com return; 79885b2aaca4e634952568fb7c226c99fc162c034febungeman@google.com } 799bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com path.transform(inverse, &localPath); 800bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com // now localPath is only affected by the paint settings, and not the canvas matrix 801bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 802d49b87f7307690e47c5cb093ff9d7cce4f009e87reed@google.com SkStrokeRec rec(SkStrokeRec::kFill_InitStyle); 803935e9f4fafdfc64130e6be9ea2bb30e3bafd852armistry@google.com 804d49b87f7307690e47c5cb093ff9d7cce4f009e87reed@google.com if (fRec.fFrameWidth > 0) { 805d49b87f7307690e47c5cb093ff9d7cce4f009e87reed@google.com rec.setStrokeStyle(fRec.fFrameWidth, 806d49b87f7307690e47c5cb093ff9d7cce4f009e87reed@google.com SkToBool(fRec.fFlags & kFrameAndFill_Flag)); 807d49b87f7307690e47c5cb093ff9d7cce4f009e87reed@google.com // glyphs are always closed contours, so cap type is ignored, 808d49b87f7307690e47c5cb093ff9d7cce4f009e87reed@google.com // so we just pass something. 809d49b87f7307690e47c5cb093ff9d7cce4f009e87reed@google.com rec.setStrokeParams(SkPaint::kButt_Cap, 810d49b87f7307690e47c5cb093ff9d7cce4f009e87reed@google.com (SkPaint::Join)fRec.fStrokeJoin, 811d49b87f7307690e47c5cb093ff9d7cce4f009e87reed@google.com fRec.fMiterLimit); 812d49b87f7307690e47c5cb093ff9d7cce4f009e87reed@google.com } 813935e9f4fafdfc64130e6be9ea2bb30e3bafd852armistry@google.com 81402a9b1d3258a7a0d74344e5c84313b36fcd2a8c2reed@google.com if (fPathEffect) { 815bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com SkPath effectPath; 816bb77acf17c4eb4f58b6bfbe48d750d018485ecf2reed@google.com if (fPathEffect->filterPath(&effectPath, localPath, &rec, NULL)) { 817bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com localPath.swap(effectPath); 81802a9b1d3258a7a0d74344e5c84313b36fcd2a8c2reed@google.com } 819bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } 820bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 821d49b87f7307690e47c5cb093ff9d7cce4f009e87reed@google.com if (rec.needToApply()) { 822d49b87f7307690e47c5cb093ff9d7cce4f009e87reed@google.com SkPath strokePath; 823d49b87f7307690e47c5cb093ff9d7cce4f009e87reed@google.com if (rec.applyToPath(&strokePath, localPath)) { 824d49b87f7307690e47c5cb093ff9d7cce4f009e87reed@google.com localPath.swap(strokePath); 825d49b87f7307690e47c5cb093ff9d7cce4f009e87reed@google.com } 826bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } 827919114813d58933c9d9433b141e0222c34b700b1reed@google.com 828bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com // now return stuff to the caller 82902a9b1d3258a7a0d74344e5c84313b36fcd2a8c2reed@google.com if (fillToDevMatrix) { 830bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com *fillToDevMatrix = matrix; 83102a9b1d3258a7a0d74344e5c84313b36fcd2a8c2reed@google.com } 83202a9b1d3258a7a0d74344e5c84313b36fcd2a8c2reed@google.com if (devPath) { 833bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com localPath.transform(matrix, devPath); 83402a9b1d3258a7a0d74344e5c84313b36fcd2a8c2reed@google.com } 83502a9b1d3258a7a0d74344e5c84313b36fcd2a8c2reed@google.com if (fillPath) { 836bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com fillPath->swap(localPath); 83702a9b1d3258a7a0d74344e5c84313b36fcd2a8c2reed@google.com } 83802a9b1d3258a7a0d74344e5c84313b36fcd2a8c2reed@google.com } else { // nothing tricky to do 83902a9b1d3258a7a0d74344e5c84313b36fcd2a8c2reed@google.com if (fillToDevMatrix) { 840bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com fillToDevMatrix->reset(); 84102a9b1d3258a7a0d74344e5c84313b36fcd2a8c2reed@google.com } 84202a9b1d3258a7a0d74344e5c84313b36fcd2a8c2reed@google.com if (devPath) { 84302a9b1d3258a7a0d74344e5c84313b36fcd2a8c2reed@google.com if (fillPath == NULL) { 844bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com devPath->swap(path); 84502a9b1d3258a7a0d74344e5c84313b36fcd2a8c2reed@google.com } else { 846bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com *devPath = path; 84702a9b1d3258a7a0d74344e5c84313b36fcd2a8c2reed@google.com } 848bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } 849919114813d58933c9d9433b141e0222c34b700b1reed@google.com 85002a9b1d3258a7a0d74344e5c84313b36fcd2a8c2reed@google.com if (fillPath) { 851bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com fillPath->swap(path); 85202a9b1d3258a7a0d74344e5c84313b36fcd2a8c2reed@google.com } 853bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } 854919114813d58933c9d9433b141e0222c34b700b1reed@google.com 85502a9b1d3258a7a0d74344e5c84313b36fcd2a8c2reed@google.com if (devPath) { 856bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com devPath->updateBoundsCache(); 85702a9b1d3258a7a0d74344e5c84313b36fcd2a8c2reed@google.com } 85802a9b1d3258a7a0d74344e5c84313b36fcd2a8c2reed@google.com if (fillPath) { 859bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com fillPath->updateBoundsCache(); 86002a9b1d3258a7a0d74344e5c84313b36fcd2a8c2reed@google.com } 861bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com} 862bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 863bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 864d765b1f62822099898688837ea0f73d698db4f8areed@google.comvoid SkScalerContextRec::getMatrixFrom2x2(SkMatrix* dst) const { 865f9657f297bb01db7d8ae4edcbc766354df1b0200bungeman@google.com dst->setAll(fPost2x2[0][0], fPost2x2[0][1], 0, 866f9657f297bb01db7d8ae4edcbc766354df1b0200bungeman@google.com fPost2x2[1][0], fPost2x2[1][1], 0, 867f9657f297bb01db7d8ae4edcbc766354df1b0200bungeman@google.com 0, 0, SkScalarToPersp(SK_Scalar1)); 868bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com} 869bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 870d765b1f62822099898688837ea0f73d698db4f8areed@google.comvoid SkScalerContextRec::getLocalMatrix(SkMatrix* m) const { 8714ea89a7639423dfa5aabed6830a71fc09d014196reed@google.com SkPaint::SetTextMatrix(m, fTextSize, fPreScaleX, fPreSkewX); 872bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com} 873bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 874d765b1f62822099898688837ea0f73d698db4f8areed@google.comvoid SkScalerContextRec::getSingleMatrix(SkMatrix* m) const { 875bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com this->getLocalMatrix(m); 876bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 877bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com // now concat the device matrix 87802a9b1d3258a7a0d74344e5c84313b36fcd2a8c2reed@google.com SkMatrix deviceMatrix; 87902a9b1d3258a7a0d74344e5c84313b36fcd2a8c2reed@google.com this->getMatrixFrom2x2(&deviceMatrix); 88002a9b1d3258a7a0d74344e5c84313b36fcd2a8c2reed@google.com m->postConcat(deviceMatrix); 881bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com} 882bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 883454aadd1dba42a701e7bb9bc73f7c7e76a99700freed@google.comSkAxisAlignment SkComputeAxisAlignmentForHText(const SkMatrix& matrix) { 884454aadd1dba42a701e7bb9bc73f7c7e76a99700freed@google.com SkASSERT(!matrix.hasPerspective()); 885935e9f4fafdfc64130e6be9ea2bb30e3bafd852armistry@google.com 886454aadd1dba42a701e7bb9bc73f7c7e76a99700freed@google.com if (0 == matrix[SkMatrix::kMSkewY]) { 887454aadd1dba42a701e7bb9bc73f7c7e76a99700freed@google.com return kX_SkAxisAlignment; 888454aadd1dba42a701e7bb9bc73f7c7e76a99700freed@google.com } 889454aadd1dba42a701e7bb9bc73f7c7e76a99700freed@google.com if (0 == matrix[SkMatrix::kMScaleX]) { 890454aadd1dba42a701e7bb9bc73f7c7e76a99700freed@google.com return kY_SkAxisAlignment; 891454aadd1dba42a701e7bb9bc73f7c7e76a99700freed@google.com } 892454aadd1dba42a701e7bb9bc73f7c7e76a99700freed@google.com return kNone_SkAxisAlignment; 893454aadd1dba42a701e7bb9bc73f7c7e76a99700freed@google.com} 894454aadd1dba42a701e7bb9bc73f7c7e76a99700freed@google.com 895efc74b8af0ee522065266db255e9bc48c8ceaceereed@android.com/////////////////////////////////////////////////////////////////////////////// 896efc74b8af0ee522065266db255e9bc48c8ceaceereed@android.com 897bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#include "SkFontHost.h" 898bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 899efc74b8af0ee522065266db255e9bc48c8ceaceereed@android.comclass SkScalerContext_Empty : public SkScalerContext { 900efc74b8af0ee522065266db255e9bc48c8ceaceereed@android.compublic: 9018e01453029702b114d4eb939e4fbe7fd33b57b50reed@google.com SkScalerContext_Empty(SkTypeface* face, const SkDescriptor* desc) 9028e01453029702b114d4eb939e4fbe7fd33b57b50reed@google.com : SkScalerContext(face, desc) {} 903efc74b8af0ee522065266db255e9bc48c8ceaceereed@android.com 904efc74b8af0ee522065266db255e9bc48c8ceaceereed@android.comprotected: 905ec0f292459a7b5fb0300c83e456714033ab802fbbungeman@google.com virtual unsigned generateGlyphCount() SK_OVERRIDE { 906efc74b8af0ee522065266db255e9bc48c8ceaceereed@android.com return 0; 907efc74b8af0ee522065266db255e9bc48c8ceaceereed@android.com } 908ec0f292459a7b5fb0300c83e456714033ab802fbbungeman@google.com virtual uint16_t generateCharToGlyph(SkUnichar uni) SK_OVERRIDE { 909efc74b8af0ee522065266db255e9bc48c8ceaceereed@android.com return 0; 910efc74b8af0ee522065266db255e9bc48c8ceaceereed@android.com } 911ec0f292459a7b5fb0300c83e456714033ab802fbbungeman@google.com virtual void generateAdvance(SkGlyph* glyph) SK_OVERRIDE { 912efc74b8af0ee522065266db255e9bc48c8ceaceereed@android.com glyph->zeroMetrics(); 913efc74b8af0ee522065266db255e9bc48c8ceaceereed@android.com } 914ec0f292459a7b5fb0300c83e456714033ab802fbbungeman@google.com virtual void generateMetrics(SkGlyph* glyph) SK_OVERRIDE { 915efc74b8af0ee522065266db255e9bc48c8ceaceereed@android.com glyph->zeroMetrics(); 916efc74b8af0ee522065266db255e9bc48c8ceaceereed@android.com } 917ec0f292459a7b5fb0300c83e456714033ab802fbbungeman@google.com virtual void generateImage(const SkGlyph& glyph) SK_OVERRIDE {} 918ec0f292459a7b5fb0300c83e456714033ab802fbbungeman@google.com virtual void generatePath(const SkGlyph& glyph, SkPath* path) SK_OVERRIDE {} 919efc74b8af0ee522065266db255e9bc48c8ceaceereed@android.com virtual void generateFontMetrics(SkPaint::FontMetrics* mx, 920ec0f292459a7b5fb0300c83e456714033ab802fbbungeman@google.com SkPaint::FontMetrics* my) SK_OVERRIDE { 921efc74b8af0ee522065266db255e9bc48c8ceaceereed@android.com if (mx) { 9225eafe260fa3574ec71eccb5519f41b8095f56562reed@android.com sk_bzero(mx, sizeof(*mx)); 923efc74b8af0ee522065266db255e9bc48c8ceaceereed@android.com } 924efc74b8af0ee522065266db255e9bc48c8ceaceereed@android.com if (my) { 9255eafe260fa3574ec71eccb5519f41b8095f56562reed@android.com sk_bzero(my, sizeof(*my)); 926efc74b8af0ee522065266db255e9bc48c8ceaceereed@android.com } 927efc74b8af0ee522065266db255e9bc48c8ceaceereed@android.com } 928efc74b8af0ee522065266db255e9bc48c8ceaceereed@android.com}; 929efc74b8af0ee522065266db255e9bc48c8ceaceereed@android.com 930e216b62841acd5db9d91b63960805568259a2e0ereed@android.comextern SkScalerContext* SkCreateColorScalerContext(const SkDescriptor* desc); 931e216b62841acd5db9d91b63960805568259a2e0ereed@android.com 932bcb996959ff24d7cc2c5cbaa1b4dd5b47bb9c8ccreed@google.comSkScalerContext* SkTypeface::createScalerContext(const SkDescriptor* desc, 933bcb996959ff24d7cc2c5cbaa1b4dd5b47bb9c8ccreed@google.com bool allowFailure) const { 934bcb996959ff24d7cc2c5cbaa1b4dd5b47bb9c8ccreed@google.com SkScalerContext* c = this->onCreateScalerContext(desc); 935bcb996959ff24d7cc2c5cbaa1b4dd5b47bb9c8ccreed@google.com 936bcb996959ff24d7cc2c5cbaa1b4dd5b47bb9c8ccreed@google.com if (!c && !allowFailure) { 9378e01453029702b114d4eb939e4fbe7fd33b57b50reed@google.com c = SkNEW_ARGS(SkScalerContext_Empty, 9388e01453029702b114d4eb939e4fbe7fd33b57b50reed@google.com (const_cast<SkTypeface*>(this), desc)); 939efc74b8af0ee522065266db255e9bc48c8ceaceereed@android.com } 940efc74b8af0ee522065266db255e9bc48c8ceaceereed@android.com return c; 941bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com} 942