1cb93a386Sopenharmony_ci/* 2cb93a386Sopenharmony_ci * Copyright 2016 Google Inc. 3cb93a386Sopenharmony_ci * 4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be 5cb93a386Sopenharmony_ci * found in the LICENSE file. 6cb93a386Sopenharmony_ci */ 7cb93a386Sopenharmony_ci 8cb93a386Sopenharmony_ci#include "src/pdf/SkPDFMakeCIDGlyphWidthsArray.h" 9cb93a386Sopenharmony_ci 10cb93a386Sopenharmony_ci#include "include/core/SkPaint.h" 11cb93a386Sopenharmony_ci#include "include/private/SkTo.h" 12cb93a386Sopenharmony_ci#include "src/core/SkScalerCache.h" 13cb93a386Sopenharmony_ci#include "src/core/SkStrikeSpec.h" 14cb93a386Sopenharmony_ci#include "src/pdf/SkPDFGlyphUse.h" 15cb93a386Sopenharmony_ci 16cb93a386Sopenharmony_ci#include <algorithm> 17cb93a386Sopenharmony_ci#include <vector> 18cb93a386Sopenharmony_ci 19cb93a386Sopenharmony_ci// TODO(halcanary): Write unit tests for SkPDFMakeCIDGlyphWidthsArray(). 20cb93a386Sopenharmony_ci 21cb93a386Sopenharmony_ci// TODO(halcanary): The logic in this file originated in several 22cb93a386Sopenharmony_ci// disparate places. I feel sure that someone could simplify this 23cb93a386Sopenharmony_ci// down to a single easy-to-read function. 24cb93a386Sopenharmony_ci 25cb93a386Sopenharmony_cinamespace { 26cb93a386Sopenharmony_ci 27cb93a386Sopenharmony_ci// scale from em-units to base-1000, returning as a SkScalar 28cb93a386Sopenharmony_ciSkScalar from_font_units(SkScalar scaled, uint16_t emSize) { 29cb93a386Sopenharmony_ci if (emSize == 1000) { 30cb93a386Sopenharmony_ci return scaled; 31cb93a386Sopenharmony_ci } else { 32cb93a386Sopenharmony_ci return scaled * 1000 / emSize; 33cb93a386Sopenharmony_ci } 34cb93a386Sopenharmony_ci} 35cb93a386Sopenharmony_ci 36cb93a386Sopenharmony_ciSkScalar scale_from_font_units(int16_t val, uint16_t emSize) { 37cb93a386Sopenharmony_ci return from_font_units(SkIntToScalar(val), emSize); 38cb93a386Sopenharmony_ci} 39cb93a386Sopenharmony_ci 40cb93a386Sopenharmony_ci// Unfortunately poppler does not appear to respect the default width setting. 41cb93a386Sopenharmony_ci#if defined(SK_PDF_CAN_USE_DW) 42cb93a386Sopenharmony_ciint16_t findMode(SkSpan<const int16_t> advances) { 43cb93a386Sopenharmony_ci if (advances.empty()) { 44cb93a386Sopenharmony_ci return 0; 45cb93a386Sopenharmony_ci } 46cb93a386Sopenharmony_ci 47cb93a386Sopenharmony_ci int16_t previousAdvance = advances[0]; 48cb93a386Sopenharmony_ci int16_t currentModeAdvance = advances[0]; 49cb93a386Sopenharmony_ci size_t currentCount = 1; 50cb93a386Sopenharmony_ci size_t currentModeCount = 1; 51cb93a386Sopenharmony_ci 52cb93a386Sopenharmony_ci for (size_t i = 1; i < advances.size(); ++i) { 53cb93a386Sopenharmony_ci if (advances[i] == previousAdvance) { 54cb93a386Sopenharmony_ci ++currentCount; 55cb93a386Sopenharmony_ci } else { 56cb93a386Sopenharmony_ci if (currentCount > currentModeCount) { 57cb93a386Sopenharmony_ci currentModeAdvance = previousAdvance; 58cb93a386Sopenharmony_ci currentModeCount = currentCount; 59cb93a386Sopenharmony_ci } 60cb93a386Sopenharmony_ci previousAdvance = advances[i]; 61cb93a386Sopenharmony_ci currentCount = 1; 62cb93a386Sopenharmony_ci } 63cb93a386Sopenharmony_ci } 64cb93a386Sopenharmony_ci 65cb93a386Sopenharmony_ci return currentCount > currentModeCount ? previousAdvance : currentModeAdvance; 66cb93a386Sopenharmony_ci} 67cb93a386Sopenharmony_ci#endif 68cb93a386Sopenharmony_ci} // namespace 69cb93a386Sopenharmony_ci 70cb93a386Sopenharmony_ci/** Retrieve advance data for glyphs. Used by the PDF backend. */ 71cb93a386Sopenharmony_ci// TODO(halcanary): this function is complex enough to need its logic 72cb93a386Sopenharmony_ci// tested with unit tests. 73cb93a386Sopenharmony_cistd::unique_ptr<SkPDFArray> SkPDFMakeCIDGlyphWidthsArray(const SkTypeface& typeface, 74cb93a386Sopenharmony_ci const SkPDFGlyphUse& subset, 75cb93a386Sopenharmony_ci SkScalar* defaultAdvance) { 76cb93a386Sopenharmony_ci // There are two ways of expressing advances 77cb93a386Sopenharmony_ci // 78cb93a386Sopenharmony_ci // range: " gfid [adv.ances adv.ances ... adv.ances]" 79cb93a386Sopenharmony_ci // run: " gfid gfid adv.ances" 80cb93a386Sopenharmony_ci // 81cb93a386Sopenharmony_ci // Assuming that on average 82cb93a386Sopenharmony_ci // the ASCII representation of an advance plus a space is 10 characters 83cb93a386Sopenharmony_ci // the ASCII representation of a glyph id plus a space is 4 characters 84cb93a386Sopenharmony_ci // the ASCII representation of unused gid plus a space in a range is 2 characters 85cb93a386Sopenharmony_ci // 86cb93a386Sopenharmony_ci // When not in a range or run 87cb93a386Sopenharmony_ci // a. Skipping don't cares or defaults is a win (trivial) 88cb93a386Sopenharmony_ci // b. Run wins for 2+ repeats " gid gid adv.ances" 89cb93a386Sopenharmony_ci // " gid [adv.ances adv.ances]" 90cb93a386Sopenharmony_ci // rule: 2+ repeats create run as long as possible, else start range 91cb93a386Sopenharmony_ci // 92cb93a386Sopenharmony_ci // When in a range 93cb93a386Sopenharmony_ci // Cost of stopping and starting a range is 8 characters "] gid [" 94cb93a386Sopenharmony_ci // c. Skipping defaults is always a win " adv.ances" 95cb93a386Sopenharmony_ci // rule: end range if default seen 96cb93a386Sopenharmony_ci // d. Skipping 4+ don't cares is a win " 0 0 0 0" 97cb93a386Sopenharmony_ci // rule: end range if 4+ don't cares 98cb93a386Sopenharmony_ci // Cost of stop and start range plus run is 28 characters "] gid gid adv.ances gid [" 99cb93a386Sopenharmony_ci // e. Switching for 2+ repeats and 4+ don't cares wins " 0 0 adv.ances 0 0 adv.ances" 100cb93a386Sopenharmony_ci // rule: end range for 2+ repeats with 4+ don't cares 101cb93a386Sopenharmony_ci // f. Switching for 3+ repeats wins " adv.ances adv.ances adv.ances" 102cb93a386Sopenharmony_ci // rule: end range for 3+ repeats 103cb93a386Sopenharmony_ci 104cb93a386Sopenharmony_ci int emSize; 105cb93a386Sopenharmony_ci SkStrikeSpec strikeSpec = SkStrikeSpec::MakePDFVector(typeface, &emSize); 106cb93a386Sopenharmony_ci SkBulkGlyphMetricsAndPaths paths{strikeSpec}; 107cb93a386Sopenharmony_ci 108cb93a386Sopenharmony_ci auto result = SkPDFMakeArray(); 109cb93a386Sopenharmony_ci 110cb93a386Sopenharmony_ci std::vector<SkGlyphID> glyphIDs; 111cb93a386Sopenharmony_ci subset.getSetValues([&](unsigned index) { 112cb93a386Sopenharmony_ci glyphIDs.push_back(SkToU16(index)); 113cb93a386Sopenharmony_ci }); 114cb93a386Sopenharmony_ci auto glyphs = paths.glyphs(SkMakeSpan(glyphIDs)); 115cb93a386Sopenharmony_ci 116cb93a386Sopenharmony_ci#if defined(SK_PDF_CAN_USE_DW) 117cb93a386Sopenharmony_ci std::vector<int16_t> advances; 118cb93a386Sopenharmony_ci advances.reserve_back(glyphs.size()); 119cb93a386Sopenharmony_ci for (const SkGlyph* glyph : glyphs) { 120cb93a386Sopenharmony_ci advances.push_back((int16_t)glyph->advanceX()); 121cb93a386Sopenharmony_ci } 122cb93a386Sopenharmony_ci std::sort(advances.begin(), advances.end()); 123cb93a386Sopenharmony_ci int16_t modeAdvance = findMode(SkMakeSpan(advances)); 124cb93a386Sopenharmony_ci *defaultAdvance = scale_from_font_units(modeAdvance, emSize); 125cb93a386Sopenharmony_ci#else 126cb93a386Sopenharmony_ci *defaultAdvance = 0; 127cb93a386Sopenharmony_ci#endif 128cb93a386Sopenharmony_ci 129cb93a386Sopenharmony_ci for (size_t i = 0; i < glyphs.size(); ++i) { 130cb93a386Sopenharmony_ci int16_t advance = (int16_t)glyphs[i]->advanceX(); 131cb93a386Sopenharmony_ci 132cb93a386Sopenharmony_ci#if defined(SK_PDF_CAN_USE_DW) 133cb93a386Sopenharmony_ci // a. Skipping don't cares or defaults is a win (trivial) 134cb93a386Sopenharmony_ci if (advance == modeAdvance) { 135cb93a386Sopenharmony_ci continue; 136cb93a386Sopenharmony_ci } 137cb93a386Sopenharmony_ci#endif 138cb93a386Sopenharmony_ci 139cb93a386Sopenharmony_ci // b. 2+ repeats create run as long as possible, else start range 140cb93a386Sopenharmony_ci { 141cb93a386Sopenharmony_ci size_t j = i + 1; // j is always one past the last known repeat 142cb93a386Sopenharmony_ci for (; j < glyphs.size(); ++j) { 143cb93a386Sopenharmony_ci int16_t next_advance = (int16_t)glyphs[j]->advanceX(); 144cb93a386Sopenharmony_ci if (advance != next_advance) { 145cb93a386Sopenharmony_ci break; 146cb93a386Sopenharmony_ci } 147cb93a386Sopenharmony_ci } 148cb93a386Sopenharmony_ci if (j - i >= 2) { 149cb93a386Sopenharmony_ci result->appendInt(glyphs[i]->getGlyphID()); 150cb93a386Sopenharmony_ci result->appendInt(glyphs[j - 1]->getGlyphID()); 151cb93a386Sopenharmony_ci result->appendScalar(scale_from_font_units(advance, emSize)); 152cb93a386Sopenharmony_ci i = j - 1; 153cb93a386Sopenharmony_ci continue; 154cb93a386Sopenharmony_ci } 155cb93a386Sopenharmony_ci } 156cb93a386Sopenharmony_ci 157cb93a386Sopenharmony_ci { 158cb93a386Sopenharmony_ci result->appendInt(glyphs[i]->getGlyphID()); 159cb93a386Sopenharmony_ci auto advanceArray = SkPDFMakeArray(); 160cb93a386Sopenharmony_ci advanceArray->appendScalar(scale_from_font_units(advance, emSize)); 161cb93a386Sopenharmony_ci size_t j = i + 1; // j is always one past the last output 162cb93a386Sopenharmony_ci for (; j < glyphs.size(); ++j) { 163cb93a386Sopenharmony_ci advance = (int16_t)glyphs[j]->advanceX(); 164cb93a386Sopenharmony_ci#if defined(SK_PDF_CAN_USE_DW) 165cb93a386Sopenharmony_ci // c. end range if default seen 166cb93a386Sopenharmony_ci if (advance == modeAdvance) { 167cb93a386Sopenharmony_ci break; 168cb93a386Sopenharmony_ci } 169cb93a386Sopenharmony_ci#endif 170cb93a386Sopenharmony_ci 171cb93a386Sopenharmony_ci int dontCares = glyphs[j]->getGlyphID() - glyphs[j - 1]->getGlyphID() - 1; 172cb93a386Sopenharmony_ci // d. end range if 4+ don't cares 173cb93a386Sopenharmony_ci if (dontCares >= 4) { 174cb93a386Sopenharmony_ci break; 175cb93a386Sopenharmony_ci } 176cb93a386Sopenharmony_ci 177cb93a386Sopenharmony_ci int16_t next_advance = 0; 178cb93a386Sopenharmony_ci // e. end range for 2+ repeats with 4+ don't cares 179cb93a386Sopenharmony_ci if (j + 1 < glyphs.size()) { 180cb93a386Sopenharmony_ci next_advance = (int16_t)glyphs[j+1]->advanceX(); 181cb93a386Sopenharmony_ci int next_dontCares = glyphs[j+1]->getGlyphID() - glyphs[j]->getGlyphID() - 1; 182cb93a386Sopenharmony_ci if (advance == next_advance && dontCares + next_dontCares >= 4) { 183cb93a386Sopenharmony_ci break; 184cb93a386Sopenharmony_ci } 185cb93a386Sopenharmony_ci } 186cb93a386Sopenharmony_ci 187cb93a386Sopenharmony_ci // f. end range for 3+ repeats 188cb93a386Sopenharmony_ci if (j + 2 < glyphs.size() && advance == next_advance) { 189cb93a386Sopenharmony_ci next_advance = (int16_t)glyphs[j+2]->advanceX(); 190cb93a386Sopenharmony_ci if (advance == next_advance) { 191cb93a386Sopenharmony_ci break; 192cb93a386Sopenharmony_ci } 193cb93a386Sopenharmony_ci } 194cb93a386Sopenharmony_ci 195cb93a386Sopenharmony_ci while (dontCares --> 0) { 196cb93a386Sopenharmony_ci advanceArray->appendScalar(0); 197cb93a386Sopenharmony_ci } 198cb93a386Sopenharmony_ci advanceArray->appendScalar(scale_from_font_units(advance, emSize)); 199cb93a386Sopenharmony_ci } 200cb93a386Sopenharmony_ci result->appendObject(std::move(advanceArray)); 201cb93a386Sopenharmony_ci i = j - 1; 202cb93a386Sopenharmony_ci } 203cb93a386Sopenharmony_ci } 204cb93a386Sopenharmony_ci 205cb93a386Sopenharmony_ci return result; 206cb93a386Sopenharmony_ci} 207