1ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com 2ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com/* 3ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Copyright 2006 The Android Open Source Project 4ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * 5ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Use of this source code is governed by a BSD-style license that can be 6ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * found in the LICENSE file. 7ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com */ 8ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com 98a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkScalerContext.h" 11309485b7b51f4cae4c0361ab4da00fe9cc89515cagl@chromium.org#include "SkColorPriv.h" 128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkDescriptor.h" 138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkDraw.h" 148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkFontHost.h" 15bbe50131413098bffed9186660c41f047d881596bungeman@google.com#include "SkGlyph.h" 168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkMaskFilter.h" 1797efada074e4806479f1350ab1508939c2fdcb53bungeman@google.com#include "SkMaskGamma.h" 188b0e8ac5f582de80356019406e2975079bf0829dcommit-bot@chromium.org#include "SkReadBuffer.h" 198b0e8ac5f582de80356019406e2975079bf0829dcommit-bot@chromium.org#include "SkWriteBuffer.h" 208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkPathEffect.h" 218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkRasterizer.h" 22045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com#include "SkRasterClip.h" 238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkStroke.h" 248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkThread.h" 258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#define ComputeBWRowBytes(width) (((unsigned)(width) + 7) >> 3) 278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkGlyph::toMask(SkMask* mask) const { 298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkASSERT(mask); 308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com mask->fImage = (uint8_t*)fImage; 328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com mask->fBounds.set(fLeft, fTop, fLeft + fWidth, fTop + fHeight); 338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com mask->fRowBytes = this->rowBytes(); 346c14b43a840c791699747ba4cc0ed5abf2bda218reed@android.com mask->fFormat = static_cast<SkMask::Format>(fMaskFormat); 358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comsize_t SkGlyph::computeImageSize() const { 38309485b7b51f4cae4c0361ab4da00fe9cc89515cagl@chromium.org const size_t size = this->rowBytes() * fHeight; 39309485b7b51f4cae4c0361ab4da00fe9cc89515cagl@chromium.org 40309485b7b51f4cae4c0361ab4da00fe9cc89515cagl@chromium.org switch (fMaskFormat) { 417db9fe65b2bb099e9dc41f79cc15b6a7a142bed6reed@google.com case SkMask::k3D_Format: 427db9fe65b2bb099e9dc41f79cc15b6a7a142bed6reed@google.com return 3 * size; 437db9fe65b2bb099e9dc41f79cc15b6a7a142bed6reed@google.com default: 447db9fe65b2bb099e9dc41f79cc15b6a7a142bed6reed@google.com return size; 458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 4862900b4c64401bc80ae85f6f5c87309a273cae10reed@android.comvoid SkGlyph::zeroMetrics() { 4962900b4c64401bc80ae85f6f5c87309a273cae10reed@android.com fAdvanceX = 0; 5062900b4c64401bc80ae85f6f5c87309a273cae10reed@android.com fAdvanceY = 0; 5162900b4c64401bc80ae85f6f5c87309a273cae10reed@android.com fWidth = 0; 5262900b4c64401bc80ae85f6f5c87309a273cae10reed@android.com fHeight = 0; 5362900b4c64401bc80ae85f6f5c87309a273cae10reed@android.com fTop = 0; 5462900b4c64401bc80ae85f6f5c87309a273cae10reed@android.com fLeft = 0; 5562900b4c64401bc80ae85f6f5c87309a273cae10reed@android.com fRsbDelta = 0; 5662900b4c64401bc80ae85f6f5c87309a273cae10reed@android.com fLsbDelta = 0; 5762900b4c64401bc80ae85f6f5c87309a273cae10reed@android.com} 5862900b4c64401bc80ae85f6f5c87309a273cae10reed@android.com 5962900b4c64401bc80ae85f6f5c87309a273cae10reed@android.com/////////////////////////////////////////////////////////////////////////////// 6062900b4c64401bc80ae85f6f5c87309a273cae10reed@android.com 618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#ifdef SK_DEBUG 628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com #define DUMP_RECx 638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#endif 648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 65353482251e61971a8cf3a60bbb6910f482be634freed@google.comstatic SkFlattenable* load_flattenable(const SkDescriptor* desc, uint32_t tag, 66c0b7e10c6a68f59e1653e6c18e6bc954b3c3f0cfcommit-bot@chromium.org SkFlattenable::Type ft) { 678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkFlattenable* obj = NULL; 688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com uint32_t len; 698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com const void* data = desc->findEntry(tag, &len); 70583b18a20959c9ac360316a366f4ddd9598bdf52skia.committer@gmail.com 718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (data) { 728b0e8ac5f582de80356019406e2975079bf0829dcommit-bot@chromium.org SkReadBuffer buffer(data, len); 73c0b7e10c6a68f59e1653e6c18e6bc954b3c3f0cfcommit-bot@chromium.org obj = buffer.readFlattenable(ft); 748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkASSERT(buffer.offset() == buffer.size()); 758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return obj; 778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 790da48618a758ef46c2174bdc1eaeb6dd8a693a2ereed@google.comSkScalerContext::SkScalerContext(SkTypeface* typeface, const SkDescriptor* desc) 8097efada074e4806479f1350ab1508939c2fdcb53bungeman@google.com : fRec(*static_cast<const Rec*>(desc->findEntry(kRec_SkDescriptorTag, NULL))) 81a76de72a6036da0a6b051b14411b80941971f881bungeman@google.com 820da48618a758ef46c2174bdc1eaeb6dd8a693a2ereed@google.com , fTypeface(SkRef(typeface)) 83c0b7e10c6a68f59e1653e6c18e6bc954b3c3f0cfcommit-bot@chromium.org , fPathEffect(static_cast<SkPathEffect*>(load_flattenable(desc, kPathEffect_SkDescriptorTag, 84c0b7e10c6a68f59e1653e6c18e6bc954b3c3f0cfcommit-bot@chromium.org SkFlattenable::kSkPathEffect_Type))) 85c0b7e10c6a68f59e1653e6c18e6bc954b3c3f0cfcommit-bot@chromium.org , fMaskFilter(static_cast<SkMaskFilter*>(load_flattenable(desc, kMaskFilter_SkDescriptorTag, 86c0b7e10c6a68f59e1653e6c18e6bc954b3c3f0cfcommit-bot@chromium.org SkFlattenable::kSkMaskFilter_Type))) 87c0b7e10c6a68f59e1653e6c18e6bc954b3c3f0cfcommit-bot@chromium.org , fRasterizer(static_cast<SkRasterizer*>(load_flattenable(desc, kRasterizer_SkDescriptorTag, 88c0b7e10c6a68f59e1653e6c18e6bc954b3c3f0cfcommit-bot@chromium.org SkFlattenable::kSkRasterizer_Type))) 89a76de72a6036da0a6b051b14411b80941971f881bungeman@google.com // Initialize based on our settings. Subclasses can also force this. 9097efada074e4806479f1350ab1508939c2fdcb53bungeman@google.com , fGenerateImageFromPath(fRec.fFrameWidth > 0 || fPathEffect != NULL || fRasterizer != NULL) 91a76de72a6036da0a6b051b14411b80941971f881bungeman@google.com 92a76de72a6036da0a6b051b14411b80941971f881bungeman@google.com , fPreBlend(fMaskFilter ? SkMaskGamma::PreBlend() : SkScalerContext::GetMaskPreBlend(fRec)) 93a76de72a6036da0a6b051b14411b80941971f881bungeman@google.com , fPreBlendForFilter(fMaskFilter ? SkScalerContext::GetMaskPreBlend(fRec) 94a76de72a6036da0a6b051b14411b80941971f881bungeman@google.com : SkMaskGamma::PreBlend()) 958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com{ 968a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#ifdef DUMP_REC 978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com desc->assertChecksum(); 9834abef14a637450743e1debccdcdb5bdc2e9ba01commit-bot@chromium.org SkDebugf("SkScalerContext checksum %x count %d length %d\n", 997db9fe65b2bb099e9dc41f79cc15b6a7a142bed6reed@google.com desc->getChecksum(), desc->getCount(), desc->getLength()); 1008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkDebugf(" textsize %g prescale %g preskew %g post [%g %g %g %g]\n", 1018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com rec->fTextSize, rec->fPreScaleX, rec->fPreSkewX, rec->fPost2x2[0][0], 1028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com rec->fPost2x2[0][1], rec->fPost2x2[1][0], rec->fPost2x2[1][1]); 1038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkDebugf(" frame %g miter %g hints %d framefill %d format %d join %d\n", 1048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com rec->fFrameWidth, rec->fMiterLimit, rec->fHints, rec->fFrameAndFill, 1058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com rec->fMaskFormat, rec->fStrokeJoin); 1067db9fe65b2bb099e9dc41f79cc15b6a7a142bed6reed@google.com SkDebugf(" pathEffect %x maskFilter %x\n", 1077db9fe65b2bb099e9dc41f79cc15b6a7a142bed6reed@google.com desc->findEntry(kPathEffect_SkDescriptorTag, NULL), 1088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com desc->findEntry(kMaskFilter_SkDescriptorTag, NULL)); 1098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#endif 1108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 1118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comSkScalerContext::~SkScalerContext() { 11382065d667f64e232bcde2ad849756a6096fcbe6freed@google.com SkSafeUnref(fPathEffect); 11482065d667f64e232bcde2ad849756a6096fcbe6freed@google.com SkSafeUnref(fMaskFilter); 11582065d667f64e232bcde2ad849756a6096fcbe6freed@google.com SkSafeUnref(fRasterizer); 1168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 1178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkScalerContext::getAdvance(SkGlyph* glyph) { 1198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // mark us as just having a valid advance 1208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com glyph->fMaskFormat = MASK_FORMAT_JUST_ADVANCE; 1218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // we mark the format before making the call, in case the impl 1228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // internally ends up calling its generateMetrics, which is OK 1238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // albeit slower than strictly necessary 1241b27704eba15be4e9d1997faac42038493a30be5djsollen generateAdvance(glyph); 1258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 1268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkScalerContext::getMetrics(SkGlyph* glyph) { 1281b27704eba15be4e9d1997faac42038493a30be5djsollen generateMetrics(glyph); 1298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // for now we have separate cache entries for devkerning on and off 1318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // in the future we might share caches, but make our measure/draw 1328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // code make the distinction. Thus we zap the values if the caller 1338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // has not asked for them. 1348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if ((fRec.fFlags & SkScalerContext::kDevKernText_Flag) == 0) { 1358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // no devkern, so zap the fields 1368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com glyph->fLsbDelta = glyph->fRsbDelta = 0; 1378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 1388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // if either dimension is empty, zap the image bounds of the glyph 1408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (0 == glyph->fWidth || 0 == glyph->fHeight) { 1418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com glyph->fWidth = 0; 1428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com glyph->fHeight = 0; 1438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com glyph->fTop = 0; 1448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com glyph->fLeft = 0; 1458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com glyph->fMaskFormat = 0; 1468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return; 1478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 14882065d667f64e232bcde2ad849756a6096fcbe6freed@google.com 149a767fa06ca28be9df1ff6e08a299e0bec839a2dcreed@google.com if (fGenerateImageFromPath) { 1508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkPath devPath, fillPath; 1518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkMatrix fillToDevMatrix; 1528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com this->internalGetPath(*glyph, &fillPath, &devPath, &fillToDevMatrix); 1548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (fRasterizer) { 1568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkMask mask; 1578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (fRasterizer->rasterize(fillPath, fillToDevMatrix, NULL, 1598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fMaskFilter, &mask, 1608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkMask::kJustComputeBounds_CreateMode)) { 1618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com glyph->fLeft = mask.fBounds.fLeft; 1628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com glyph->fTop = mask.fBounds.fTop; 1638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com glyph->fWidth = SkToU16(mask.fBounds.width()); 1648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com glyph->fHeight = SkToU16(mask.fBounds.height()); 1658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } else { 1667767cd87fdadeed868457a2407e8b0a50006fc4asenorblanco@chromium.org goto SK_ERROR; 1678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 1688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } else { 1698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // just use devPath 1708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkIRect ir; 171d252db03d9650013b545ef9781fe993c07f8f314reed@android.com devPath.getBounds().roundOut(&ir); 17282065d667f64e232bcde2ad849756a6096fcbe6freed@google.com 173b757f8d20c582463999bd7aa5a48110e84945d19reed@android.com if (ir.isEmpty() || !ir.is16Bit()) { 1747767cd87fdadeed868457a2407e8b0a50006fc4asenorblanco@chromium.org goto SK_ERROR; 175d4577757874d1dda1a3bffa3f2347c251859c27ereed@android.com } 1768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com glyph->fLeft = ir.fLeft; 1778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com glyph->fTop = ir.fTop; 1788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com glyph->fWidth = SkToU16(ir.width()); 1798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com glyph->fHeight = SkToU16(ir.height()); 1800abbff9987b9452fd30cce198bea34fdb210ac41bungeman@google.com 1810abbff9987b9452fd30cce198bea34fdb210ac41bungeman@google.com if (glyph->fWidth > 0) { 182d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com switch (fRec.fMaskFormat) { 183d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com case SkMask::kLCD16_Format: 184d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com case SkMask::kLCD32_Format: 185d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com glyph->fWidth += 2; 186d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com glyph->fLeft -= 1; 187d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com break; 188d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com default: 189d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com break; 190d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com } 1910abbff9987b9452fd30cce198bea34fdb210ac41bungeman@google.com } 1928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 1938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 1948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 195a22e2117e44efa4298dd0eb6df304a8166c8e9c3robertphillips@google.com if (SkMask::kARGB32_Format != glyph->fMaskFormat) { 196a22e2117e44efa4298dd0eb6df304a8166c8e9c3robertphillips@google.com glyph->fMaskFormat = fRec.fMaskFormat; 197a22e2117e44efa4298dd0eb6df304a8166c8e9c3robertphillips@google.com } 1988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1995bdfb331ac650cf464baa96a49e2473ee10a515creed@google.com // If we are going to create the mask, then we cannot keep the color 2005bdfb331ac650cf464baa96a49e2473ee10a515creed@google.com if ((fGenerateImageFromPath || fMaskFilter) && 2015bdfb331ac650cf464baa96a49e2473ee10a515creed@google.com SkMask::kARGB32_Format == glyph->fMaskFormat) { 2025bdfb331ac650cf464baa96a49e2473ee10a515creed@google.com glyph->fMaskFormat = SkMask::kA8_Format; 2035bdfb331ac650cf464baa96a49e2473ee10a515creed@google.com } 2045bdfb331ac650cf464baa96a49e2473ee10a515creed@google.com 2058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (fMaskFilter) { 2068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkMask src, dst; 2078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkMatrix matrix; 2088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 2098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com glyph->toMask(&src); 2108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fRec.getMatrixFrom2x2(&matrix); 2118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 2128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com src.fImage = NULL; // only want the bounds from the filter 2138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (fMaskFilter->filterMask(&dst, src, matrix, NULL)) { 2148136d58161c3fa314af42f5c65682be855dfec1breed@google.com if (dst.fBounds.isEmpty() || !dst.fBounds.is16Bit()) { 2158136d58161c3fa314af42f5c65682be855dfec1breed@google.com goto SK_ERROR; 2168136d58161c3fa314af42f5c65682be855dfec1breed@google.com } 2178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkASSERT(dst.fImage == NULL); 2188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com glyph->fLeft = dst.fBounds.fLeft; 2198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com glyph->fTop = dst.fBounds.fTop; 2208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com glyph->fWidth = SkToU16(dst.fBounds.width()); 2218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com glyph->fHeight = SkToU16(dst.fBounds.height()); 2228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com glyph->fMaskFormat = dst.fFormat; 2238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 2248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 225d4577757874d1dda1a3bffa3f2347c251859c27ereed@android.com return; 22682065d667f64e232bcde2ad849756a6096fcbe6freed@google.com 2277767cd87fdadeed868457a2407e8b0a50006fc4asenorblanco@chromium.orgSK_ERROR: 228d4577757874d1dda1a3bffa3f2347c251859c27ereed@android.com // draw nothing 'cause we failed 229d4577757874d1dda1a3bffa3f2347c251859c27ereed@android.com glyph->fLeft = 0; 230d4577757874d1dda1a3bffa3f2347c251859c27ereed@android.com glyph->fTop = 0; 231d4577757874d1dda1a3bffa3f2347c251859c27ereed@android.com glyph->fWidth = 0; 232d4577757874d1dda1a3bffa3f2347c251859c27ereed@android.com glyph->fHeight = 0; 233b757f8d20c582463999bd7aa5a48110e84945d19reed@android.com // put a valid value here, in case it was earlier set to 234b757f8d20c582463999bd7aa5a48110e84945d19reed@android.com // MASK_FORMAT_JUST_ADVANCE 235b757f8d20c582463999bd7aa5a48110e84945d19reed@android.com glyph->fMaskFormat = fRec.fMaskFormat; 2368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 2378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 2380abbff9987b9452fd30cce198bea34fdb210ac41bungeman@google.com#define SK_SHOW_TEXT_BLIT_COVERAGE 0 239a76de72a6036da0a6b051b14411b80941971f881bungeman@google.com 240a76de72a6036da0a6b051b14411b80941971f881bungeman@google.comstatic void applyLUTToA8Mask(const SkMask& mask, const uint8_t* lut) { 241a76de72a6036da0a6b051b14411b80941971f881bungeman@google.com uint8_t* SK_RESTRICT dst = (uint8_t*)mask.fImage; 242a76de72a6036da0a6b051b14411b80941971f881bungeman@google.com unsigned rowBytes = mask.fRowBytes; 243a76de72a6036da0a6b051b14411b80941971f881bungeman@google.com 244a76de72a6036da0a6b051b14411b80941971f881bungeman@google.com for (int y = mask.fBounds.height() - 1; y >= 0; --y) { 245a76de72a6036da0a6b051b14411b80941971f881bungeman@google.com for (int x = mask.fBounds.width() - 1; x >= 0; --x) { 246a76de72a6036da0a6b051b14411b80941971f881bungeman@google.com dst[x] = lut[dst[x]]; 247a76de72a6036da0a6b051b14411b80941971f881bungeman@google.com } 248a76de72a6036da0a6b051b14411b80941971f881bungeman@google.com dst += rowBytes; 249a76de72a6036da0a6b051b14411b80941971f881bungeman@google.com } 250a76de72a6036da0a6b051b14411b80941971f881bungeman@google.com} 251a76de72a6036da0a6b051b14411b80941971f881bungeman@google.com 25297efada074e4806479f1350ab1508939c2fdcb53bungeman@google.comtemplate<bool APPLY_PREBLEND> 2530abbff9987b9452fd30cce198bea34fdb210ac41bungeman@google.comstatic void pack4xHToLCD16(const SkBitmap& src, const SkMask& dst, 254a76de72a6036da0a6b051b14411b80941971f881bungeman@google.com const SkMaskGamma::PreBlend& maskPreBlend) { 2550abbff9987b9452fd30cce198bea34fdb210ac41bungeman@google.com#define SAMPLES_PER_PIXEL 4 2560abbff9987b9452fd30cce198bea34fdb210ac41bungeman@google.com#define LCD_PER_PIXEL 3 257900ecf2f1579d42c9d2959831787af0346320f86reed@google.com SkASSERT(kAlpha_8_SkColorType == src.colorType()); 258cf598b176da861a8fd1a4e2386a7ddf874684bb3reed@google.com SkASSERT(SkMask::kLCD16_Format == dst.fFormat); 259fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com 2600abbff9987b9452fd30cce198bea34fdb210ac41bungeman@google.com const int sample_width = src.width(); 2610abbff9987b9452fd30cce198bea34fdb210ac41bungeman@google.com const int height = src.height(); 2620abbff9987b9452fd30cce198bea34fdb210ac41bungeman@google.com 263a767fa06ca28be9df1ff6e08a299e0bec839a2dcreed@google.com uint16_t* dstP = (uint16_t*)dst.fImage; 264cf598b176da861a8fd1a4e2386a7ddf874684bb3reed@google.com size_t dstRB = dst.fRowBytes; 2650abbff9987b9452fd30cce198bea34fdb210ac41bungeman@google.com // An N tap FIR is defined by 2660abbff9987b9452fd30cce198bea34fdb210ac41bungeman@google.com // out[n] = coeff[0]*x[n] + coeff[1]*x[n-1] + ... + coeff[N]*x[n-N] 2670abbff9987b9452fd30cce198bea34fdb210ac41bungeman@google.com // or 2680abbff9987b9452fd30cce198bea34fdb210ac41bungeman@google.com // out[n] = sum(i, 0, N, coeff[i]*x[n-i]) 2690abbff9987b9452fd30cce198bea34fdb210ac41bungeman@google.com 2700abbff9987b9452fd30cce198bea34fdb210ac41bungeman@google.com // The strategy is to use one FIR (different coefficients) for each of r, g, and b. 2710abbff9987b9452fd30cce198bea34fdb210ac41bungeman@google.com // This means using every 4th FIR output value of each FIR and discarding the rest. 2720abbff9987b9452fd30cce198bea34fdb210ac41bungeman@google.com // The FIRs are aligned, and the coefficients reach 5 samples to each side of their 'center'. 2730abbff9987b9452fd30cce198bea34fdb210ac41bungeman@google.com // (For r and b this is technically incorrect, but the coeffs outside round to zero anyway.) 27427e21fe577211c1c40cbf40d0385b02c69d04522skia.committer@gmail.com 2750abbff9987b9452fd30cce198bea34fdb210ac41bungeman@google.com // These are in some fixed point repesentation. 2760abbff9987b9452fd30cce198bea34fdb210ac41bungeman@google.com // Adding up to more than one simulates ink spread. 2770abbff9987b9452fd30cce198bea34fdb210ac41bungeman@google.com // For implementation reasons, these should never add up to more than two. 2780abbff9987b9452fd30cce198bea34fdb210ac41bungeman@google.com 2790abbff9987b9452fd30cce198bea34fdb210ac41bungeman@google.com // Coefficients determined by a gausian where 5 samples = 3 std deviations (0x110 'contrast'). 2800abbff9987b9452fd30cce198bea34fdb210ac41bungeman@google.com // Calculated using tools/generate_fir_coeff.py 2810abbff9987b9452fd30cce198bea34fdb210ac41bungeman@google.com // With this one almost no fringing is ever seen, but it is imperceptibly blurry. 2820abbff9987b9452fd30cce198bea34fdb210ac41bungeman@google.com // The lcd smoothed text is almost imperceptibly different from gray, 2830abbff9987b9452fd30cce198bea34fdb210ac41bungeman@google.com // but is still sharper on small stems and small rounded corners than gray. 2840abbff9987b9452fd30cce198bea34fdb210ac41bungeman@google.com // This also seems to be about as wide as one can get and only have a three pixel kernel. 2850abbff9987b9452fd30cce198bea34fdb210ac41bungeman@google.com // TODO: caculate these at runtime so parameters can be adjusted (esp contrast). 2860abbff9987b9452fd30cce198bea34fdb210ac41bungeman@google.com static const unsigned int coefficients[LCD_PER_PIXEL][SAMPLES_PER_PIXEL*3] = { 2870abbff9987b9452fd30cce198bea34fdb210ac41bungeman@google.com //The red subpixel is centered inside the first sample (at 1/6 pixel), and is shifted. 2880abbff9987b9452fd30cce198bea34fdb210ac41bungeman@google.com { 0x03, 0x0b, 0x1c, 0x33, 0x40, 0x39, 0x24, 0x10, 0x05, 0x01, 0x00, 0x00, }, 2890abbff9987b9452fd30cce198bea34fdb210ac41bungeman@google.com //The green subpixel is centered between two samples (at 1/2 pixel), so is symetric 2900abbff9987b9452fd30cce198bea34fdb210ac41bungeman@google.com { 0x00, 0x02, 0x08, 0x16, 0x2b, 0x3d, 0x3d, 0x2b, 0x16, 0x08, 0x02, 0x00, }, 2910abbff9987b9452fd30cce198bea34fdb210ac41bungeman@google.com //The blue subpixel is centered inside the last sample (at 5/6 pixel), and is shifted. 2920abbff9987b9452fd30cce198bea34fdb210ac41bungeman@google.com { 0x00, 0x00, 0x01, 0x05, 0x10, 0x24, 0x39, 0x40, 0x33, 0x1c, 0x0b, 0x03, }, 2930abbff9987b9452fd30cce198bea34fdb210ac41bungeman@google.com }; 294fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com 295cf598b176da861a8fd1a4e2386a7ddf874684bb3reed@google.com for (int y = 0; y < height; ++y) { 296cf598b176da861a8fd1a4e2386a7ddf874684bb3reed@google.com const uint8_t* srcP = src.getAddr8(0, y); 2970abbff9987b9452fd30cce198bea34fdb210ac41bungeman@google.com 2980abbff9987b9452fd30cce198bea34fdb210ac41bungeman@google.com // TODO: this fir filter implementation is straight forward, but slow. 2990abbff9987b9452fd30cce198bea34fdb210ac41bungeman@google.com // It should be possible to make it much faster. 3000abbff9987b9452fd30cce198bea34fdb210ac41bungeman@google.com for (int sample_x = -4, pixel_x = 0; sample_x < sample_width + 4; sample_x += 4, ++pixel_x) { 3010abbff9987b9452fd30cce198bea34fdb210ac41bungeman@google.com int fir[LCD_PER_PIXEL] = { 0 }; 3020abbff9987b9452fd30cce198bea34fdb210ac41bungeman@google.com for (int sample_index = SkMax32(0, sample_x - 4), coeff_index = sample_index - (sample_x - 4) 3030abbff9987b9452fd30cce198bea34fdb210ac41bungeman@google.com ; sample_index < SkMin32(sample_x + 8, sample_width) 3040abbff9987b9452fd30cce198bea34fdb210ac41bungeman@google.com ; ++sample_index, ++coeff_index) 3050abbff9987b9452fd30cce198bea34fdb210ac41bungeman@google.com { 3060abbff9987b9452fd30cce198bea34fdb210ac41bungeman@google.com int sample_value = srcP[sample_index]; 3070abbff9987b9452fd30cce198bea34fdb210ac41bungeman@google.com for (int subpxl_index = 0; subpxl_index < LCD_PER_PIXEL; ++subpxl_index) { 3080abbff9987b9452fd30cce198bea34fdb210ac41bungeman@google.com fir[subpxl_index] += coefficients[subpxl_index][coeff_index] * sample_value; 3090abbff9987b9452fd30cce198bea34fdb210ac41bungeman@google.com } 3100abbff9987b9452fd30cce198bea34fdb210ac41bungeman@google.com } 3110abbff9987b9452fd30cce198bea34fdb210ac41bungeman@google.com for (int subpxl_index = 0; subpxl_index < LCD_PER_PIXEL; ++subpxl_index) { 3120abbff9987b9452fd30cce198bea34fdb210ac41bungeman@google.com fir[subpxl_index] /= 0x100; 3130abbff9987b9452fd30cce198bea34fdb210ac41bungeman@google.com fir[subpxl_index] = SkMin32(fir[subpxl_index], 255); 3140abbff9987b9452fd30cce198bea34fdb210ac41bungeman@google.com } 3150abbff9987b9452fd30cce198bea34fdb210ac41bungeman@google.com 3160abbff9987b9452fd30cce198bea34fdb210ac41bungeman@google.com U8CPU r = sk_apply_lut_if<APPLY_PREBLEND>(fir[0], maskPreBlend.fR); 3170abbff9987b9452fd30cce198bea34fdb210ac41bungeman@google.com U8CPU g = sk_apply_lut_if<APPLY_PREBLEND>(fir[1], maskPreBlend.fG); 3180abbff9987b9452fd30cce198bea34fdb210ac41bungeman@google.com U8CPU b = sk_apply_lut_if<APPLY_PREBLEND>(fir[2], maskPreBlend.fB); 3190abbff9987b9452fd30cce198bea34fdb210ac41bungeman@google.com#if SK_SHOW_TEXT_BLIT_COVERAGE 3200abbff9987b9452fd30cce198bea34fdb210ac41bungeman@google.com r = SkMax32(r, 10); g = SkMax32(g, 10); b = SkMax32(b, 10); 3210abbff9987b9452fd30cce198bea34fdb210ac41bungeman@google.com#endif 3220abbff9987b9452fd30cce198bea34fdb210ac41bungeman@google.com dstP[pixel_x] = SkPack888ToRGB16(r, g, b); 323cf598b176da861a8fd1a4e2386a7ddf874684bb3reed@google.com } 324cf598b176da861a8fd1a4e2386a7ddf874684bb3reed@google.com dstP = (uint16_t*)((char*)dstP + dstRB); 325cf598b176da861a8fd1a4e2386a7ddf874684bb3reed@google.com } 326cf598b176da861a8fd1a4e2386a7ddf874684bb3reed@google.com} 327a767fa06ca28be9df1ff6e08a299e0bec839a2dcreed@google.com 32897efada074e4806479f1350ab1508939c2fdcb53bungeman@google.comtemplate<bool APPLY_PREBLEND> 3290abbff9987b9452fd30cce198bea34fdb210ac41bungeman@google.comstatic void pack4xHToLCD32(const SkBitmap& src, const SkMask& dst, 330a76de72a6036da0a6b051b14411b80941971f881bungeman@google.com const SkMaskGamma::PreBlend& maskPreBlend) { 331900ecf2f1579d42c9d2959831787af0346320f86reed@google.com SkASSERT(kAlpha_8_SkColorType == src.colorType()); 332cf598b176da861a8fd1a4e2386a7ddf874684bb3reed@google.com SkASSERT(SkMask::kLCD32_Format == dst.fFormat); 333fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com 334cf598b176da861a8fd1a4e2386a7ddf874684bb3reed@google.com const int width = dst.fBounds.width(); 335cf598b176da861a8fd1a4e2386a7ddf874684bb3reed@google.com const int height = dst.fBounds.height(); 336a767fa06ca28be9df1ff6e08a299e0bec839a2dcreed@google.com SkPMColor* dstP = (SkPMColor*)dst.fImage; 337cf598b176da861a8fd1a4e2386a7ddf874684bb3reed@google.com size_t dstRB = dst.fRowBytes; 338fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com 339cf598b176da861a8fd1a4e2386a7ddf874684bb3reed@google.com for (int y = 0; y < height; ++y) { 340cf598b176da861a8fd1a4e2386a7ddf874684bb3reed@google.com const uint8_t* srcP = src.getAddr8(0, y); 3410abbff9987b9452fd30cce198bea34fdb210ac41bungeman@google.com 3420abbff9987b9452fd30cce198bea34fdb210ac41bungeman@google.com // TODO: need to use fir filter here as well. 343cf598b176da861a8fd1a4e2386a7ddf874684bb3reed@google.com for (int x = 0; x < width; ++x) { 344a76de72a6036da0a6b051b14411b80941971f881bungeman@google.com U8CPU r = sk_apply_lut_if<APPLY_PREBLEND>(*srcP++, maskPreBlend.fR); 345a76de72a6036da0a6b051b14411b80941971f881bungeman@google.com U8CPU g = sk_apply_lut_if<APPLY_PREBLEND>(*srcP++, maskPreBlend.fG); 346a76de72a6036da0a6b051b14411b80941971f881bungeman@google.com U8CPU b = sk_apply_lut_if<APPLY_PREBLEND>(*srcP++, maskPreBlend.fB); 34797efada074e4806479f1350ab1508939c2fdcb53bungeman@google.com dstP[x] = SkPackARGB32(0xFF, r, g, b); 348a767fa06ca28be9df1ff6e08a299e0bec839a2dcreed@google.com } 349a767fa06ca28be9df1ff6e08a299e0bec839a2dcreed@google.com dstP = (SkPMColor*)((char*)dstP + dstRB); 350a767fa06ca28be9df1ff6e08a299e0bec839a2dcreed@google.com } 351a767fa06ca28be9df1ff6e08a299e0bec839a2dcreed@google.com} 352a767fa06ca28be9df1ff6e08a299e0bec839a2dcreed@google.com 353d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.comstatic inline int convert_8_to_1(unsigned byte) { 354d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com SkASSERT(byte <= 0xFF); 355d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com return byte >> 7; 356d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com} 357d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com 358d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.comstatic uint8_t pack_8_to_1(const uint8_t alpha[8]) { 359d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com unsigned bits = 0; 360d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com for (int i = 0; i < 8; ++i) { 361d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com bits <<= 1; 362d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com bits |= convert_8_to_1(alpha[i]); 363d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com } 364d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com return SkToU8(bits); 365d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com} 366d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com 367d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.comstatic void packA8ToA1(const SkMask& mask, const uint8_t* src, size_t srcRB) { 368d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com const int height = mask.fBounds.height(); 369d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com const int width = mask.fBounds.width(); 370d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com const int octs = width >> 3; 371d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com const int leftOverBits = width & 7; 372d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com 373d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com uint8_t* dst = mask.fImage; 374d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com const int dstPad = mask.fRowBytes - SkAlign8(width)/8; 375d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com SkASSERT(dstPad >= 0); 376d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com 377f117781362ecf673f43f93918781853690f0e145commit-bot@chromium.org SkASSERT(width >= 0); 378f117781362ecf673f43f93918781853690f0e145commit-bot@chromium.org SkASSERT(srcRB >= (size_t)width); 379f117781362ecf673f43f93918781853690f0e145commit-bot@chromium.org const size_t srcPad = srcRB - width; 380d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com 381d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com for (int y = 0; y < height; ++y) { 382d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com for (int i = 0; i < octs; ++i) { 383d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com *dst++ = pack_8_to_1(src); 384d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com src += 8; 385d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com } 386d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com if (leftOverBits > 0) { 387d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com unsigned bits = 0; 388d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com int shift = 7; 389d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com for (int i = 0; i < leftOverBits; ++i, --shift) { 390c932c9fd77503aec47c256818dd94a8b57219a43robertphillips@google.com bits |= convert_8_to_1(*src++) << shift; 391d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com } 392d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com *dst++ = bits; 393d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com } 394d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com src += srcPad; 395d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com dst += dstPad; 396d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com } 397d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com} 398d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com 399a76de72a6036da0a6b051b14411b80941971f881bungeman@google.comstatic void generateMask(const SkMask& mask, const SkPath& path, 400a76de72a6036da0a6b051b14411b80941971f881bungeman@google.com const SkMaskGamma::PreBlend& maskPreBlend) { 401d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com SkPaint paint; 402cf598b176da861a8fd1a4e2386a7ddf874684bb3reed@google.com 403cf598b176da861a8fd1a4e2386a7ddf874684bb3reed@google.com int srcW = mask.fBounds.width(); 404cf598b176da861a8fd1a4e2386a7ddf874684bb3reed@google.com int srcH = mask.fBounds.height(); 405cf598b176da861a8fd1a4e2386a7ddf874684bb3reed@google.com int dstW = srcW; 406cf598b176da861a8fd1a4e2386a7ddf874684bb3reed@google.com int dstH = srcH; 407cf598b176da861a8fd1a4e2386a7ddf874684bb3reed@google.com int dstRB = mask.fRowBytes; 408cf598b176da861a8fd1a4e2386a7ddf874684bb3reed@google.com 409cf598b176da861a8fd1a4e2386a7ddf874684bb3reed@google.com SkMatrix matrix; 410cf598b176da861a8fd1a4e2386a7ddf874684bb3reed@google.com matrix.setTranslate(-SkIntToScalar(mask.fBounds.fLeft), 411cf598b176da861a8fd1a4e2386a7ddf874684bb3reed@google.com -SkIntToScalar(mask.fBounds.fTop)); 412cf598b176da861a8fd1a4e2386a7ddf874684bb3reed@google.com 413d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com paint.setAntiAlias(SkMask::kBW_Format != mask.fFormat); 414d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com switch (mask.fFormat) { 415d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com case SkMask::kBW_Format: 416d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com dstRB = 0; // signals we need a copy 417d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com break; 418d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com case SkMask::kA8_Format: 419d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com break; 420d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com case SkMask::kLCD16_Format: 421d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com case SkMask::kLCD32_Format: 422d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com // TODO: trigger off LCD orientation 423d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com dstW = 4*dstW - 8; 424d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com matrix.setTranslate(-SkIntToScalar(mask.fBounds.fLeft + 1), 425d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com -SkIntToScalar(mask.fBounds.fTop)); 426d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com matrix.postScale(SkIntToScalar(4), SK_Scalar1); 427d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com dstRB = 0; // signals we need a copy 428d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com break; 429d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com default: 430d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com SkDEBUGFAIL("unexpected mask format"); 431cf598b176da861a8fd1a4e2386a7ddf874684bb3reed@google.com } 432cf598b176da861a8fd1a4e2386a7ddf874684bb3reed@google.com 433045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com SkRasterClip clip; 434045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com clip.setRect(SkIRect::MakeWH(dstW, dstH)); 435cf598b176da861a8fd1a4e2386a7ddf874684bb3reed@google.com 436a3264e53ee3f3c5d6a2c813df7e44b5b96d207f2commit-bot@chromium.org const SkImageInfo info = SkImageInfo::MakeA8(dstW, dstH); 437cf598b176da861a8fd1a4e2386a7ddf874684bb3reed@google.com SkBitmap bm; 438cf598b176da861a8fd1a4e2386a7ddf874684bb3reed@google.com 439cf598b176da861a8fd1a4e2386a7ddf874684bb3reed@google.com if (0 == dstRB) { 440848250415eddc54075f7eb8795e8db79e749c6abreed if (!bm.tryAllocPixels(info)) { 4419be5727d96979f6a0f89b00a43c19bca97ace0fcreed@google.com // can't allocate offscreen, so empty the mask and return 4429be5727d96979f6a0f89b00a43c19bca97ace0fcreed@google.com sk_bzero(mask.fImage, mask.computeImageSize()); 4439be5727d96979f6a0f89b00a43c19bca97ace0fcreed@google.com return; 4449be5727d96979f6a0f89b00a43c19bca97ace0fcreed@google.com } 445cf598b176da861a8fd1a4e2386a7ddf874684bb3reed@google.com } else { 446a3264e53ee3f3c5d6a2c813df7e44b5b96d207f2commit-bot@chromium.org bm.installPixels(info, mask.fImage, dstRB); 447cf598b176da861a8fd1a4e2386a7ddf874684bb3reed@google.com } 448cf598b176da861a8fd1a4e2386a7ddf874684bb3reed@google.com sk_bzero(bm.getPixels(), bm.getSafeSize()); 449fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com 450cf598b176da861a8fd1a4e2386a7ddf874684bb3reed@google.com SkDraw draw; 451045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com draw.fRC = &clip; 452045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com draw.fClip = &clip.bwRgn(); 453cf598b176da861a8fd1a4e2386a7ddf874684bb3reed@google.com draw.fMatrix = &matrix; 454cf598b176da861a8fd1a4e2386a7ddf874684bb3reed@google.com draw.fBitmap = &bm; 455cf598b176da861a8fd1a4e2386a7ddf874684bb3reed@google.com draw.drawPath(path, paint); 456fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com 4570c5f3762e863411798b1d6c55157d24c69d5bc25bungeman@google.com switch (mask.fFormat) { 458d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com case SkMask::kBW_Format: 459d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com packA8ToA1(mask, bm.getAddr8(0, 0), bm.rowBytes()); 460d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com break; 4610c5f3762e863411798b1d6c55157d24c69d5bc25bungeman@google.com case SkMask::kA8_Format: 4620c5f3762e863411798b1d6c55157d24c69d5bc25bungeman@google.com if (maskPreBlend.isApplicable()) { 4630c5f3762e863411798b1d6c55157d24c69d5bc25bungeman@google.com applyLUTToA8Mask(mask, maskPreBlend.fG); 4640c5f3762e863411798b1d6c55157d24c69d5bc25bungeman@google.com } 4650c5f3762e863411798b1d6c55157d24c69d5bc25bungeman@google.com break; 4660c5f3762e863411798b1d6c55157d24c69d5bc25bungeman@google.com case SkMask::kLCD16_Format: 4670c5f3762e863411798b1d6c55157d24c69d5bc25bungeman@google.com if (maskPreBlend.isApplicable()) { 4680abbff9987b9452fd30cce198bea34fdb210ac41bungeman@google.com pack4xHToLCD16<true>(bm, mask, maskPreBlend); 4690c5f3762e863411798b1d6c55157d24c69d5bc25bungeman@google.com } else { 4700abbff9987b9452fd30cce198bea34fdb210ac41bungeman@google.com pack4xHToLCD16<false>(bm, mask, maskPreBlend); 4710c5f3762e863411798b1d6c55157d24c69d5bc25bungeman@google.com } 4720c5f3762e863411798b1d6c55157d24c69d5bc25bungeman@google.com break; 4730c5f3762e863411798b1d6c55157d24c69d5bc25bungeman@google.com case SkMask::kLCD32_Format: 4740c5f3762e863411798b1d6c55157d24c69d5bc25bungeman@google.com if (maskPreBlend.isApplicable()) { 4750abbff9987b9452fd30cce198bea34fdb210ac41bungeman@google.com pack4xHToLCD32<true>(bm, mask, maskPreBlend); 4760c5f3762e863411798b1d6c55157d24c69d5bc25bungeman@google.com } else { 4770abbff9987b9452fd30cce198bea34fdb210ac41bungeman@google.com pack4xHToLCD32<false>(bm, mask, maskPreBlend); 4780c5f3762e863411798b1d6c55157d24c69d5bc25bungeman@google.com } 4790c5f3762e863411798b1d6c55157d24c69d5bc25bungeman@google.com break; 4800c5f3762e863411798b1d6c55157d24c69d5bc25bungeman@google.com default: 4810c5f3762e863411798b1d6c55157d24c69d5bc25bungeman@google.com break; 482cf598b176da861a8fd1a4e2386a7ddf874684bb3reed@google.com } 483cf598b176da861a8fd1a4e2386a7ddf874684bb3reed@google.com} 484cf598b176da861a8fd1a4e2386a7ddf874684bb3reed@google.com 4855bdfb331ac650cf464baa96a49e2473ee10a515creed@google.comstatic void extract_alpha(const SkMask& dst, 4865bdfb331ac650cf464baa96a49e2473ee10a515creed@google.com const SkPMColor* srcRow, size_t srcRB) { 4875bdfb331ac650cf464baa96a49e2473ee10a515creed@google.com int width = dst.fBounds.width(); 4885bdfb331ac650cf464baa96a49e2473ee10a515creed@google.com int height = dst.fBounds.height(); 4895bdfb331ac650cf464baa96a49e2473ee10a515creed@google.com int dstRB = dst.fRowBytes; 4905bdfb331ac650cf464baa96a49e2473ee10a515creed@google.com uint8_t* dstRow = dst.fImage; 4915bdfb331ac650cf464baa96a49e2473ee10a515creed@google.com 4925bdfb331ac650cf464baa96a49e2473ee10a515creed@google.com for (int y = 0; y < height; ++y) { 4935bdfb331ac650cf464baa96a49e2473ee10a515creed@google.com for (int x = 0; x < width; ++x) { 4945bdfb331ac650cf464baa96a49e2473ee10a515creed@google.com dstRow[x] = SkGetPackedA32(srcRow[x]); 4955bdfb331ac650cf464baa96a49e2473ee10a515creed@google.com } 4965bdfb331ac650cf464baa96a49e2473ee10a515creed@google.com // zero any padding on each row 4975bdfb331ac650cf464baa96a49e2473ee10a515creed@google.com for (int x = width; x < dstRB; ++x) { 4985bdfb331ac650cf464baa96a49e2473ee10a515creed@google.com dstRow[x] = 0; 4995bdfb331ac650cf464baa96a49e2473ee10a515creed@google.com } 5005bdfb331ac650cf464baa96a49e2473ee10a515creed@google.com dstRow += dstRB; 5015bdfb331ac650cf464baa96a49e2473ee10a515creed@google.com srcRow = (const SkPMColor*)((const char*)srcRow + srcRB); 5025bdfb331ac650cf464baa96a49e2473ee10a515creed@google.com } 5035bdfb331ac650cf464baa96a49e2473ee10a515creed@google.com} 5045bdfb331ac650cf464baa96a49e2473ee10a515creed@google.com 5058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkScalerContext::getImage(const SkGlyph& origGlyph) { 5068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com const SkGlyph* glyph = &origGlyph; 5078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkGlyph tmpGlyph; 508fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com 5095bdfb331ac650cf464baa96a49e2473ee10a515creed@google.com // in case we need to call generateImage on a mask-format that is different 5105bdfb331ac650cf464baa96a49e2473ee10a515creed@google.com // (i.e. larger) than what our caller allocated by looking at origGlyph. 5115bdfb331ac650cf464baa96a49e2473ee10a515creed@google.com SkAutoMalloc tmpGlyphImageStorage; 5125bdfb331ac650cf464baa96a49e2473ee10a515creed@google.com 5135bdfb331ac650cf464baa96a49e2473ee10a515creed@google.com // If we are going to draw-from-path, then we cannot generate color, since 5145bdfb331ac650cf464baa96a49e2473ee10a515creed@google.com // the path only makes a mask. This case should have been caught up in 5155bdfb331ac650cf464baa96a49e2473ee10a515creed@google.com // generateMetrics(). 5165bdfb331ac650cf464baa96a49e2473ee10a515creed@google.com SkASSERT(!fGenerateImageFromPath || 5175bdfb331ac650cf464baa96a49e2473ee10a515creed@google.com SkMask::kARGB32_Format != origGlyph.fMaskFormat); 5185bdfb331ac650cf464baa96a49e2473ee10a515creed@google.com 5198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (fMaskFilter) { // restore the prefilter bounds 520ce2b1afb582f0a2274f476c949cff8b0e1c72b36reed@google.com tmpGlyph.init(origGlyph.fID); 5218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 5228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // need the original bounds, sans our maskfilter 5238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkMaskFilter* mf = fMaskFilter; 5248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fMaskFilter = NULL; // temp disable 5258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com this->getMetrics(&tmpGlyph); 5268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fMaskFilter = mf; // restore 5278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 5288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // we need the prefilter bounds to be <= filter bounds 5298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkASSERT(tmpGlyph.fWidth <= origGlyph.fWidth); 5308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkASSERT(tmpGlyph.fHeight <= origGlyph.fHeight); 5315bdfb331ac650cf464baa96a49e2473ee10a515creed@google.com 5325bdfb331ac650cf464baa96a49e2473ee10a515creed@google.com if (tmpGlyph.fMaskFormat == origGlyph.fMaskFormat) { 5335bdfb331ac650cf464baa96a49e2473ee10a515creed@google.com tmpGlyph.fImage = origGlyph.fImage; 5345bdfb331ac650cf464baa96a49e2473ee10a515creed@google.com } else { 5355bdfb331ac650cf464baa96a49e2473ee10a515creed@google.com tmpGlyphImageStorage.reset(tmpGlyph.computeImageSize()); 5365bdfb331ac650cf464baa96a49e2473ee10a515creed@google.com tmpGlyph.fImage = tmpGlyphImageStorage.get(); 5375bdfb331ac650cf464baa96a49e2473ee10a515creed@google.com } 5388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com glyph = &tmpGlyph; 5398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 5408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 541a767fa06ca28be9df1ff6e08a299e0bec839a2dcreed@google.com if (fGenerateImageFromPath) { 5428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkPath devPath, fillPath; 5438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkMatrix fillToDevMatrix; 544cf598b176da861a8fd1a4e2386a7ddf874684bb3reed@google.com SkMask mask; 5458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 5468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com this->internalGetPath(*glyph, &fillPath, &devPath, &fillToDevMatrix); 547cf598b176da861a8fd1a4e2386a7ddf874684bb3reed@google.com glyph->toMask(&mask); 5488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 5498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (fRasterizer) { 5508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com mask.fFormat = SkMask::kA8_Format; 5514516f4786f5dda1b86a8f825b9e8e910d9c2363creed@android.com sk_bzero(glyph->fImage, mask.computeImageSize()); 55282065d667f64e232bcde2ad849756a6096fcbe6freed@google.com 5538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (!fRasterizer->rasterize(fillPath, fillToDevMatrix, NULL, 5548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fMaskFilter, &mask, 5558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkMask::kJustRenderImage_CreateMode)) { 5568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return; 5578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 558a76de72a6036da0a6b051b14411b80941971f881bungeman@google.com if (fPreBlend.isApplicable()) { 559a76de72a6036da0a6b051b14411b80941971f881bungeman@google.com applyLUTToA8Mask(mask, fPreBlend.fG); 56097efada074e4806479f1350ab1508939c2fdcb53bungeman@google.com } 5618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } else { 5625bdfb331ac650cf464baa96a49e2473ee10a515creed@google.com SkASSERT(SkMask::kARGB32_Format != mask.fFormat); 563a76de72a6036da0a6b051b14411b80941971f881bungeman@google.com generateMask(mask, devPath, fPreBlend); 5648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 5658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } else { 5661b27704eba15be4e9d1997faac42038493a30be5djsollen generateImage(*glyph); 5678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 5688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 5698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (fMaskFilter) { 5708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkMask srcM, dstM; 5718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkMatrix matrix; 5728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 5738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // the src glyph image shouldn't be 3D 5748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkASSERT(SkMask::k3D_Format != glyph->fMaskFormat); 5755bdfb331ac650cf464baa96a49e2473ee10a515creed@google.com 5765bdfb331ac650cf464baa96a49e2473ee10a515creed@google.com SkAutoSMalloc<32*32> a8storage; 5778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com glyph->toMask(&srcM); 5785bdfb331ac650cf464baa96a49e2473ee10a515creed@google.com if (SkMask::kARGB32_Format == srcM.fFormat) { 5795bdfb331ac650cf464baa96a49e2473ee10a515creed@google.com // now we need to extract the alpha-channel from the glyph's image 5805bdfb331ac650cf464baa96a49e2473ee10a515creed@google.com // and copy it into a temp buffer, and then point srcM at that temp. 5815bdfb331ac650cf464baa96a49e2473ee10a515creed@google.com srcM.fFormat = SkMask::kA8_Format; 5825bdfb331ac650cf464baa96a49e2473ee10a515creed@google.com srcM.fRowBytes = SkAlign4(srcM.fBounds.width()); 5835bdfb331ac650cf464baa96a49e2473ee10a515creed@google.com size_t size = srcM.computeImageSize(); 5845bdfb331ac650cf464baa96a49e2473ee10a515creed@google.com a8storage.reset(size); 5855bdfb331ac650cf464baa96a49e2473ee10a515creed@google.com srcM.fImage = (uint8_t*)a8storage.get(); 5865bdfb331ac650cf464baa96a49e2473ee10a515creed@google.com extract_alpha(srcM, 5875bdfb331ac650cf464baa96a49e2473ee10a515creed@google.com (const SkPMColor*)glyph->fImage, glyph->rowBytes()); 5885bdfb331ac650cf464baa96a49e2473ee10a515creed@google.com } 5892fd42c471c77f54ace35c13975651e17d5b2e8c6skia.committer@gmail.com 5908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fRec.getMatrixFrom2x2(&matrix); 5918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 5928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (fMaskFilter->filterMask(&dstM, srcM, matrix, NULL)) { 5938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com int width = SkFastMin32(origGlyph.fWidth, dstM.fBounds.width()); 5948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com int height = SkFastMin32(origGlyph.fHeight, dstM.fBounds.height()); 5958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com int dstRB = origGlyph.rowBytes(); 5968a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com int srcRB = dstM.fRowBytes; 59782065d667f64e232bcde2ad849756a6096fcbe6freed@google.com 5988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com const uint8_t* src = (const uint8_t*)dstM.fImage; 5998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com uint8_t* dst = (uint8_t*)origGlyph.fImage; 6008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 6018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (SkMask::k3D_Format == dstM.fFormat) { 6028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // we have to copy 3 times as much 6038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com height *= 3; 6048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 6058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 6068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // clean out our glyph, since it may be larger than dstM 6074516f4786f5dda1b86a8f825b9e8e910d9c2363creed@android.com //sk_bzero(dst, height * dstRB); 6088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 6098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com while (--height >= 0) { 6108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com memcpy(dst, src, width); 6118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com src += srcRB; 6128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com dst += dstRB; 6138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 6148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkMask::FreeImage(dstM.fImage); 61597efada074e4806479f1350ab1508939c2fdcb53bungeman@google.com 616a76de72a6036da0a6b051b14411b80941971f881bungeman@google.com if (fPreBlendForFilter.isApplicable()) { 617a76de72a6036da0a6b051b14411b80941971f881bungeman@google.com applyLUTToA8Mask(srcM, fPreBlendForFilter.fG); 618a76de72a6036da0a6b051b14411b80941971f881bungeman@google.com } 6198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 6208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 6218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 6228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 6237db9fe65b2bb099e9dc41f79cc15b6a7a142bed6reed@google.comvoid SkScalerContext::getPath(const SkGlyph& glyph, SkPath* path) { 6248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com this->internalGetPath(glyph, NULL, path, NULL); 6258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 6268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 6270a01f5a2c44f3d6a7fa2d3c837f46894d9b29e5dreed@google.comvoid SkScalerContext::getFontMetrics(SkPaint::FontMetrics* fm) { 628410780677af260e32948b02c0725ef6ad761260cbungeman this->generateFontMetrics(fm); 6298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 6308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 6319d3a985aa3c82605346ed1518375a8c384b925e5reed@android.comSkUnichar SkScalerContext::generateGlyphToChar(uint16_t glyph) { 6329d3a985aa3c82605346ed1518375a8c384b925e5reed@android.com return 0; 6339d3a985aa3c82605346ed1518375a8c384b925e5reed@android.com} 6349d3a985aa3c82605346ed1518375a8c384b925e5reed@android.com 6357db9fe65b2bb099e9dc41f79cc15b6a7a142bed6reed@google.com/////////////////////////////////////////////////////////////////////////////// 6368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 6377db9fe65b2bb099e9dc41f79cc15b6a7a142bed6reed@google.comvoid SkScalerContext::internalGetPath(const SkGlyph& glyph, SkPath* fillPath, 6387db9fe65b2bb099e9dc41f79cc15b6a7a142bed6reed@google.com SkPath* devPath, SkMatrix* fillToDevMatrix) { 6398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkPath path; 6401b27704eba15be4e9d1997faac42038493a30be5djsollen generatePath(glyph, &path); 64182065d667f64e232bcde2ad849756a6096fcbe6freed@google.com 642cf598b176da861a8fd1a4e2386a7ddf874684bb3reed@google.com if (fRec.fFlags & SkScalerContext::kSubpixelPositioning_Flag) { 643cf598b176da861a8fd1a4e2386a7ddf874684bb3reed@google.com SkFixed dx = glyph.getSubXFixed(); 644cf598b176da861a8fd1a4e2386a7ddf874684bb3reed@google.com SkFixed dy = glyph.getSubYFixed(); 645cf598b176da861a8fd1a4e2386a7ddf874684bb3reed@google.com if (dx | dy) { 646cf598b176da861a8fd1a4e2386a7ddf874684bb3reed@google.com path.offset(SkFixedToScalar(dx), SkFixedToScalar(dy)); 647cf598b176da861a8fd1a4e2386a7ddf874684bb3reed@google.com } 648cf598b176da861a8fd1a4e2386a7ddf874684bb3reed@google.com } 649cf598b176da861a8fd1a4e2386a7ddf874684bb3reed@google.com 6507db9fe65b2bb099e9dc41f79cc15b6a7a142bed6reed@google.com if (fRec.fFrameWidth > 0 || fPathEffect != NULL) { 6518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // need the path in user-space, with only the point-size applied 6528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // so that our stroking and effects will operate the same way they 6538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // would if the user had extracted the path themself, and then 6548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // called drawPath 6558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkPath localPath; 6568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkMatrix matrix, inverse; 6578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 6588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fRec.getMatrixFrom2x2(&matrix); 6599575fb8b1d505572dd9808af1697921fe48c021ebungeman@google.com if (!matrix.invert(&inverse)) { 6609575fb8b1d505572dd9808af1697921fe48c021ebungeman@google.com // assume fillPath and devPath are already empty. 6619575fb8b1d505572dd9808af1697921fe48c021ebungeman@google.com return; 6629575fb8b1d505572dd9808af1697921fe48c021ebungeman@google.com } 6638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com path.transform(inverse, &localPath); 6648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // now localPath is only affected by the paint settings, and not the canvas matrix 6658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 666fd4be26c4202ae91f0f7cf2c03e44b5169d885ebreed@google.com SkStrokeRec rec(SkStrokeRec::kFill_InitStyle); 667fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com 668fd4be26c4202ae91f0f7cf2c03e44b5169d885ebreed@google.com if (fRec.fFrameWidth > 0) { 669fd4be26c4202ae91f0f7cf2c03e44b5169d885ebreed@google.com rec.setStrokeStyle(fRec.fFrameWidth, 670fd4be26c4202ae91f0f7cf2c03e44b5169d885ebreed@google.com SkToBool(fRec.fFlags & kFrameAndFill_Flag)); 671fd4be26c4202ae91f0f7cf2c03e44b5169d885ebreed@google.com // glyphs are always closed contours, so cap type is ignored, 672fd4be26c4202ae91f0f7cf2c03e44b5169d885ebreed@google.com // so we just pass something. 673fd4be26c4202ae91f0f7cf2c03e44b5169d885ebreed@google.com rec.setStrokeParams(SkPaint::kButt_Cap, 674fd4be26c4202ae91f0f7cf2c03e44b5169d885ebreed@google.com (SkPaint::Join)fRec.fStrokeJoin, 675fd4be26c4202ae91f0f7cf2c03e44b5169d885ebreed@google.com fRec.fMiterLimit); 676fd4be26c4202ae91f0f7cf2c03e44b5169d885ebreed@google.com } 677fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com 6787db9fe65b2bb099e9dc41f79cc15b6a7a142bed6reed@google.com if (fPathEffect) { 6798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkPath effectPath; 6804bbdeac58cc928dc66296bde3bd06e78070d96b7reed@google.com if (fPathEffect->filterPath(&effectPath, localPath, &rec, NULL)) { 6818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com localPath.swap(effectPath); 6827db9fe65b2bb099e9dc41f79cc15b6a7a142bed6reed@google.com } 6838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 6848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 685fd4be26c4202ae91f0f7cf2c03e44b5169d885ebreed@google.com if (rec.needToApply()) { 686fd4be26c4202ae91f0f7cf2c03e44b5169d885ebreed@google.com SkPath strokePath; 687fd4be26c4202ae91f0f7cf2c03e44b5169d885ebreed@google.com if (rec.applyToPath(&strokePath, localPath)) { 688fd4be26c4202ae91f0f7cf2c03e44b5169d885ebreed@google.com localPath.swap(strokePath); 689fd4be26c4202ae91f0f7cf2c03e44b5169d885ebreed@google.com } 6908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 69182065d667f64e232bcde2ad849756a6096fcbe6freed@google.com 6928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // now return stuff to the caller 6937db9fe65b2bb099e9dc41f79cc15b6a7a142bed6reed@google.com if (fillToDevMatrix) { 6948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com *fillToDevMatrix = matrix; 6957db9fe65b2bb099e9dc41f79cc15b6a7a142bed6reed@google.com } 6967db9fe65b2bb099e9dc41f79cc15b6a7a142bed6reed@google.com if (devPath) { 6978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com localPath.transform(matrix, devPath); 6987db9fe65b2bb099e9dc41f79cc15b6a7a142bed6reed@google.com } 6997db9fe65b2bb099e9dc41f79cc15b6a7a142bed6reed@google.com if (fillPath) { 7008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fillPath->swap(localPath); 7017db9fe65b2bb099e9dc41f79cc15b6a7a142bed6reed@google.com } 7027db9fe65b2bb099e9dc41f79cc15b6a7a142bed6reed@google.com } else { // nothing tricky to do 7037db9fe65b2bb099e9dc41f79cc15b6a7a142bed6reed@google.com if (fillToDevMatrix) { 7048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fillToDevMatrix->reset(); 7057db9fe65b2bb099e9dc41f79cc15b6a7a142bed6reed@google.com } 7067db9fe65b2bb099e9dc41f79cc15b6a7a142bed6reed@google.com if (devPath) { 7077db9fe65b2bb099e9dc41f79cc15b6a7a142bed6reed@google.com if (fillPath == NULL) { 7088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com devPath->swap(path); 7097db9fe65b2bb099e9dc41f79cc15b6a7a142bed6reed@google.com } else { 7108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com *devPath = path; 7117db9fe65b2bb099e9dc41f79cc15b6a7a142bed6reed@google.com } 7128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 71382065d667f64e232bcde2ad849756a6096fcbe6freed@google.com 7147db9fe65b2bb099e9dc41f79cc15b6a7a142bed6reed@google.com if (fillPath) { 7158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fillPath->swap(path); 7167db9fe65b2bb099e9dc41f79cc15b6a7a142bed6reed@google.com } 7178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 71882065d667f64e232bcde2ad849756a6096fcbe6freed@google.com 7197db9fe65b2bb099e9dc41f79cc15b6a7a142bed6reed@google.com if (devPath) { 7208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com devPath->updateBoundsCache(); 7217db9fe65b2bb099e9dc41f79cc15b6a7a142bed6reed@google.com } 7227db9fe65b2bb099e9dc41f79cc15b6a7a142bed6reed@google.com if (fillPath) { 7238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fillPath->updateBoundsCache(); 7247db9fe65b2bb099e9dc41f79cc15b6a7a142bed6reed@google.com } 7258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 7268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 7278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 728a9d4e84c435f61be3c02d7f54acab973e8b7761creed@google.comvoid SkScalerContextRec::getMatrixFrom2x2(SkMatrix* dst) const { 72950dd41017ad121b5f40f063d813ba517668fcfbcbungeman@google.com dst->setAll(fPost2x2[0][0], fPost2x2[0][1], 0, 73050dd41017ad121b5f40f063d813ba517668fcfbcbungeman@google.com fPost2x2[1][0], fPost2x2[1][1], 0, 73150dd41017ad121b5f40f063d813ba517668fcfbcbungeman@google.com 0, 0, SkScalarToPersp(SK_Scalar1)); 7328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 7338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 734a9d4e84c435f61be3c02d7f54acab973e8b7761creed@google.comvoid SkScalerContextRec::getLocalMatrix(SkMatrix* m) const { 735ed43dffbf140cebc0575bed7b4dff1b32430ad21reed@google.com SkPaint::SetTextMatrix(m, fTextSize, fPreScaleX, fPreSkewX); 7368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 7378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 738a9d4e84c435f61be3c02d7f54acab973e8b7761creed@google.comvoid SkScalerContextRec::getSingleMatrix(SkMatrix* m) const { 7398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com this->getLocalMatrix(m); 7408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 7418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // now concat the device matrix 7427db9fe65b2bb099e9dc41f79cc15b6a7a142bed6reed@google.com SkMatrix deviceMatrix; 7437db9fe65b2bb099e9dc41f79cc15b6a7a142bed6reed@google.com this->getMatrixFrom2x2(&deviceMatrix); 7447db9fe65b2bb099e9dc41f79cc15b6a7a142bed6reed@google.com m->postConcat(deviceMatrix); 7458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 7468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 7472e68478d8654c8a4048b45ad16ac039dadb25c33reed@google.comSkAxisAlignment SkComputeAxisAlignmentForHText(const SkMatrix& matrix) { 7482e68478d8654c8a4048b45ad16ac039dadb25c33reed@google.com SkASSERT(!matrix.hasPerspective()); 749fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com 7502e68478d8654c8a4048b45ad16ac039dadb25c33reed@google.com if (0 == matrix[SkMatrix::kMSkewY]) { 7512e68478d8654c8a4048b45ad16ac039dadb25c33reed@google.com return kX_SkAxisAlignment; 7522e68478d8654c8a4048b45ad16ac039dadb25c33reed@google.com } 7532e68478d8654c8a4048b45ad16ac039dadb25c33reed@google.com if (0 == matrix[SkMatrix::kMScaleX]) { 7542e68478d8654c8a4048b45ad16ac039dadb25c33reed@google.com return kY_SkAxisAlignment; 7552e68478d8654c8a4048b45ad16ac039dadb25c33reed@google.com } 7562e68478d8654c8a4048b45ad16ac039dadb25c33reed@google.com return kNone_SkAxisAlignment; 7572e68478d8654c8a4048b45ad16ac039dadb25c33reed@google.com} 7582e68478d8654c8a4048b45ad16ac039dadb25c33reed@google.com 75962900b4c64401bc80ae85f6f5c87309a273cae10reed@android.com/////////////////////////////////////////////////////////////////////////////// 76062900b4c64401bc80ae85f6f5c87309a273cae10reed@android.com 7618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkFontHost.h" 7628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 76362900b4c64401bc80ae85f6f5c87309a273cae10reed@android.comclass SkScalerContext_Empty : public SkScalerContext { 76462900b4c64401bc80ae85f6f5c87309a273cae10reed@android.compublic: 7650da48618a758ef46c2174bdc1eaeb6dd8a693a2ereed@google.com SkScalerContext_Empty(SkTypeface* face, const SkDescriptor* desc) 7660da48618a758ef46c2174bdc1eaeb6dd8a693a2ereed@google.com : SkScalerContext(face, desc) {} 76762900b4c64401bc80ae85f6f5c87309a273cae10reed@android.com 76862900b4c64401bc80ae85f6f5c87309a273cae10reed@android.comprotected: 769a76de72a6036da0a6b051b14411b80941971f881bungeman@google.com virtual unsigned generateGlyphCount() SK_OVERRIDE { 77062900b4c64401bc80ae85f6f5c87309a273cae10reed@android.com return 0; 77162900b4c64401bc80ae85f6f5c87309a273cae10reed@android.com } 772a76de72a6036da0a6b051b14411b80941971f881bungeman@google.com virtual uint16_t generateCharToGlyph(SkUnichar uni) SK_OVERRIDE { 77362900b4c64401bc80ae85f6f5c87309a273cae10reed@android.com return 0; 77462900b4c64401bc80ae85f6f5c87309a273cae10reed@android.com } 775a76de72a6036da0a6b051b14411b80941971f881bungeman@google.com virtual void generateAdvance(SkGlyph* glyph) SK_OVERRIDE { 77662900b4c64401bc80ae85f6f5c87309a273cae10reed@android.com glyph->zeroMetrics(); 77762900b4c64401bc80ae85f6f5c87309a273cae10reed@android.com } 778a76de72a6036da0a6b051b14411b80941971f881bungeman@google.com virtual void generateMetrics(SkGlyph* glyph) SK_OVERRIDE { 77962900b4c64401bc80ae85f6f5c87309a273cae10reed@android.com glyph->zeroMetrics(); 78062900b4c64401bc80ae85f6f5c87309a273cae10reed@android.com } 781a76de72a6036da0a6b051b14411b80941971f881bungeman@google.com virtual void generateImage(const SkGlyph& glyph) SK_OVERRIDE {} 782a76de72a6036da0a6b051b14411b80941971f881bungeman@google.com virtual void generatePath(const SkGlyph& glyph, SkPath* path) SK_OVERRIDE {} 783410780677af260e32948b02c0725ef6ad761260cbungeman virtual void generateFontMetrics(SkPaint::FontMetrics* metrics) SK_OVERRIDE { 784410780677af260e32948b02c0725ef6ad761260cbungeman if (metrics) { 785410780677af260e32948b02c0725ef6ad761260cbungeman sk_bzero(metrics, sizeof(*metrics)); 78662900b4c64401bc80ae85f6f5c87309a273cae10reed@android.com } 78762900b4c64401bc80ae85f6f5c87309a273cae10reed@android.com } 78862900b4c64401bc80ae85f6f5c87309a273cae10reed@android.com}; 78962900b4c64401bc80ae85f6f5c87309a273cae10reed@android.com 790f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.comextern SkScalerContext* SkCreateColorScalerContext(const SkDescriptor* desc); 791f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com 79284e22d847fc84727bc220947162363ee1fe068fcreed@google.comSkScalerContext* SkTypeface::createScalerContext(const SkDescriptor* desc, 79384e22d847fc84727bc220947162363ee1fe068fcreed@google.com bool allowFailure) const { 79484e22d847fc84727bc220947162363ee1fe068fcreed@google.com SkScalerContext* c = this->onCreateScalerContext(desc); 79584e22d847fc84727bc220947162363ee1fe068fcreed@google.com 79684e22d847fc84727bc220947162363ee1fe068fcreed@google.com if (!c && !allowFailure) { 7970da48618a758ef46c2174bdc1eaeb6dd8a693a2ereed@google.com c = SkNEW_ARGS(SkScalerContext_Empty, 7980da48618a758ef46c2174bdc1eaeb6dd8a693a2ereed@google.com (const_cast<SkTypeface*>(this), desc)); 79962900b4c64401bc80ae85f6f5c87309a273cae10reed@android.com } 80062900b4c64401bc80ae85f6f5c87309a273cae10reed@android.com return c; 8018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 802