1e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com/* 2e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com * Copyright 2011 Google Inc. 3e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com * 4e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com * Use of this source code is governed by a BSD-style license that can be 5e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com * found in the LICENSE file. 6e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com */ 7e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com 8e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com#include "SkTypes.h" 9e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com#undef GetGlyphIndices 10e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com 1172cf4fcafa54cfa04c5ec7cb8eaa3acb144712ddbungeman@google.com#include "SkDWrite.h" 12e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com#include "SkDWriteGeometrySink.h" 13e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com#include "SkEndian.h" 14e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com#include "SkGlyph.h" 15e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com#include "SkHRESULT.h" 16e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com#include "SkMaskGamma.h" 17058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com#include "SkMatrix22.h" 18058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com#include "SkOTTable_EBLC.h" 19058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com#include "SkOTTable_EBSC.h" 20740c3f17f7f37fca5268b60a83448953f075d8d1bungeman#include "SkOTTable_gasp.h" 21761b2509d59787a8920b2e98911cff9f88e0eb4ebungeman#include "SkOTTable_maxp.h" 22e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com#include "SkPath.h" 2351daa25a2b16bca578e78b7ea1e5815b9abb8b0bbungeman#include "SkScalerContext.h" 2451daa25a2b16bca578e78b7ea1e5815b9abb8b0bbungeman#include "SkScalerContext_win_dw.h" 25e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com#include "SkTScopedComPtr.h" 2651daa25a2b16bca578e78b7ea1e5815b9abb8b0bbungeman#include "SkTypeface_win_dw.h" 27e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com 28e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com#include <dwrite.h> 29f548444684b9c96f7717aebe645944af4f95d650bungeman#if SK_HAS_DWRITE_1_H 30f548444684b9c96f7717aebe645944af4f95d650bungeman# include <dwrite_1.h> 31f548444684b9c96f7717aebe645944af4f95d650bungeman#endif 32e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com 33e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.comstatic bool isLCD(const SkScalerContext::Rec& rec) { 34e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com return SkMask::kLCD16_Format == rec.fMaskFormat || 35e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com SkMask::kLCD32_Format == rec.fMaskFormat; 36e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com} 37e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com 38761b2509d59787a8920b2e98911cff9f88e0eb4ebungemanstatic bool is_hinted_without_gasp(DWriteFontTypeface* typeface) { 39761b2509d59787a8920b2e98911cff9f88e0eb4ebungeman AutoTDWriteTable<SkOTTableMaximumProfile> maxp(typeface->fDWriteFontFace.get()); 40761b2509d59787a8920b2e98911cff9f88e0eb4ebungeman if (!maxp.fExists) { 41761b2509d59787a8920b2e98911cff9f88e0eb4ebungeman return false; 42761b2509d59787a8920b2e98911cff9f88e0eb4ebungeman } 43761b2509d59787a8920b2e98911cff9f88e0eb4ebungeman if (maxp.fSize < sizeof(SkOTTableMaximumProfile::Version::TT)) { 44761b2509d59787a8920b2e98911cff9f88e0eb4ebungeman return false; 45761b2509d59787a8920b2e98911cff9f88e0eb4ebungeman } 46761b2509d59787a8920b2e98911cff9f88e0eb4ebungeman if (maxp->version.version != SkOTTableMaximumProfile::Version::TT::VERSION) { 47761b2509d59787a8920b2e98911cff9f88e0eb4ebungeman return false; 48761b2509d59787a8920b2e98911cff9f88e0eb4ebungeman } 49761b2509d59787a8920b2e98911cff9f88e0eb4ebungeman 50761b2509d59787a8920b2e98911cff9f88e0eb4ebungeman if (0 == maxp->version.tt.maxSizeOfInstructions) { 51761b2509d59787a8920b2e98911cff9f88e0eb4ebungeman // No hints. 52761b2509d59787a8920b2e98911cff9f88e0eb4ebungeman return false; 53761b2509d59787a8920b2e98911cff9f88e0eb4ebungeman } 54761b2509d59787a8920b2e98911cff9f88e0eb4ebungeman 55761b2509d59787a8920b2e98911cff9f88e0eb4ebungeman AutoTDWriteTable<SkOTTableGridAndScanProcedure> gasp(typeface->fDWriteFontFace.get()); 56761b2509d59787a8920b2e98911cff9f88e0eb4ebungeman return !gasp.fExists; 57761b2509d59787a8920b2e98911cff9f88e0eb4ebungeman} 58761b2509d59787a8920b2e98911cff9f88e0eb4ebungeman 59740c3f17f7f37fca5268b60a83448953f075d8d1bungeman/** A PPEMRange is inclusive, [min, max]. */ 60740c3f17f7f37fca5268b60a83448953f075d8d1bungemanstruct PPEMRange { 61740c3f17f7f37fca5268b60a83448953f075d8d1bungeman int min; 62740c3f17f7f37fca5268b60a83448953f075d8d1bungeman int max; 63740c3f17f7f37fca5268b60a83448953f075d8d1bungeman}; 64740c3f17f7f37fca5268b60a83448953f075d8d1bungeman 65740c3f17f7f37fca5268b60a83448953f075d8d1bungeman/** If the rendering mode for the specified 'size' is gridfit, then place 66740c3f17f7f37fca5268b60a83448953f075d8d1bungeman * the gridfit range into 'range'. Otherwise, leave 'range' alone. 67740c3f17f7f37fca5268b60a83448953f075d8d1bungeman */ 68740c3f17f7f37fca5268b60a83448953f075d8d1bungemanstatic void expand_range_if_gridfit_only(DWriteFontTypeface* typeface, int size, PPEMRange* range) { 69740c3f17f7f37fca5268b60a83448953f075d8d1bungeman AutoTDWriteTable<SkOTTableGridAndScanProcedure> gasp(typeface->fDWriteFontFace.get()); 70740c3f17f7f37fca5268b60a83448953f075d8d1bungeman if (!gasp.fExists) { 71740c3f17f7f37fca5268b60a83448953f075d8d1bungeman return; 72740c3f17f7f37fca5268b60a83448953f075d8d1bungeman } 73740c3f17f7f37fca5268b60a83448953f075d8d1bungeman if (gasp.fSize < sizeof(SkOTTableGridAndScanProcedure)) { 74740c3f17f7f37fca5268b60a83448953f075d8d1bungeman return; 75740c3f17f7f37fca5268b60a83448953f075d8d1bungeman } 76740c3f17f7f37fca5268b60a83448953f075d8d1bungeman if (gasp->version != SkOTTableGridAndScanProcedure::version0 && 77740c3f17f7f37fca5268b60a83448953f075d8d1bungeman gasp->version != SkOTTableGridAndScanProcedure::version1) 78740c3f17f7f37fca5268b60a83448953f075d8d1bungeman { 79c83780c9ec9fb7dc46abed71a64d83ec0ce7a274Ben Wagner return; 80740c3f17f7f37fca5268b60a83448953f075d8d1bungeman } 81740c3f17f7f37fca5268b60a83448953f075d8d1bungeman 82740c3f17f7f37fca5268b60a83448953f075d8d1bungeman uint16_t numRanges = SkEndianSwap16(gasp->numRanges); 83740c3f17f7f37fca5268b60a83448953f075d8d1bungeman if (numRanges > 1024 || 84740c3f17f7f37fca5268b60a83448953f075d8d1bungeman gasp.fSize < sizeof(SkOTTableGridAndScanProcedure) + 85740c3f17f7f37fca5268b60a83448953f075d8d1bungeman sizeof(SkOTTableGridAndScanProcedure::GaspRange) * numRanges) 86740c3f17f7f37fca5268b60a83448953f075d8d1bungeman { 87740c3f17f7f37fca5268b60a83448953f075d8d1bungeman return; 88740c3f17f7f37fca5268b60a83448953f075d8d1bungeman } 89740c3f17f7f37fca5268b60a83448953f075d8d1bungeman 90740c3f17f7f37fca5268b60a83448953f075d8d1bungeman const SkOTTableGridAndScanProcedure::GaspRange* rangeTable = 91740c3f17f7f37fca5268b60a83448953f075d8d1bungeman SkTAfter<const SkOTTableGridAndScanProcedure::GaspRange>(gasp.get()); 92740c3f17f7f37fca5268b60a83448953f075d8d1bungeman int minPPEM = -1; 93740c3f17f7f37fca5268b60a83448953f075d8d1bungeman for (uint16_t i = 0; i < numRanges; ++i, ++rangeTable) { 94740c3f17f7f37fca5268b60a83448953f075d8d1bungeman int maxPPEM = SkEndianSwap16(rangeTable->maxPPEM); 95740c3f17f7f37fca5268b60a83448953f075d8d1bungeman // Test that the size is in range and the range is gridfit only. 96740c3f17f7f37fca5268b60a83448953f075d8d1bungeman if (minPPEM < size && size <= maxPPEM && 97740c3f17f7f37fca5268b60a83448953f075d8d1bungeman rangeTable->flags.raw.value == SkOTTableGridAndScanProcedure::GaspRange::behavior::Raw::GridfitMask) 98740c3f17f7f37fca5268b60a83448953f075d8d1bungeman { 99740c3f17f7f37fca5268b60a83448953f075d8d1bungeman range->min = minPPEM + 1; 100740c3f17f7f37fca5268b60a83448953f075d8d1bungeman range->max = maxPPEM; 101740c3f17f7f37fca5268b60a83448953f075d8d1bungeman return; 102740c3f17f7f37fca5268b60a83448953f075d8d1bungeman } 103740c3f17f7f37fca5268b60a83448953f075d8d1bungeman minPPEM = maxPPEM; 104740c3f17f7f37fca5268b60a83448953f075d8d1bungeman } 105740c3f17f7f37fca5268b60a83448953f075d8d1bungeman} 106740c3f17f7f37fca5268b60a83448953f075d8d1bungeman 107740c3f17f7f37fca5268b60a83448953f075d8d1bungemanstatic bool has_bitmap_strike(DWriteFontTypeface* typeface, PPEMRange range) { 108058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com { 109058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com AutoTDWriteTable<SkOTTableEmbeddedBitmapLocation> eblc(typeface->fDWriteFontFace.get()); 110058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com if (!eblc.fExists) { 111058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com return false; 112058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com } 113058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com if (eblc.fSize < sizeof(SkOTTableEmbeddedBitmapLocation)) { 114058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com return false; 115058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com } 116058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com if (eblc->version != SkOTTableEmbeddedBitmapLocation::version_initial) { 117058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com return false; 118058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com } 119058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com 120058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com uint32_t numSizes = SkEndianSwap32(eblc->numSizes); 121740c3f17f7f37fca5268b60a83448953f075d8d1bungeman if (numSizes > 1024 || 122740c3f17f7f37fca5268b60a83448953f075d8d1bungeman eblc.fSize < sizeof(SkOTTableEmbeddedBitmapLocation) + 123058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com sizeof(SkOTTableEmbeddedBitmapLocation::BitmapSizeTable) * numSizes) 124058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com { 125058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com return false; 126058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com } 127058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com 128058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com const SkOTTableEmbeddedBitmapLocation::BitmapSizeTable* sizeTable = 129058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com SkTAfter<const SkOTTableEmbeddedBitmapLocation::BitmapSizeTable>(eblc.get()); 130058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com for (uint32_t i = 0; i < numSizes; ++i, ++sizeTable) { 131740c3f17f7f37fca5268b60a83448953f075d8d1bungeman if (sizeTable->ppemX == sizeTable->ppemY && 132740c3f17f7f37fca5268b60a83448953f075d8d1bungeman range.min <= sizeTable->ppemX && sizeTable->ppemX <= range.max) 133740c3f17f7f37fca5268b60a83448953f075d8d1bungeman { 134058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com // TODO: determine if we should dig through IndexSubTableArray/IndexSubTable 135058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com // to determine the actual number of glyphs with bitmaps. 136058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com 137058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com // TODO: Ensure that the bitmaps actually cover a significant portion of the strike. 138058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com 139740c3f17f7f37fca5268b60a83448953f075d8d1bungeman // TODO: Ensure that the bitmaps are bi-level? 140058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com if (sizeTable->endGlyphIndex >= sizeTable->startGlyphIndex + 3) { 141058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com return true; 142058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com } 143058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com } 144058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com } 145058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com } 146058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com 147058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com { 148058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com AutoTDWriteTable<SkOTTableEmbeddedBitmapScaling> ebsc(typeface->fDWriteFontFace.get()); 149058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com if (!ebsc.fExists) { 150058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com return false; 151058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com } 152058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com if (ebsc.fSize < sizeof(SkOTTableEmbeddedBitmapScaling)) { 153058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com return false; 154058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com } 155058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com if (ebsc->version != SkOTTableEmbeddedBitmapScaling::version_initial) { 156058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com return false; 157058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com } 158058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com 159058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com uint32_t numSizes = SkEndianSwap32(ebsc->numSizes); 160740c3f17f7f37fca5268b60a83448953f075d8d1bungeman if (numSizes > 1024 || 161740c3f17f7f37fca5268b60a83448953f075d8d1bungeman ebsc.fSize < sizeof(SkOTTableEmbeddedBitmapScaling) + 162058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com sizeof(SkOTTableEmbeddedBitmapScaling::BitmapScaleTable) * numSizes) 163058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com { 164058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com return false; 165058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com } 166058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com 167058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com const SkOTTableEmbeddedBitmapScaling::BitmapScaleTable* scaleTable = 168058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com SkTAfter<const SkOTTableEmbeddedBitmapScaling::BitmapScaleTable>(ebsc.get()); 169058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com for (uint32_t i = 0; i < numSizes; ++i, ++scaleTable) { 170740c3f17f7f37fca5268b60a83448953f075d8d1bungeman if (scaleTable->ppemX == scaleTable->ppemY && 171740c3f17f7f37fca5268b60a83448953f075d8d1bungeman range.min <= scaleTable->ppemX && scaleTable->ppemX <= range.max) { 172058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com // EBSC tables are normally only found in bitmap only fonts. 173058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com return true; 174058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com } 175058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com } 176058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com } 177058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com 178058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com return false; 179058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com} 180058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com 181740c3f17f7f37fca5268b60a83448953f075d8d1bungemanstatic bool both_zero(SkScalar a, SkScalar b) { 182058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com return 0 == a && 0 == b; 183058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com} 184058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com 185058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com// returns false if there is any non-90-rotation or skew 186740c3f17f7f37fca5268b60a83448953f075d8d1bungemanstatic bool is_axis_aligned(const SkScalerContext::Rec& rec) { 187058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com return 0 == rec.fPreSkewX && 188740c3f17f7f37fca5268b60a83448953f075d8d1bungeman (both_zero(rec.fPost2x2[0][1], rec.fPost2x2[1][0]) || 189740c3f17f7f37fca5268b60a83448953f075d8d1bungeman both_zero(rec.fPost2x2[0][0], rec.fPost2x2[1][1])); 190058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com} 191058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com 19230ddd615c447fed73286151b463af20d309c85f1reed@google.comSkScalerContext_DW::SkScalerContext_DW(DWriteFontTypeface* typeface, 1936eddc77f6a0078570471277954c07d73b3a921d8bungeman@google.com const SkDescriptor* desc) 1940da48618a758ef46c2174bdc1eaeb6dd8a693a2ereed@google.com : SkScalerContext(typeface, desc) 1950da48618a758ef46c2174bdc1eaeb6dd8a693a2ereed@google.com , fTypeface(SkRef(typeface)) 196e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com , fGlyphCount(-1) { 197e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com 198058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com // In general, all glyphs should use CLEARTYPE_NATURAL_SYMMETRIC 199058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com // except when bi-level rendering is requested or there are embedded 200058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com // bi-level bitmaps (and the embedded bitmap flag is set and no rotation). 201058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com // 202058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com // DirectWrite's IDWriteFontFace::GetRecommendedRenderingMode does not do 203058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com // this. As a result, determine the actual size of the text and then see if 204058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com // there are any embedded bi-level bitmaps of that size. If there are, then 205058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com // force bitmaps by requesting bi-level rendering. 206058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com // 207058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com // FreeType allows for separate ppemX and ppemY, but DirectWrite assumes 208058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com // square pixels and only uses ppemY. Therefore the transform must track any 209058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com // non-uniform x-scale. 210058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com // 211058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com // Also, rotated glyphs should have the same absolute advance widths as 212058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com // horizontal glyphs and the subpixel flag should not affect glyph shapes. 213058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com 214058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com // A is the total matrix. 215058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com SkMatrix A; 216058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com fRec.getSingleMatrix(&A); 217058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com 218058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com // h is where A maps the horizontal baseline. 219058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com SkPoint h = SkPoint::Make(SK_Scalar1, 0); 220058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com A.mapPoints(&h, 1); 221058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com 222058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com // G is the Givens Matrix for A (rotational matrix where GA[0][1] == 0). 223058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com SkMatrix G; 224058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com SkComputeGivensRotation(h, &G); 225058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com 226058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com // GA is the matrix A with rotation removed. 227058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com SkMatrix GA(G); 228058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com GA.preConcat(A); 229058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com 230058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com // realTextSize is the actual device size we want (as opposed to the size the user requested). 231058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com // gdiTextSize is the size we request when GDI compatible. 232058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com // If the scale is negative, this means the matrix will do the flip anyway. 233058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com SkScalar realTextSize = SkScalarAbs(GA.get(SkMatrix::kMScaleY)); 234058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com // Due to floating point math, the lower bits are suspect. Round carefully. 2357c18351d1f9f8fe4c5cbebf1852cd4f7bb5e026fbungeman@google.com SkScalar gdiTextSize = SkScalarRoundToScalar(realTextSize * 64.0f) / 64.0f; 236058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com if (gdiTextSize == 0) { 237058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com gdiTextSize = SK_Scalar1; 238058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com } 239058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com 2407c18351d1f9f8fe4c5cbebf1852cd4f7bb5e026fbungeman@google.com bool bitmapRequested = SkToBool(fRec.fFlags & SkScalerContext::kEmbeddedBitmapText_Flag); 241740c3f17f7f37fca5268b60a83448953f075d8d1bungeman bool treatLikeBitmap = false; 2427c18351d1f9f8fe4c5cbebf1852cd4f7bb5e026fbungeman@google.com bool axisAlignedBitmap = false; 2437c18351d1f9f8fe4c5cbebf1852cd4f7bb5e026fbungeman@google.com if (bitmapRequested) { 244740c3f17f7f37fca5268b60a83448953f075d8d1bungeman // When embedded bitmaps are requested, treat the entire range like 245740c3f17f7f37fca5268b60a83448953f075d8d1bungeman // a bitmap strike if the range is gridfit only and contains a bitmap. 246740c3f17f7f37fca5268b60a83448953f075d8d1bungeman int bitmapPPEM = SkScalarTruncToInt(gdiTextSize); 247740c3f17f7f37fca5268b60a83448953f075d8d1bungeman PPEMRange range = { bitmapPPEM, bitmapPPEM }; 248740c3f17f7f37fca5268b60a83448953f075d8d1bungeman expand_range_if_gridfit_only(typeface, bitmapPPEM, &range); 249740c3f17f7f37fca5268b60a83448953f075d8d1bungeman treatLikeBitmap = has_bitmap_strike(typeface, range); 250740c3f17f7f37fca5268b60a83448953f075d8d1bungeman 251740c3f17f7f37fca5268b60a83448953f075d8d1bungeman axisAlignedBitmap = is_axis_aligned(fRec); 2527c18351d1f9f8fe4c5cbebf1852cd4f7bb5e026fbungeman@google.com } 253058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com 2547c18351d1f9f8fe4c5cbebf1852cd4f7bb5e026fbungeman@google.com // If the user requested aliased, do so with aliased compatible metrics. 2557c18351d1f9f8fe4c5cbebf1852cd4f7bb5e026fbungeman@google.com if (SkMask::kBW_Format == fRec.fMaskFormat) { 256058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com fTextSizeRender = gdiTextSize; 257d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com fRenderingMode = DWRITE_RENDERING_MODE_ALIASED; 258d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com fTextureType = DWRITE_TEXTURE_ALIASED_1x1; 259058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com fTextSizeMeasure = gdiTextSize; 260058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com fMeasuringMode = DWRITE_MEASURING_MODE_GDI_CLASSIC; 261df1640d413c16abf4527960642aca41581808699bungeman 2627c18351d1f9f8fe4c5cbebf1852cd4f7bb5e026fbungeman@google.com // If we can use a bitmap, use gdi classic rendering and measurement. 2637c18351d1f9f8fe4c5cbebf1852cd4f7bb5e026fbungeman@google.com // This will not always provide a bitmap, but matches expected behavior. 264740c3f17f7f37fca5268b60a83448953f075d8d1bungeman } else if (treatLikeBitmap && axisAlignedBitmap) { 2657c18351d1f9f8fe4c5cbebf1852cd4f7bb5e026fbungeman@google.com fTextSizeRender = gdiTextSize; 2667c18351d1f9f8fe4c5cbebf1852cd4f7bb5e026fbungeman@google.com fRenderingMode = DWRITE_RENDERING_MODE_CLEARTYPE_GDI_CLASSIC; 2677c18351d1f9f8fe4c5cbebf1852cd4f7bb5e026fbungeman@google.com fTextureType = DWRITE_TEXTURE_CLEARTYPE_3x1; 2687c18351d1f9f8fe4c5cbebf1852cd4f7bb5e026fbungeman@google.com fTextSizeMeasure = gdiTextSize; 2697c18351d1f9f8fe4c5cbebf1852cd4f7bb5e026fbungeman@google.com fMeasuringMode = DWRITE_MEASURING_MODE_GDI_CLASSIC; 270df1640d413c16abf4527960642aca41581808699bungeman 2717c18351d1f9f8fe4c5cbebf1852cd4f7bb5e026fbungeman@google.com // If rotated but the horizontal text could have used a bitmap, 2727c18351d1f9f8fe4c5cbebf1852cd4f7bb5e026fbungeman@google.com // render high quality rotated glyphs but measure using bitmap metrics. 273740c3f17f7f37fca5268b60a83448953f075d8d1bungeman } else if (treatLikeBitmap) { 274058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com fTextSizeRender = gdiTextSize; 275058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com fRenderingMode = DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC; 276058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com fTextureType = DWRITE_TEXTURE_CLEARTYPE_3x1; 277058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com fTextSizeMeasure = gdiTextSize; 278d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com fMeasuringMode = DWRITE_MEASURING_MODE_GDI_CLASSIC; 2797c18351d1f9f8fe4c5cbebf1852cd4f7bb5e026fbungeman@google.com 280761b2509d59787a8920b2e98911cff9f88e0eb4ebungeman // Fonts that have hints but no gasp table get non-symmetric rendering. 281761b2509d59787a8920b2e98911cff9f88e0eb4ebungeman // Usually such fonts have low quality hints which were never tested 282761b2509d59787a8920b2e98911cff9f88e0eb4ebungeman // with anything but GDI ClearType classic. Such fonts often rely on 283761b2509d59787a8920b2e98911cff9f88e0eb4ebungeman // drop out control in the y direction in order to be legible. 284761b2509d59787a8920b2e98911cff9f88e0eb4ebungeman } else if (is_hinted_without_gasp(typeface)) { 285761b2509d59787a8920b2e98911cff9f88e0eb4ebungeman fTextSizeRender = gdiTextSize; 286761b2509d59787a8920b2e98911cff9f88e0eb4ebungeman fRenderingMode = DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL; 287761b2509d59787a8920b2e98911cff9f88e0eb4ebungeman fTextureType = DWRITE_TEXTURE_CLEARTYPE_3x1; 288761b2509d59787a8920b2e98911cff9f88e0eb4ebungeman fTextSizeMeasure = realTextSize; 289761b2509d59787a8920b2e98911cff9f88e0eb4ebungeman fMeasuringMode = DWRITE_MEASURING_MODE_NATURAL; 290761b2509d59787a8920b2e98911cff9f88e0eb4ebungeman 2917c18351d1f9f8fe4c5cbebf1852cd4f7bb5e026fbungeman@google.com // The normal case is to use natural symmetric rendering and linear metrics. 292d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com } else { 293058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com fTextSizeRender = realTextSize; 294d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com fRenderingMode = DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC; 295d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com fTextureType = DWRITE_TEXTURE_CLEARTYPE_3x1; 296058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com fTextSizeMeasure = realTextSize; 297d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com fMeasuringMode = DWRITE_MEASURING_MODE_NATURAL; 298d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com } 299d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com 300d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com if (this->isSubpixel()) { 301058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com fTextSizeMeasure = realTextSize; 302d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com fMeasuringMode = DWRITE_MEASURING_MODE_NATURAL; 303d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com } 304058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com 305058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com // Remove the realTextSize, as that is the text height scale currently in A. 306058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com SkScalar scale = SkScalarInvert(realTextSize); 307058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com 308058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com // fSkXform is the total matrix A without the text height scale. 309058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com fSkXform = A; 310058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com fSkXform.preScale(scale, scale); //remove the text height scale. 311058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com 312058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com fXform.m11 = SkScalarToFloat(fSkXform.getScaleX()); 313058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com fXform.m12 = SkScalarToFloat(fSkXform.getSkewY()); 314058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com fXform.m21 = SkScalarToFloat(fSkXform.getSkewX()); 315058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com fXform.m22 = SkScalarToFloat(fSkXform.getScaleY()); 316058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com fXform.dx = 0; 317058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com fXform.dy = 0; 318058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com 319058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com // GsA is the non-rotational part of A without the text height scale. 320058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com SkMatrix GsA(GA); 321058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com GsA.preScale(scale, scale); //remove text height scale, G is rotational so reorders with scale. 322058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com 323058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com fGsA.m11 = SkScalarToFloat(GsA.get(SkMatrix::kMScaleX)); 324058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com fGsA.m12 = SkScalarToFloat(GsA.get(SkMatrix::kMSkewY)); // This should be ~0. 325058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com fGsA.m21 = SkScalarToFloat(GsA.get(SkMatrix::kMSkewX)); 326058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com fGsA.m22 = SkScalarToFloat(GsA.get(SkMatrix::kMScaleY)); 327e4ae0bc5caeed52e07c7e5939fa4ac38d9e408abbungeman@google.com fGsA.dx = 0; 328e4ae0bc5caeed52e07c7e5939fa4ac38d9e408abbungeman@google.com fGsA.dy = 0; 329058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com 330058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com // fG_inv is G inverse, which is fairly simple since G is 2x2 rotational. 331058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com fG_inv.setAll(G.get(SkMatrix::kMScaleX), -G.get(SkMatrix::kMSkewX), G.get(SkMatrix::kMTransX), 332058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com -G.get(SkMatrix::kMSkewY), G.get(SkMatrix::kMScaleY), G.get(SkMatrix::kMTransY), 333058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com G.get(SkMatrix::kMPersp0), G.get(SkMatrix::kMPersp1), G.get(SkMatrix::kMPersp2)); 334e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com} 335e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com 33630ddd615c447fed73286151b463af20d309c85f1reed@google.comSkScalerContext_DW::~SkScalerContext_DW() { 337e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com} 338e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com 33930ddd615c447fed73286151b463af20d309c85f1reed@google.comunsigned SkScalerContext_DW::generateGlyphCount() { 340e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com if (fGlyphCount < 0) { 341e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com fGlyphCount = fTypeface->fDWriteFontFace->GetGlyphCount(); 342e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com } 343e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com return fGlyphCount; 344e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com} 345e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com 34630ddd615c447fed73286151b463af20d309c85f1reed@google.comuint16_t SkScalerContext_DW::generateCharToGlyph(SkUnichar uni) { 347e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com uint16_t index = 0; 348e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com fTypeface->fDWriteFontFace->GetGlyphIndices(reinterpret_cast<UINT32*>(&uni), 1, &index); 349e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com return index; 350e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com} 351e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com 35230ddd615c447fed73286151b463af20d309c85f1reed@google.comvoid SkScalerContext_DW::generateAdvance(SkGlyph* glyph) { 353e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com //Delta is the difference between the right/left side bearing metric 354e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com //and where the right/left side bearing ends up after hinting. 355e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com //DirectWrite does not provide this information. 356e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com glyph->fRsbDelta = 0; 357e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com glyph->fLsbDelta = 0; 358d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com 359e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com glyph->fAdvanceX = 0; 360e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com glyph->fAdvanceY = 0; 361e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com 362e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com uint16_t glyphId = glyph->getGlyphID(); 363e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com DWRITE_GLYPH_METRICS gm; 364d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com 365d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com if (DWRITE_MEASURING_MODE_GDI_CLASSIC == fMeasuringMode || 366d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com DWRITE_MEASURING_MODE_GDI_NATURAL == fMeasuringMode) 367d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com { 368d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com HRVM(fTypeface->fDWriteFontFace->GetGdiCompatibleGlyphMetrics( 369058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com fTextSizeMeasure, 370d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com 1.0f, // pixelsPerDip 371058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com &fGsA, 372d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com DWRITE_MEASURING_MODE_GDI_NATURAL == fMeasuringMode, 373d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com &glyphId, 1, 374d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com &gm), 375d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com "Could not get gdi compatible glyph metrics."); 376d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com } else { 377d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com HRVM(fTypeface->fDWriteFontFace->GetDesignGlyphMetrics(&glyphId, 1, &gm), 378d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com "Could not get design metrics."); 379d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com } 380e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com 381e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com DWRITE_FONT_METRICS dwfm; 382e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com fTypeface->fDWriteFontFace->GetMetrics(&dwfm); 383058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com SkScalar advanceX = SkScalarMulDiv(fTextSizeMeasure, 384e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com SkIntToScalar(gm.advanceWidth), 385e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com SkIntToScalar(dwfm.designUnitsPerEm)); 386d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com 387e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com SkVector vecs[1] = { { advanceX, 0 } }; 388058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com if (DWRITE_MEASURING_MODE_GDI_CLASSIC == fMeasuringMode || 389058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com DWRITE_MEASURING_MODE_GDI_NATURAL == fMeasuringMode) 390058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com { 391761b2509d59787a8920b2e98911cff9f88e0eb4ebungeman // DirectWrite produced 'compatible' metrics, but while close, 392761b2509d59787a8920b2e98911cff9f88e0eb4ebungeman // the end result is not always an integer as it would be with GDI. 393761b2509d59787a8920b2e98911cff9f88e0eb4ebungeman vecs[0].fX = SkScalarRoundToScalar(advanceX); 394058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com fG_inv.mapVectors(vecs, SK_ARRAY_COUNT(vecs)); 395058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com } else { 396058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com fSkXform.mapVectors(vecs, SK_ARRAY_COUNT(vecs)); 397058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com } 398e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com 399e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com glyph->fAdvanceX = SkScalarToFixed(vecs[0].fX); 400e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com glyph->fAdvanceY = SkScalarToFixed(vecs[0].fY); 401e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com} 402e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com 403683a37692bc67ef1144922b73a1e871e7e1e842ebungemanHRESULT SkScalerContext_DW::getBoundingBox(SkGlyph* glyph, 404683a37692bc67ef1144922b73a1e871e7e1e842ebungeman DWRITE_RENDERING_MODE renderingMode, 405683a37692bc67ef1144922b73a1e871e7e1e842ebungeman DWRITE_TEXTURE_TYPE textureType, 406683a37692bc67ef1144922b73a1e871e7e1e842ebungeman RECT* bbox) 407b2f7fce9e034c3b6749e75a129e7836df3529706Ben Wagner{ 408e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com //Measure raster size. 409e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com fXform.dx = SkFixedToFloat(glyph->getSubXFixed()); 410e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com fXform.dy = SkFixedToFloat(glyph->getSubYFixed()); 411e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com 412e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com FLOAT advance = 0; 413e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com 414e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com UINT16 glyphId = glyph->getGlyphID(); 415e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com 416e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com DWRITE_GLYPH_OFFSET offset; 417e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com offset.advanceOffset = 0.0f; 418e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com offset.ascenderOffset = 0.0f; 419e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com 420e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com DWRITE_GLYPH_RUN run; 421e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com run.glyphCount = 1; 422e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com run.glyphAdvances = &advance; 423e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com run.fontFace = fTypeface->fDWriteFontFace.get(); 424058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com run.fontEmSize = SkScalarToFloat(fTextSizeRender); 425e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com run.bidiLevel = 0; 426e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com run.glyphIndices = &glyphId; 427e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com run.isSideways = FALSE; 428e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com run.glyphOffsets = &offset; 429e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com 430e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com SkTScopedComPtr<IDWriteGlyphRunAnalysis> glyphRunAnalysis; 431683a37692bc67ef1144922b73a1e871e7e1e842ebungeman HRM(fTypeface->fFactory->CreateGlyphRunAnalysis( 432683a37692bc67ef1144922b73a1e871e7e1e842ebungeman &run, 433683a37692bc67ef1144922b73a1e871e7e1e842ebungeman 1.0f, // pixelsPerDip, 434683a37692bc67ef1144922b73a1e871e7e1e842ebungeman &fXform, 435683a37692bc67ef1144922b73a1e871e7e1e842ebungeman renderingMode, 436683a37692bc67ef1144922b73a1e871e7e1e842ebungeman fMeasuringMode, 437683a37692bc67ef1144922b73a1e871e7e1e842ebungeman 0.0f, // baselineOriginX, 438683a37692bc67ef1144922b73a1e871e7e1e842ebungeman 0.0f, // baselineOriginY, 439683a37692bc67ef1144922b73a1e871e7e1e842ebungeman &glyphRunAnalysis), 440683a37692bc67ef1144922b73a1e871e7e1e842ebungeman "Could not create glyph run analysis."); 441683a37692bc67ef1144922b73a1e871e7e1e842ebungeman 442683a37692bc67ef1144922b73a1e871e7e1e842ebungeman HRM(glyphRunAnalysis->GetAlphaTextureBounds(textureType, bbox), 443683a37692bc67ef1144922b73a1e871e7e1e842ebungeman "Could not get texture bounds."); 444683a37692bc67ef1144922b73a1e871e7e1e842ebungeman 445683a37692bc67ef1144922b73a1e871e7e1e842ebungeman return S_OK; 446683a37692bc67ef1144922b73a1e871e7e1e842ebungeman} 447683a37692bc67ef1144922b73a1e871e7e1e842ebungeman 448683a37692bc67ef1144922b73a1e871e7e1e842ebungeman/** GetAlphaTextureBounds succeeds but sometimes returns empty bounds like 449683a37692bc67ef1144922b73a1e871e7e1e842ebungeman * { 0x80000000, 0x80000000, 0x80000000, 0x80000000 } 450683a37692bc67ef1144922b73a1e871e7e1e842ebungeman * for small, but not quite zero, sized glyphs. 451683a37692bc67ef1144922b73a1e871e7e1e842ebungeman * Only set as non-empty if the returned bounds are non-empty. 452683a37692bc67ef1144922b73a1e871e7e1e842ebungeman */ 453683a37692bc67ef1144922b73a1e871e7e1e842ebungemanstatic bool glyph_check_and_set_bounds(SkGlyph* glyph, const RECT& bbox) { 454683a37692bc67ef1144922b73a1e871e7e1e842ebungeman if (bbox.left >= bbox.right || bbox.top >= bbox.bottom) { 455683a37692bc67ef1144922b73a1e871e7e1e842ebungeman return false; 456683a37692bc67ef1144922b73a1e871e7e1e842ebungeman } 457683a37692bc67ef1144922b73a1e871e7e1e842ebungeman glyph->fWidth = SkToU16(bbox.right - bbox.left); 458683a37692bc67ef1144922b73a1e871e7e1e842ebungeman glyph->fHeight = SkToU16(bbox.bottom - bbox.top); 459683a37692bc67ef1144922b73a1e871e7e1e842ebungeman glyph->fLeft = SkToS16(bbox.left); 460683a37692bc67ef1144922b73a1e871e7e1e842ebungeman glyph->fTop = SkToS16(bbox.top); 461683a37692bc67ef1144922b73a1e871e7e1e842ebungeman return true; 462b2f7fce9e034c3b6749e75a129e7836df3529706Ben Wagner} 463b2f7fce9e034c3b6749e75a129e7836df3529706Ben Wagner 464b2f7fce9e034c3b6749e75a129e7836df3529706Ben Wagnervoid SkScalerContext_DW::generateMetrics(SkGlyph* glyph) { 465b2f7fce9e034c3b6749e75a129e7836df3529706Ben Wagner glyph->fWidth = 0; 466683a37692bc67ef1144922b73a1e871e7e1e842ebungeman glyph->fHeight = 0; 467683a37692bc67ef1144922b73a1e871e7e1e842ebungeman glyph->fLeft = 0; 468683a37692bc67ef1144922b73a1e871e7e1e842ebungeman glyph->fTop = 0; 469b2f7fce9e034c3b6749e75a129e7836df3529706Ben Wagner 470b2f7fce9e034c3b6749e75a129e7836df3529706Ben Wagner this->generateAdvance(glyph); 471b2f7fce9e034c3b6749e75a129e7836df3529706Ben Wagner 472b2f7fce9e034c3b6749e75a129e7836df3529706Ben Wagner RECT bbox; 473683a37692bc67ef1144922b73a1e871e7e1e842ebungeman HRVM(this->getBoundingBox(glyph, fRenderingMode, fTextureType, &bbox), 474683a37692bc67ef1144922b73a1e871e7e1e842ebungeman "Requested bounding box could not be determined."); 475683a37692bc67ef1144922b73a1e871e7e1e842ebungeman 476683a37692bc67ef1144922b73a1e871e7e1e842ebungeman if (glyph_check_and_set_bounds(glyph, bbox)) { 477683a37692bc67ef1144922b73a1e871e7e1e842ebungeman return; 478683a37692bc67ef1144922b73a1e871e7e1e842ebungeman } 479b2f7fce9e034c3b6749e75a129e7836df3529706Ben Wagner 480b2f7fce9e034c3b6749e75a129e7836df3529706Ben Wagner // GetAlphaTextureBounds succeeds but returns an empty RECT if there are no 481b2f7fce9e034c3b6749e75a129e7836df3529706Ben Wagner // glyphs of the specified texture type. When this happens, try with the 482b2f7fce9e034c3b6749e75a129e7836df3529706Ben Wagner // alternate texture type. 483683a37692bc67ef1144922b73a1e871e7e1e842ebungeman if (DWRITE_TEXTURE_CLEARTYPE_3x1 == fTextureType) { 484683a37692bc67ef1144922b73a1e871e7e1e842ebungeman HRVM(this->getBoundingBox(glyph, 485683a37692bc67ef1144922b73a1e871e7e1e842ebungeman DWRITE_RENDERING_MODE_ALIASED, 486683a37692bc67ef1144922b73a1e871e7e1e842ebungeman DWRITE_TEXTURE_ALIASED_1x1, 487683a37692bc67ef1144922b73a1e871e7e1e842ebungeman &bbox), 488683a37692bc67ef1144922b73a1e871e7e1e842ebungeman "Fallback bounding box could not be determined."); 489683a37692bc67ef1144922b73a1e871e7e1e842ebungeman if (glyph_check_and_set_bounds(glyph, bbox)) { 490683a37692bc67ef1144922b73a1e871e7e1e842ebungeman glyph->fForceBW = 1; 491b2f7fce9e034c3b6749e75a129e7836df3529706Ben Wagner } 492b2f7fce9e034c3b6749e75a129e7836df3529706Ben Wagner } 493683a37692bc67ef1144922b73a1e871e7e1e842ebungeman // TODO: handle the case where a request for DWRITE_TEXTURE_ALIASED_1x1 494683a37692bc67ef1144922b73a1e871e7e1e842ebungeman // fails, and try DWRITE_TEXTURE_CLEARTYPE_3x1. 495e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com} 496e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com 497410780677af260e32948b02c0725ef6ad761260cbungemanvoid SkScalerContext_DW::generateFontMetrics(SkPaint::FontMetrics* metrics) { 498410780677af260e32948b02c0725ef6ad761260cbungeman if (NULL == metrics) { 499f73c237291bb1fc698f688d8a9b1cdd23838ed18bungeman return; 500e1b9bad0711e557e45fee109fb492d19e35e1d38bungeman@google.com } 501e1b9bad0711e557e45fee109fb492d19e35e1d38bungeman@google.com 502410780677af260e32948b02c0725ef6ad761260cbungeman sk_bzero(metrics, sizeof(*metrics)); 503410780677af260e32948b02c0725ef6ad761260cbungeman 504e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com DWRITE_FONT_METRICS dwfm; 505d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com if (DWRITE_MEASURING_MODE_GDI_CLASSIC == fMeasuringMode || 506d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com DWRITE_MEASURING_MODE_GDI_NATURAL == fMeasuringMode) 507d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com { 508d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com fTypeface->fDWriteFontFace->GetGdiCompatibleMetrics( 509058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com fTextSizeRender, 510d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com 1.0f, // pixelsPerDip 511d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com &fXform, 512d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com &dwfm); 513d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com } else { 514d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com fTypeface->fDWriteFontFace->GetMetrics(&dwfm); 515d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com } 516e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com 517e1b9bad0711e557e45fee109fb492d19e35e1d38bungeman@google.com SkScalar upem = SkIntToScalar(dwfm.designUnitsPerEm); 518e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com 519f73c237291bb1fc698f688d8a9b1cdd23838ed18bungeman metrics->fAscent = -fTextSizeRender * SkIntToScalar(dwfm.ascent) / upem; 520410780677af260e32948b02c0725ef6ad761260cbungeman metrics->fDescent = fTextSizeRender * SkIntToScalar(dwfm.descent) / upem; 521410780677af260e32948b02c0725ef6ad761260cbungeman metrics->fLeading = fTextSizeRender * SkIntToScalar(dwfm.lineGap) / upem; 522410780677af260e32948b02c0725ef6ad761260cbungeman metrics->fXHeight = fTextSizeRender * SkIntToScalar(dwfm.xHeight) / upem; 523410780677af260e32948b02c0725ef6ad761260cbungeman metrics->fUnderlineThickness = fTextSizeRender * SkIntToScalar(dwfm.underlineThickness) / upem; 524410780677af260e32948b02c0725ef6ad761260cbungeman metrics->fUnderlinePosition = -(fTextSizeRender * SkIntToScalar(dwfm.underlinePosition) / upem); 525410780677af260e32948b02c0725ef6ad761260cbungeman 526410780677af260e32948b02c0725ef6ad761260cbungeman metrics->fFlags |= SkPaint::FontMetrics::kUnderlineThinknessIsValid_Flag; 527410780677af260e32948b02c0725ef6ad761260cbungeman metrics->fFlags |= SkPaint::FontMetrics::kUnderlinePositionIsValid_Flag; 528f73c237291bb1fc698f688d8a9b1cdd23838ed18bungeman 529f548444684b9c96f7717aebe645944af4f95d650bungeman#if SK_HAS_DWRITE_1_H 53049f085dddff10473b6ebf832a974288300224e60bsalomon if (fTypeface->fDWriteFontFace1.get()) { 531f73c237291bb1fc698f688d8a9b1cdd23838ed18bungeman DWRITE_FONT_METRICS1 dwfm1; 532f73c237291bb1fc698f688d8a9b1cdd23838ed18bungeman fTypeface->fDWriteFontFace1->GetMetrics(&dwfm1); 533f73c237291bb1fc698f688d8a9b1cdd23838ed18bungeman metrics->fTop = -fTextSizeRender * SkIntToScalar(dwfm1.glyphBoxTop) / upem; 534f73c237291bb1fc698f688d8a9b1cdd23838ed18bungeman metrics->fBottom = -fTextSizeRender * SkIntToScalar(dwfm1.glyphBoxBottom) / upem; 535f73c237291bb1fc698f688d8a9b1cdd23838ed18bungeman metrics->fXMin = fTextSizeRender * SkIntToScalar(dwfm1.glyphBoxLeft) / upem; 536f73c237291bb1fc698f688d8a9b1cdd23838ed18bungeman metrics->fXMax = fTextSizeRender * SkIntToScalar(dwfm1.glyphBoxRight) / upem; 537f73c237291bb1fc698f688d8a9b1cdd23838ed18bungeman 538f73c237291bb1fc698f688d8a9b1cdd23838ed18bungeman metrics->fMaxCharWidth = metrics->fXMax - metrics->fXMin; 539f548444684b9c96f7717aebe645944af4f95d650bungeman return; 540f548444684b9c96f7717aebe645944af4f95d650bungeman } 541f548444684b9c96f7717aebe645944af4f95d650bungeman#else 542f548444684b9c96f7717aebe645944af4f95d650bungeman# pragma message("No dwrite_1.h is available, font metrics may be affected.") 543f548444684b9c96f7717aebe645944af4f95d650bungeman#endif 544f548444684b9c96f7717aebe645944af4f95d650bungeman 545f548444684b9c96f7717aebe645944af4f95d650bungeman AutoTDWriteTable<SkOTTableHead> head(fTypeface->fDWriteFontFace.get()); 546f548444684b9c96f7717aebe645944af4f95d650bungeman if (head.fExists && 547f548444684b9c96f7717aebe645944af4f95d650bungeman head.fSize >= sizeof(SkOTTableHead) && 548f548444684b9c96f7717aebe645944af4f95d650bungeman head->version == SkOTTableHead::version1) 549f548444684b9c96f7717aebe645944af4f95d650bungeman { 550f548444684b9c96f7717aebe645944af4f95d650bungeman metrics->fTop = -fTextSizeRender * (int16_t)SkEndian_SwapBE16(head->yMax) / upem; 551f548444684b9c96f7717aebe645944af4f95d650bungeman metrics->fBottom = -fTextSizeRender * (int16_t)SkEndian_SwapBE16(head->yMin) / upem; 552f548444684b9c96f7717aebe645944af4f95d650bungeman metrics->fXMin = fTextSizeRender * (int16_t)SkEndian_SwapBE16(head->xMin) / upem; 553f548444684b9c96f7717aebe645944af4f95d650bungeman metrics->fXMax = fTextSizeRender * (int16_t)SkEndian_SwapBE16(head->xMax) / upem; 554f548444684b9c96f7717aebe645944af4f95d650bungeman 555f548444684b9c96f7717aebe645944af4f95d650bungeman metrics->fMaxCharWidth = metrics->fXMax - metrics->fXMin; 556f548444684b9c96f7717aebe645944af4f95d650bungeman return; 557f73c237291bb1fc698f688d8a9b1cdd23838ed18bungeman } 558f548444684b9c96f7717aebe645944af4f95d650bungeman 559f548444684b9c96f7717aebe645944af4f95d650bungeman metrics->fTop = metrics->fAscent; 560f548444684b9c96f7717aebe645944af4f95d650bungeman metrics->fBottom = metrics->fDescent; 561e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com} 562e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com 563e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com/////////////////////////////////////////////////////////////////////////////// 564e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com 565e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com#include "SkColorPriv.h" 566e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com 567e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.comstatic void bilevel_to_bw(const uint8_t* SK_RESTRICT src, const SkGlyph& glyph) { 568e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com const int width = glyph.fWidth; 569e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com const size_t dstRB = (width + 7) >> 3; 570e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com uint8_t* SK_RESTRICT dst = static_cast<uint8_t*>(glyph.fImage); 571e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com 572e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com int byteCount = width >> 3; 573e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com int bitCount = width & 7; 574e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com 575e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com for (int y = 0; y < glyph.fHeight; ++y) { 576e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com if (byteCount > 0) { 577e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com for (int i = 0; i < byteCount; ++i) { 578e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com unsigned byte = 0; 579e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com byte |= src[0] & (1 << 7); 580e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com byte |= src[1] & (1 << 6); 581e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com byte |= src[2] & (1 << 5); 582e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com byte |= src[3] & (1 << 4); 583e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com byte |= src[4] & (1 << 3); 584e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com byte |= src[5] & (1 << 2); 585e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com byte |= src[6] & (1 << 1); 586e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com byte |= src[7] & (1 << 0); 587e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com dst[i] = byte; 588e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com src += 8; 589e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com } 590e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com } 591e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com if (bitCount > 0) { 592e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com unsigned byte = 0; 593e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com unsigned mask = 0x80; 594e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com for (int i = 0; i < bitCount; i++) { 595e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com byte |= (src[i]) & mask; 596e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com mask >>= 1; 597e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com } 598e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com dst[byteCount] = byte; 599e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com } 600e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com src += bitCount; 601e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com dst += dstRB; 602e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com } 603e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com} 604e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com 605e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.comtemplate<bool APPLY_PREBLEND> 606e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.comstatic void rgb_to_a8(const uint8_t* SK_RESTRICT src, const SkGlyph& glyph, const uint8_t* table8) { 607e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com const size_t dstRB = glyph.rowBytes(); 608e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com const U16CPU width = glyph.fWidth; 609e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com uint8_t* SK_RESTRICT dst = static_cast<uint8_t*>(glyph.fImage); 610e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com 611e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com for (U16CPU y = 0; y < glyph.fHeight; y++) { 612e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com for (U16CPU i = 0; i < width; i++) { 613e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com U8CPU r = *(src++); 614e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com U8CPU g = *(src++); 615e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com U8CPU b = *(src++); 616e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com dst[i] = sk_apply_lut_if<APPLY_PREBLEND>((r + g + b) / 3, table8); 617e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com } 618e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com dst = (uint8_t*)((char*)dst + dstRB); 619e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com } 620e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com} 621e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com 622e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.comtemplate<bool APPLY_PREBLEND> 623e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.comstatic void rgb_to_lcd16(const uint8_t* SK_RESTRICT src, const SkGlyph& glyph, 624e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com const uint8_t* tableR, const uint8_t* tableG, const uint8_t* tableB) { 625e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com const size_t dstRB = glyph.rowBytes(); 626e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com const U16CPU width = glyph.fWidth; 627e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com uint16_t* SK_RESTRICT dst = static_cast<uint16_t*>(glyph.fImage); 628e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com 629e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com for (U16CPU y = 0; y < glyph.fHeight; y++) { 630e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com for (U16CPU i = 0; i < width; i++) { 631e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com U8CPU r = sk_apply_lut_if<APPLY_PREBLEND>(*(src++), tableR); 632e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com U8CPU g = sk_apply_lut_if<APPLY_PREBLEND>(*(src++), tableG); 633e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com U8CPU b = sk_apply_lut_if<APPLY_PREBLEND>(*(src++), tableB); 634e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com dst[i] = SkPack888ToRGB16(r, g, b); 635e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com } 636e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com dst = (uint16_t*)((char*)dst + dstRB); 637e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com } 638e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com} 639e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com 640e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.comtemplate<bool APPLY_PREBLEND> 641e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.comstatic void rgb_to_lcd32(const uint8_t* SK_RESTRICT src, const SkGlyph& glyph, 642e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com const uint8_t* tableR, const uint8_t* tableG, const uint8_t* tableB) { 643e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com const size_t dstRB = glyph.rowBytes(); 644e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com const U16CPU width = glyph.fWidth; 645e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com SkPMColor* SK_RESTRICT dst = static_cast<SkPMColor*>(glyph.fImage); 646e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com 647e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com for (U16CPU y = 0; y < glyph.fHeight; y++) { 648e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com for (U16CPU i = 0; i < width; i++) { 649e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com U8CPU r = sk_apply_lut_if<APPLY_PREBLEND>(*(src++), tableR); 650e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com U8CPU g = sk_apply_lut_if<APPLY_PREBLEND>(*(src++), tableG); 651e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com U8CPU b = sk_apply_lut_if<APPLY_PREBLEND>(*(src++), tableB); 652e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com dst[i] = SkPackARGB32(0xFF, r, g, b); 653e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com } 654e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com dst = (SkPMColor*)((char*)dst + dstRB); 655e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com } 656e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com} 657e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com 658b2f7fce9e034c3b6749e75a129e7836df3529706Ben Wagnerconst void* SkScalerContext_DW::drawDWMask(const SkGlyph& glyph, 659b2f7fce9e034c3b6749e75a129e7836df3529706Ben Wagner DWRITE_RENDERING_MODE renderingMode, 660b2f7fce9e034c3b6749e75a129e7836df3529706Ben Wagner DWRITE_TEXTURE_TYPE textureType) 661b2f7fce9e034c3b6749e75a129e7836df3529706Ben Wagner{ 662d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com int sizeNeeded = glyph.fWidth * glyph.fHeight; 663b2f7fce9e034c3b6749e75a129e7836df3529706Ben Wagner if (DWRITE_RENDERING_MODE_ALIASED != renderingMode) { 664d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com sizeNeeded *= 3; 665d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com } 666d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com if (sizeNeeded > fBits.count()) { 667d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com fBits.setCount(sizeNeeded); 668d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com } 669d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com 670d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com // erase 671d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com memset(fBits.begin(), 0, sizeNeeded); 672d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com 673d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com fXform.dx = SkFixedToFloat(glyph.getSubXFixed()); 674d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com fXform.dy = SkFixedToFloat(glyph.getSubYFixed()); 675d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com 676d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com FLOAT advance = 0.0f; 677d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com 678d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com UINT16 index = glyph.getGlyphID(); 679d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com 680d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com DWRITE_GLYPH_OFFSET offset; 681d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com offset.advanceOffset = 0.0f; 682d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com offset.ascenderOffset = 0.0f; 683e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com 684d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com DWRITE_GLYPH_RUN run; 685d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com run.glyphCount = 1; 686d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com run.glyphAdvances = &advance; 687d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com run.fontFace = fTypeface->fDWriteFontFace.get(); 688058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com run.fontEmSize = SkScalarToFloat(fTextSizeRender); 689d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com run.bidiLevel = 0; 690d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com run.glyphIndices = &index; 691d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com run.isSideways = FALSE; 692d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com run.glyphOffsets = &offset; 693d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com 694d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com SkTScopedComPtr<IDWriteGlyphRunAnalysis> glyphRunAnalysis; 695d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com HRNM(fTypeface->fFactory->CreateGlyphRunAnalysis(&run, 696d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com 1.0f, // pixelsPerDip, 697d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com &fXform, 698b2f7fce9e034c3b6749e75a129e7836df3529706Ben Wagner renderingMode, 699d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com fMeasuringMode, 700d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com 0.0f, // baselineOriginX, 701d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com 0.0f, // baselineOriginY, 702d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com &glyphRunAnalysis), 703d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com "Could not create glyph run analysis."); 704d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com 705d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com //NOTE: this assumes that the glyph has already been measured 706d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com //with an exact same glyph run analysis. 707d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com RECT bbox; 708d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com bbox.left = glyph.fLeft; 709d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com bbox.top = glyph.fTop; 710d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com bbox.right = glyph.fLeft + glyph.fWidth; 711d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com bbox.bottom = glyph.fTop + glyph.fHeight; 712b2f7fce9e034c3b6749e75a129e7836df3529706Ben Wagner HRNM(glyphRunAnalysis->CreateAlphaTexture(textureType, 713d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com &bbox, 714d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com fBits.begin(), 715d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com sizeNeeded), 716d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com "Could not draw mask."); 717d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com return fBits.begin(); 718d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com} 719d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com 720d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.comvoid SkScalerContext_DW::generateImage(const SkGlyph& glyph) { 721e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com //Create the mask. 722b2f7fce9e034c3b6749e75a129e7836df3529706Ben Wagner DWRITE_RENDERING_MODE renderingMode = fRenderingMode; 723b2f7fce9e034c3b6749e75a129e7836df3529706Ben Wagner DWRITE_TEXTURE_TYPE textureType = fTextureType; 724b2f7fce9e034c3b6749e75a129e7836df3529706Ben Wagner if (glyph.fForceBW) { 725b2f7fce9e034c3b6749e75a129e7836df3529706Ben Wagner renderingMode = DWRITE_RENDERING_MODE_ALIASED; 726b2f7fce9e034c3b6749e75a129e7836df3529706Ben Wagner textureType = DWRITE_TEXTURE_ALIASED_1x1; 727b2f7fce9e034c3b6749e75a129e7836df3529706Ben Wagner } 728b2f7fce9e034c3b6749e75a129e7836df3529706Ben Wagner const void* bits = this->drawDWMask(glyph, renderingMode, textureType); 729e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com if (!bits) { 730e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com sk_bzero(glyph.fImage, glyph.computeImageSize()); 731e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com return; 732e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com } 733e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com 734e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com //Copy the mask into the glyph. 735e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com const uint8_t* src = (const uint8_t*)bits; 736b2f7fce9e034c3b6749e75a129e7836df3529706Ben Wagner if (DWRITE_RENDERING_MODE_ALIASED == renderingMode) { 737e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com bilevel_to_bw(src, glyph); 738d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com const_cast<SkGlyph&>(glyph).fMaskFormat = SkMask::kBW_Format; 739d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com } else if (!isLCD(fRec)) { 740a76de72a6036da0a6b051b14411b80941971f881bungeman@google.com if (fPreBlend.isApplicable()) { 741a76de72a6036da0a6b051b14411b80941971f881bungeman@google.com rgb_to_a8<true>(src, glyph, fPreBlend.fG); 742e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com } else { 743a76de72a6036da0a6b051b14411b80941971f881bungeman@google.com rgb_to_a8<false>(src, glyph, fPreBlend.fG); 744e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com } 745e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com } else if (SkMask::kLCD16_Format == glyph.fMaskFormat) { 746a76de72a6036da0a6b051b14411b80941971f881bungeman@google.com if (fPreBlend.isApplicable()) { 747a76de72a6036da0a6b051b14411b80941971f881bungeman@google.com rgb_to_lcd16<true>(src, glyph, fPreBlend.fR, fPreBlend.fG, fPreBlend.fB); 748e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com } else { 749a76de72a6036da0a6b051b14411b80941971f881bungeman@google.com rgb_to_lcd16<false>(src, glyph, fPreBlend.fR, fPreBlend.fG, fPreBlend.fB); 750e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com } 751e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com } else { 752e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com SkASSERT(SkMask::kLCD32_Format == glyph.fMaskFormat); 753a76de72a6036da0a6b051b14411b80941971f881bungeman@google.com if (fPreBlend.isApplicable()) { 754a76de72a6036da0a6b051b14411b80941971f881bungeman@google.com rgb_to_lcd32<true>(src, glyph, fPreBlend.fR, fPreBlend.fG, fPreBlend.fB); 755e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com } else { 756a76de72a6036da0a6b051b14411b80941971f881bungeman@google.com rgb_to_lcd32<false>(src, glyph, fPreBlend.fR, fPreBlend.fG, fPreBlend.fB); 757e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com } 758e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com } 759e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com} 760e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com 76130ddd615c447fed73286151b463af20d309c85f1reed@google.comvoid SkScalerContext_DW::generatePath(const SkGlyph& glyph, SkPath* path) { 762e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com SkASSERT(&glyph && path); 763e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com 764e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com path->reset(); 765e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com 766e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com SkTScopedComPtr<IDWriteGeometrySink> geometryToPath; 767e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com HRVM(SkDWriteGeometrySink::Create(path, &geometryToPath), 768e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com "Could not create geometry to path converter."); 769e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com uint16_t glyphId = glyph.getGlyphID(); 770e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com //TODO: convert to<->from DIUs? This would make a difference if hinting. 771e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com //It may not be needed, it appears that DirectWrite only hints at em size. 772058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com HRVM(fTypeface->fDWriteFontFace->GetGlyphRunOutline(SkScalarToFloat(fTextSizeRender), 773e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com &glyphId, 774e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com NULL, //advances 775e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com NULL, //offsets 776e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com 1, //num glyphs 777e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com FALSE, //sideways 778e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com FALSE, //rtl 779e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com geometryToPath.get()), 780e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com "Could not create glyph outline."); 781091f51b794e62942db47ccef6fef143ad1590d12bungeman@google.com 782058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com path->transform(fSkXform); 783e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com} 784