LCOV - code coverage report
Current view: top level - gfx/skia/skia/src/pdf - SkPDFMakeCIDGlyphWidthsArray.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 141 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 10 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Copyright 2016 Google Inc.
       3             :  *
       4             :  * Use of this source code is governed by a BSD-style license that can be
       5             :  * found in the LICENSE file.
       6             :  */
       7             : 
       8             : #include "SkBitSet.h"
       9             : #include "SkPDFMakeCIDGlyphWidthsArray.h"
      10             : #include "SkPaint.h"
      11             : #include "SkGlyphCache.h"
      12             : 
      13             : // TODO(halcanary): Write unit tests for SkPDFMakeCIDGlyphWidthsArray().
      14             : 
      15             : // TODO(halcanary): The logic in this file originated in several
      16             : // disparate places.  I feel sure that someone could simplify this
      17             : // down to a single easy-to-read function.
      18             : 
      19             : namespace {
      20             : 
      21           0 : struct AdvanceMetric {
      22             :     enum MetricType {
      23             :         kDefault,  // Default advance: fAdvance.count = 1
      24             :         kRange,    // Advances for a range: fAdvance.count = fEndID-fStartID
      25             :         kRun       // fStartID-fEndID have same advance: fAdvance.count = 1
      26             :     };
      27             :     MetricType fType;
      28             :     uint16_t fStartId;
      29             :     uint16_t fEndId;
      30             :     SkTDArray<int16_t> fAdvance;
      31           0 :     AdvanceMetric(uint16_t startId) : fStartId(startId) {}
      32             :     AdvanceMetric(AdvanceMetric&&) = default;
      33             :     AdvanceMetric& operator=(AdvanceMetric&& other) = default;
      34             :     AdvanceMetric(const AdvanceMetric&) = delete;
      35             :     AdvanceMetric& operator=(const AdvanceMetric&) = delete;
      36             : };
      37             : const int16_t kInvalidAdvance = SK_MinS16;
      38             : const int16_t kDontCareAdvance = SK_MinS16 + 1;
      39             : } // namespace
      40             : 
      41             : // scale from em-units to base-1000, returning as a SkScalar
      42           0 : static SkScalar from_font_units(SkScalar scaled, uint16_t emSize) {
      43           0 :     if (emSize == 1000) {
      44           0 :         return scaled;
      45             :     } else {
      46           0 :         return scaled * 1000 / emSize;
      47             :     }
      48             : }
      49             : 
      50           0 : static SkScalar scale_from_font_units(int16_t val, uint16_t emSize) {
      51           0 :     return from_font_units(SkIntToScalar(val), emSize);
      52             : }
      53             : 
      54           0 : static void strip_uninteresting_trailing_advances_from_range(
      55             :         AdvanceMetric* range) {
      56           0 :     SkASSERT(range);
      57             : 
      58           0 :     int expectedAdvanceCount = range->fEndId - range->fStartId + 1;
      59           0 :     if (range->fAdvance.count() < expectedAdvanceCount) {
      60           0 :         return;
      61             :     }
      62             : 
      63           0 :     for (int i = expectedAdvanceCount - 1; i >= 0; --i) {
      64           0 :         if (range->fAdvance[i] != kDontCareAdvance &&
      65           0 :             range->fAdvance[i] != kInvalidAdvance &&
      66           0 :             range->fAdvance[i] != 0) {
      67           0 :             range->fEndId = range->fStartId + i;
      68           0 :             break;
      69             :         }
      70             :     }
      71             : }
      72             : 
      73           0 : static void zero_wildcards_in_range(AdvanceMetric* range) {
      74           0 :     SkASSERT(range);
      75           0 :     if (range->fType != AdvanceMetric::kRange) {
      76           0 :         return;
      77             :     }
      78           0 :     SkASSERT(range->fAdvance.count() == range->fEndId - range->fStartId + 1);
      79             : 
      80             :     // Zero out wildcards.
      81           0 :     for (int i = 0; i < range->fAdvance.count(); ++i) {
      82           0 :         if (range->fAdvance[i] == kDontCareAdvance) {
      83           0 :             range->fAdvance[i] = 0;
      84             :         }
      85             :     }
      86             : }
      87             : 
      88           0 : static void finish_range(
      89             :         AdvanceMetric* range,
      90             :         int endId,
      91             :         AdvanceMetric::MetricType type) {
      92           0 :     range->fEndId = endId;
      93           0 :     range->fType = type;
      94           0 :     strip_uninteresting_trailing_advances_from_range(range);
      95             :     int newLength;
      96           0 :     if (type == AdvanceMetric::kRange) {
      97           0 :         newLength = range->fEndId - range->fStartId + 1;
      98             :     } else {
      99           0 :         if (range->fEndId == range->fStartId) {
     100           0 :             range->fType = AdvanceMetric::kRange;
     101             :         }
     102           0 :         newLength = 1;
     103             :     }
     104           0 :     SkASSERT(range->fAdvance.count() >= newLength);
     105           0 :     range->fAdvance.setCount(newLength);
     106           0 :     zero_wildcards_in_range(range);
     107           0 : }
     108             : 
     109           0 : static void compose_advance_data(const AdvanceMetric& range,
     110             :                                  uint16_t emSize,
     111             :                                  int16_t* defaultAdvance,
     112             :                                  SkPDFArray* result) {
     113           0 :     switch (range.fType) {
     114             :         case AdvanceMetric::kDefault: {
     115           0 :             SkASSERT(range.fAdvance.count() == 1);
     116           0 :             *defaultAdvance = range.fAdvance[0];
     117           0 :             break;
     118             :         }
     119             :         case AdvanceMetric::kRange: {
     120           0 :             auto advanceArray = sk_make_sp<SkPDFArray>();
     121           0 :             for (int j = 0; j < range.fAdvance.count(); j++)
     122           0 :                 advanceArray->appendScalar(
     123           0 :                         scale_from_font_units(range.fAdvance[j], emSize));
     124           0 :             result->appendInt(range.fStartId);
     125           0 :             result->appendObject(std::move(advanceArray));
     126           0 :             break;
     127             :         }
     128             :         case AdvanceMetric::kRun: {
     129           0 :             SkASSERT(range.fAdvance.count() == 1);
     130           0 :             result->appendInt(range.fStartId);
     131           0 :             result->appendInt(range.fEndId);
     132           0 :             result->appendScalar(
     133           0 :                     scale_from_font_units(range.fAdvance[0], emSize));
     134           0 :             break;
     135             :         }
     136             :     }
     137           0 : }
     138             : 
     139             : /** Retrieve advance data for glyphs. Used by the PDF backend. */
     140             : // TODO(halcanary): this function is complex enough to need its logic
     141             : // tested with unit tests.
     142           0 : sk_sp<SkPDFArray> SkPDFMakeCIDGlyphWidthsArray(SkGlyphCache* cache,
     143             :                                                const SkBitSet* subset,
     144             :                                                uint16_t emSize,
     145             :                                                int16_t* defaultAdvance) {
     146             :     // Assuming that on average, the ASCII representation of an advance plus
     147             :     // a space is 8 characters and the ASCII representation of a glyph id is 3
     148             :     // characters, then the following cut offs for using different range types
     149             :     // apply:
     150             :     // The cost of stopping and starting the range is 7 characers
     151             :     //  a. Removing 4 0's or don't care's is a win
     152             :     // The cost of stopping and starting the range plus a run is 22
     153             :     // characters
     154             :     //  b. Removing 3 repeating advances is a win
     155             :     //  c. Removing 2 repeating advances and 3 don't cares is a win
     156             :     // When not currently in a range the cost of a run over a range is 16
     157             :     // characaters, so:
     158             :     //  d. Removing a leading 0/don't cares is a win because it is omitted
     159             :     //  e. Removing 2 repeating advances is a win
     160             : 
     161           0 :     auto result = sk_make_sp<SkPDFArray>();
     162           0 :     int num_glyphs = SkToInt(cache->getGlyphCount());
     163             : 
     164           0 :     bool prevRange = false;
     165             : 
     166           0 :     int16_t lastAdvance = kInvalidAdvance;
     167           0 :     int repeatedAdvances = 0;
     168           0 :     int wildCardsInRun = 0;
     169           0 :     int trailingWildCards = 0;
     170             : 
     171             :     // Limit the loop count to glyph id ranges provided.
     172           0 :     int lastIndex = num_glyphs;
     173           0 :     if (subset) {
     174           0 :         while (!subset->has(lastIndex - 1) && lastIndex > 0) {
     175           0 :             --lastIndex;
     176             :         }
     177             :     }
     178           0 :     AdvanceMetric curRange(0);
     179             : 
     180           0 :     for (int gId = 0; gId <= lastIndex; gId++) {
     181           0 :         int16_t advance = kInvalidAdvance;
     182           0 :         if (gId < lastIndex) {
     183           0 :             if (!subset || 0 == gId || subset->has(gId)) {
     184           0 :                 advance = (int16_t)cache->getGlyphIDAdvance(gId).fAdvanceX;
     185             :             } else {
     186           0 :                 advance = kDontCareAdvance;
     187             :             }
     188             :         }
     189           0 :         if (advance == lastAdvance) {
     190           0 :             repeatedAdvances++;
     191           0 :             trailingWildCards = 0;
     192           0 :         } else if (advance == kDontCareAdvance) {
     193           0 :             wildCardsInRun++;
     194           0 :             trailingWildCards++;
     195           0 :         } else if (curRange.fAdvance.count() ==
     196           0 :                    repeatedAdvances + 1 + wildCardsInRun) {  // All in run.
     197           0 :             if (lastAdvance == 0) {
     198           0 :                 curRange.fStartId = gId;  // reset
     199           0 :                 curRange.fAdvance.setCount(0);
     200           0 :                 trailingWildCards = 0;
     201           0 :             } else if (repeatedAdvances + 1 >= 2 || trailingWildCards >= 4) {
     202           0 :                 finish_range(&curRange, gId - 1, AdvanceMetric::kRun);
     203           0 :                 compose_advance_data(curRange, emSize, defaultAdvance, result.get());
     204           0 :                 prevRange = true;
     205           0 :                 curRange = AdvanceMetric(gId);
     206           0 :                 trailingWildCards = 0;
     207             :             }
     208           0 :             repeatedAdvances = 0;
     209           0 :             wildCardsInRun = trailingWildCards;
     210           0 :             trailingWildCards = 0;
     211             :         } else {
     212           0 :             if (lastAdvance == 0 &&
     213           0 :                     repeatedAdvances + 1 + wildCardsInRun >= 4) {
     214           0 :                 finish_range(&curRange,
     215           0 :                             gId - repeatedAdvances - wildCardsInRun - 2,
     216           0 :                             AdvanceMetric::kRange);
     217           0 :                 compose_advance_data(curRange, emSize, defaultAdvance, result.get());
     218           0 :                 prevRange = true;
     219           0 :                 curRange = AdvanceMetric(gId);
     220           0 :                 trailingWildCards = 0;
     221           0 :             } else if (trailingWildCards >= 4 && repeatedAdvances + 1 < 2) {
     222           0 :                 finish_range(&curRange, gId - trailingWildCards - 1,
     223           0 :                             AdvanceMetric::kRange);
     224           0 :                 compose_advance_data(curRange, emSize, defaultAdvance, result.get());
     225           0 :                 prevRange = true;
     226           0 :                 curRange = AdvanceMetric(gId);
     227           0 :                 trailingWildCards = 0;
     228           0 :             } else if (lastAdvance != 0 &&
     229           0 :                        (repeatedAdvances + 1 >= 3 ||
     230           0 :                         (repeatedAdvances + 1 >= 2 && wildCardsInRun >= 3))) {
     231           0 :                 finish_range(&curRange,
     232           0 :                             gId - repeatedAdvances - wildCardsInRun - 2,
     233           0 :                             AdvanceMetric::kRange);
     234           0 :                 compose_advance_data(curRange, emSize, defaultAdvance, result.get());
     235             :                 curRange =
     236           0 :                         AdvanceMetric(gId - repeatedAdvances - wildCardsInRun - 1);
     237           0 :                 curRange.fAdvance.append(1, &lastAdvance);
     238           0 :                 finish_range(&curRange, gId - 1, AdvanceMetric::kRun);
     239           0 :                 compose_advance_data(curRange, emSize, defaultAdvance, result.get());
     240           0 :                 prevRange = true;
     241           0 :                 curRange = AdvanceMetric(gId);
     242           0 :                 trailingWildCards = 0;
     243             :             }
     244           0 :             repeatedAdvances = 0;
     245           0 :             wildCardsInRun = trailingWildCards;
     246           0 :             trailingWildCards = 0;
     247             :         }
     248           0 :         curRange.fAdvance.append(1, &advance);
     249           0 :         if (advance != kDontCareAdvance) {
     250           0 :             lastAdvance = advance;
     251             :         }
     252             :     }
     253           0 :     if (curRange.fStartId == lastIndex) {
     254           0 :         if (!prevRange) {
     255           0 :             return nullptr;  // https://crbug.com/567031
     256             :         }
     257             :     } else {
     258           0 :         finish_range(&curRange, lastIndex - 1, AdvanceMetric::kRange);
     259           0 :         compose_advance_data(curRange, emSize, defaultAdvance, result.get());
     260             :     }
     261           0 :     return result;
     262             : }

Generated by: LCOV version 1.13