blob: 81e98f36132ab7cf238df9f95db71cbd171e7c23 [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001
vandebo@chromium.org6f72d1e2011-02-14 23:19:59 +00002/*
epoger@google.comec3ed6a2011-07-28 14:26:00 +00003 * Copyright 2011 Google Inc.
vandebo@chromium.org6f72d1e2011-02-14 23:19:59 +00004 *
epoger@google.comec3ed6a2011-07-28 14:26:00 +00005 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
vandebo@chromium.org6f72d1e2011-02-14 23:19:59 +00007 */
8
epoger@google.comec3ed6a2011-07-28 14:26:00 +00009
vandebo@chromium.org6f72d1e2011-02-14 23:19:59 +000010#include "SkAdvancedTypefaceMetrics.h"
11#include "SkTypes.h"
12
bungeman@google.comb49d9892012-08-16 17:35:58 +000013#if defined(SK_BUILD_FOR_WIN)
bungeman@google.com42843882012-10-30 14:15:32 +000014#include <dwrite.h>
bungeman@google.come8f05922012-08-16 16:13:40 +000015#endif
16
djsollen@google.com856b9842013-04-15 14:37:28 +000017#if defined(SK_BUILD_FOR_UNIX) || defined(SK_BUILD_FOR_ANDROID)
18// forward declare structs needed for getAdvanceData() template for freetype
bungemand3ebb482015-08-05 13:57:49 -070019struct FT_FaceRec_;
djsollen@google.com856b9842013-04-15 14:37:28 +000020typedef struct FT_FaceRec_* FT_Face;
vandebo@chromium.org6f72d1e2011-02-14 23:19:59 +000021#endif
22
caryclark@google.comab0ab4a2011-06-01 20:15:20 +000023#ifdef SK_BUILD_FOR_MAC
yangsu@google.comccb74ea2011-06-21 13:09:32 +000024#import <ApplicationServices/ApplicationServices.h>
25#endif
26
27#ifdef SK_BUILD_FOR_IOS
28#include <CoreText/CoreText.h>
29#include <CoreGraphics/CoreGraphics.h>
yangsu@google.com900d8772011-06-24 18:56:00 +000030#include <CoreFoundation/CoreFoundation.h>
caryclark@google.comab0ab4a2011-06-01 20:15:20 +000031#endif
32
vandebo@chromium.org6f72d1e2011-02-14 23:19:59 +000033namespace skia_advanced_typeface_metrics_utils {
34
vandebo@chromium.orgbeb7fe12011-11-11 19:38:54 +000035const int16_t kInvalidAdvance = SK_MinS16;
36const int16_t kDontCareAdvance = SK_MinS16 + 1;
37
vandebo@chromium.org6f72d1e2011-02-14 23:19:59 +000038template <typename Data>
reed@google.comb42403b2011-11-14 13:12:47 +000039void stripUninterestingTrailingAdvancesFromRange(
40 SkAdvancedTypefaceMetrics::AdvanceMetric<Data>* range) {
41 SkASSERT(false);
42}
43
44template <>
45void stripUninterestingTrailingAdvancesFromRange<int16_t>(
46 SkAdvancedTypefaceMetrics::AdvanceMetric<int16_t>* range) {
47 SkASSERT(range);
rmistry@google.comfbfcd562012-08-23 18:09:54 +000048
reed@google.comb42403b2011-11-14 13:12:47 +000049 int expectedAdvanceCount = range->fEndId - range->fStartId + 1;
50 if (range->fAdvance.count() < expectedAdvanceCount) {
51 return;
52 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +000053
reed@google.comb42403b2011-11-14 13:12:47 +000054 for (int i = expectedAdvanceCount - 1; i >= 0; --i) {
55 if (range->fAdvance[i] != kDontCareAdvance &&
56 range->fAdvance[i] != kInvalidAdvance &&
57 range->fAdvance[i] != 0) {
58 range->fEndId = range->fStartId + i;
59 break;
60 }
61 }
62}
63
64template <typename Data>
vandebo@chromium.org6f72d1e2011-02-14 23:19:59 +000065void resetRange(SkAdvancedTypefaceMetrics::AdvanceMetric<Data>* range,
66 int startId) {
67 range->fStartId = startId;
68 range->fAdvance.setCount(0);
69}
70
71template <typename Data>
72SkAdvancedTypefaceMetrics::AdvanceMetric<Data>* appendRange(
commit-bot@chromium.orge0294402013-08-29 22:14:04 +000073 SkAutoTDelete<SkAdvancedTypefaceMetrics::AdvanceMetric<Data> >* nextSlot,
vandebo@chromium.org6f72d1e2011-02-14 23:19:59 +000074 int startId) {
75 nextSlot->reset(new SkAdvancedTypefaceMetrics::AdvanceMetric<Data>);
76 resetRange(nextSlot->get(), startId);
77 return nextSlot->get();
78}
79
80template <typename Data>
reed@google.comb42403b2011-11-14 13:12:47 +000081void zeroWildcardsInRange(
82 SkAdvancedTypefaceMetrics::AdvanceMetric<Data>* range) {
83 SkASSERT(false);
84}
85
86template <>
87void zeroWildcardsInRange<int16_t>(
88 SkAdvancedTypefaceMetrics::AdvanceMetric<int16_t>* range) {
89 SkASSERT(range);
90 if (range->fType != SkAdvancedTypefaceMetrics::WidthRange::kRange) {
91 return;
92 }
93 SkASSERT(range->fAdvance.count() == range->fEndId - range->fStartId + 1);
rmistry@google.comfbfcd562012-08-23 18:09:54 +000094
reed@google.comb42403b2011-11-14 13:12:47 +000095 // Zero out wildcards.
96 for (int i = 0; i < range->fAdvance.count(); ++i) {
97 if (range->fAdvance[i] == kDontCareAdvance) {
98 range->fAdvance[i] = 0;
99 }
100 }
101}
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000102
reed@google.comb42403b2011-11-14 13:12:47 +0000103template <typename Data>
vandebo@chromium.org6f72d1e2011-02-14 23:19:59 +0000104void finishRange(
105 SkAdvancedTypefaceMetrics::AdvanceMetric<Data>* range,
106 int endId,
107 typename SkAdvancedTypefaceMetrics::AdvanceMetric<Data>::MetricType
108 type) {
109 range->fEndId = endId;
110 range->fType = type;
vandebo@chromium.orgbeb7fe12011-11-11 19:38:54 +0000111 stripUninterestingTrailingAdvancesFromRange(range);
vandebo@chromium.org6f72d1e2011-02-14 23:19:59 +0000112 int newLength;
113 if (type == SkAdvancedTypefaceMetrics::AdvanceMetric<Data>::kRange) {
vandebo@chromium.orgbeb7fe12011-11-11 19:38:54 +0000114 newLength = range->fEndId - range->fStartId + 1;
vandebo@chromium.org6f72d1e2011-02-14 23:19:59 +0000115 } else {
vandebo@chromium.orgbeb7fe12011-11-11 19:38:54 +0000116 if (range->fEndId == range->fStartId) {
117 range->fType =
118 SkAdvancedTypefaceMetrics::AdvanceMetric<Data>::kRange;
119 }
vandebo@chromium.org6f72d1e2011-02-14 23:19:59 +0000120 newLength = 1;
121 }
122 SkASSERT(range->fAdvance.count() >= newLength);
123 range->fAdvance.setCount(newLength);
vandebo@chromium.orgbeb7fe12011-11-11 19:38:54 +0000124 zeroWildcardsInRange(range);
125}
126
vandebo@chromium.org6f72d1e2011-02-14 23:19:59 +0000127template <typename Data, typename FontHandle>
128SkAdvancedTypefaceMetrics::AdvanceMetric<Data>* getAdvanceData(
129 FontHandle fontHandle,
130 int num_glyphs,
vandebo@chromium.org37ad8fb2011-08-18 02:38:50 +0000131 const uint32_t* subsetGlyphIDs,
132 uint32_t subsetGlyphIDsLength,
vandebo@chromium.org6f72d1e2011-02-14 23:19:59 +0000133 bool (*getAdvance)(FontHandle fontHandle, int gId, Data* data)) {
vandebo@chromium.orgbeb7fe12011-11-11 19:38:54 +0000134 // Assuming that on average, the ASCII representation of an advance plus
135 // a space is 8 characters and the ASCII representation of a glyph id is 3
136 // characters, then the following cut offs for using different range types
137 // apply:
138 // The cost of stopping and starting the range is 7 characers
139 // a. Removing 4 0's or don't care's is a win
140 // The cost of stopping and starting the range plus a run is 22
141 // characters
142 // b. Removing 3 repeating advances is a win
143 // c. Removing 2 repeating advances and 3 don't cares is a win
144 // When not currently in a range the cost of a run over a range is 16
145 // characaters, so:
146 // d. Removing a leading 0/don't cares is a win because it is omitted
147 // e. Removing 2 repeating advances is a win
vandebo@chromium.org6f72d1e2011-02-14 23:19:59 +0000148
commit-bot@chromium.orge0294402013-08-29 22:14:04 +0000149 SkAutoTDelete<SkAdvancedTypefaceMetrics::AdvanceMetric<Data> > result;
vandebo@chromium.org6f72d1e2011-02-14 23:19:59 +0000150 SkAdvancedTypefaceMetrics::AdvanceMetric<Data>* curRange;
vandebo@chromium.org34dae872011-05-10 23:25:03 +0000151 SkAdvancedTypefaceMetrics::AdvanceMetric<Data>* prevRange = NULL;
vandebo@chromium.orgbeb7fe12011-11-11 19:38:54 +0000152 Data lastAdvance = kInvalidAdvance;
153 int repeatedAdvances = 0;
154 int wildCardsInRun = 0;
vandebo@chromium.orgbeb7fe12011-11-11 19:38:54 +0000155 int trailingWildCards = 0;
vandebo@chromium.org37ad8fb2011-08-18 02:38:50 +0000156 uint32_t subsetIndex = 0;
vandebo@chromium.orgbeb7fe12011-11-11 19:38:54 +0000157
158 // Limit the loop count to glyph id ranges provided.
159 int firstIndex = 0;
160 int lastIndex = num_glyphs;
161 if (subsetGlyphIDs) {
162 firstIndex = static_cast<int>(subsetGlyphIDs[0]);
163 lastIndex =
164 static_cast<int>(subsetGlyphIDs[subsetGlyphIDsLength - 1]) + 1;
165 }
166 curRange = appendRange(&result, firstIndex);
167
168 for (int gId = firstIndex; gId <= lastIndex; gId++) {
169 Data advance = kInvalidAdvance;
170 if (gId < lastIndex) {
vandebo@chromium.org37ad8fb2011-08-18 02:38:50 +0000171 // Get glyph id only when subset is NULL, or the id is in subset.
commit-bot@chromium.org4da3bfc2013-12-11 23:54:31 +0000172 SkASSERT(!subsetGlyphIDs || (subsetIndex < subsetGlyphIDsLength &&
173 static_cast<uint32_t>(gId) <= subsetGlyphIDs[subsetIndex]));
vandebo@chromium.org37ad8fb2011-08-18 02:38:50 +0000174 if (!subsetGlyphIDs ||
175 (subsetIndex < subsetGlyphIDsLength &&
vandebo@chromium.orgbeb7fe12011-11-11 19:38:54 +0000176 static_cast<uint32_t>(gId) == subsetGlyphIDs[subsetIndex])) {
edisonn@google.comf91c63e2013-01-23 20:12:31 +0000177 SkAssertResult(getAdvance(fontHandle, gId, &advance));
vandebo@chromium.org37ad8fb2011-08-18 02:38:50 +0000178 ++subsetIndex;
vandebo@chromium.orgbeb7fe12011-11-11 19:38:54 +0000179 } else {
180 advance = kDontCareAdvance;
vandebo@chromium.org37ad8fb2011-08-18 02:38:50 +0000181 }
vandebo@chromium.org34dae872011-05-10 23:25:03 +0000182 }
vandebo@chromium.org6f72d1e2011-02-14 23:19:59 +0000183 if (advance == lastAdvance) {
vandebo@chromium.orgbeb7fe12011-11-11 19:38:54 +0000184 repeatedAdvances++;
185 trailingWildCards = 0;
186 } else if (advance == kDontCareAdvance) {
187 wildCardsInRun++;
188 trailingWildCards++;
189 } else if (curRange->fAdvance.count() ==
190 repeatedAdvances + 1 + wildCardsInRun) { // All in run.
191 if (lastAdvance == 0) {
vandebo@chromium.org6f72d1e2011-02-14 23:19:59 +0000192 resetRange(curRange, gId);
vandebo@chromium.orgbeb7fe12011-11-11 19:38:54 +0000193 trailingWildCards = 0;
194 } else if (repeatedAdvances + 1 >= 2 || trailingWildCards >= 4) {
vandebo@chromium.org6f72d1e2011-02-14 23:19:59 +0000195 finishRange(curRange, gId - 1,
196 SkAdvancedTypefaceMetrics::WidthRange::kRun);
vandebo@chromium.org34dae872011-05-10 23:25:03 +0000197 prevRange = curRange;
vandebo@chromium.org6f72d1e2011-02-14 23:19:59 +0000198 curRange = appendRange(&curRange->fNext, gId);
vandebo@chromium.orgbeb7fe12011-11-11 19:38:54 +0000199 trailingWildCards = 0;
vandebo@chromium.org6f72d1e2011-02-14 23:19:59 +0000200 }
vandebo@chromium.orgbeb7fe12011-11-11 19:38:54 +0000201 repeatedAdvances = 0;
202 wildCardsInRun = trailingWildCards;
vandebo@chromium.orgbeb7fe12011-11-11 19:38:54 +0000203 trailingWildCards = 0;
vandebo@chromium.org6f72d1e2011-02-14 23:19:59 +0000204 } else {
vandebo@chromium.orgbeb7fe12011-11-11 19:38:54 +0000205 if (lastAdvance == 0 &&
206 repeatedAdvances + 1 + wildCardsInRun >= 4) {
207 finishRange(curRange,
208 gId - repeatedAdvances - wildCardsInRun - 2,
vandebo@chromium.org6f72d1e2011-02-14 23:19:59 +0000209 SkAdvancedTypefaceMetrics::WidthRange::kRange);
vandebo@chromium.org34dae872011-05-10 23:25:03 +0000210 prevRange = curRange;
vandebo@chromium.org6f72d1e2011-02-14 23:19:59 +0000211 curRange = appendRange(&curRange->fNext, gId);
vandebo@chromium.orgbeb7fe12011-11-11 19:38:54 +0000212 trailingWildCards = 0;
213 } else if (trailingWildCards >= 4 && repeatedAdvances + 1 < 2) {
214 finishRange(curRange,
215 gId - trailingWildCards - 1,
vandebo@chromium.org6f72d1e2011-02-14 23:19:59 +0000216 SkAdvancedTypefaceMetrics::WidthRange::kRange);
vandebo@chromium.orgbeb7fe12011-11-11 19:38:54 +0000217 prevRange = curRange;
218 curRange = appendRange(&curRange->fNext, gId);
219 trailingWildCards = 0;
220 } else if (lastAdvance != 0 &&
221 (repeatedAdvances + 1 >= 3 ||
222 (repeatedAdvances + 1 >= 2 && wildCardsInRun >= 3))) {
223 finishRange(curRange,
224 gId - repeatedAdvances - wildCardsInRun - 2,
225 SkAdvancedTypefaceMetrics::WidthRange::kRange);
226 curRange =
227 appendRange(&curRange->fNext,
228 gId - repeatedAdvances - wildCardsInRun - 1);
vandebo@chromium.org6f72d1e2011-02-14 23:19:59 +0000229 curRange->fAdvance.append(1, &lastAdvance);
230 finishRange(curRange, gId - 1,
231 SkAdvancedTypefaceMetrics::WidthRange::kRun);
vandebo@chromium.org34dae872011-05-10 23:25:03 +0000232 prevRange = curRange;
vandebo@chromium.org6f72d1e2011-02-14 23:19:59 +0000233 curRange = appendRange(&curRange->fNext, gId);
vandebo@chromium.orgbeb7fe12011-11-11 19:38:54 +0000234 trailingWildCards = 0;
vandebo@chromium.org6f72d1e2011-02-14 23:19:59 +0000235 }
vandebo@chromium.orgbeb7fe12011-11-11 19:38:54 +0000236 repeatedAdvances = 0;
237 wildCardsInRun = trailingWildCards;
vandebo@chromium.orgbeb7fe12011-11-11 19:38:54 +0000238 trailingWildCards = 0;
vandebo@chromium.org6f72d1e2011-02-14 23:19:59 +0000239 }
240 curRange->fAdvance.append(1, &advance);
vandebo@chromium.orgbeb7fe12011-11-11 19:38:54 +0000241 if (advance != kDontCareAdvance) {
242 lastAdvance = advance;
243 }
vandebo@chromium.org6f72d1e2011-02-14 23:19:59 +0000244 }
vandebo@chromium.orgbeb7fe12011-11-11 19:38:54 +0000245 if (curRange->fStartId == lastIndex) {
vandebo@chromium.org34dae872011-05-10 23:25:03 +0000246 SkASSERT(prevRange);
vandebo@chromium.orgbeb7fe12011-11-11 19:38:54 +0000247 SkASSERT(prevRange->fNext->fStartId == lastIndex);
commit-bot@chromium.orge0294402013-08-29 22:14:04 +0000248 prevRange->fNext.free();
vandebo@chromium.org34dae872011-05-10 23:25:03 +0000249 } else {
vandebo@chromium.orgbeb7fe12011-11-11 19:38:54 +0000250 finishRange(curRange, lastIndex - 1,
vandebo@chromium.org34dae872011-05-10 23:25:03 +0000251 SkAdvancedTypefaceMetrics::WidthRange::kRange);
252 }
commit-bot@chromium.orge0294402013-08-29 22:14:04 +0000253 return result.detach();
vandebo@chromium.org6f72d1e2011-02-14 23:19:59 +0000254}
255
256// Make AdvanceMetric template functions available for linking with typename
257// WidthRange and VerticalAdvanceRange.
bungeman@google.comb49d9892012-08-16 17:35:58 +0000258#if defined(SK_BUILD_FOR_WIN)
vandebo@chromium.org6f72d1e2011-02-14 23:19:59 +0000259template SkAdvancedTypefaceMetrics::WidthRange* getAdvanceData(
260 HDC hdc,
261 int num_glyphs,
vandebo@chromium.org37ad8fb2011-08-18 02:38:50 +0000262 const uint32_t* subsetGlyphIDs,
263 uint32_t subsetGlyphIDsLength,
vandebo@chromium.org6f72d1e2011-02-14 23:19:59 +0000264 bool (*getAdvance)(HDC hdc, int gId, int16_t* data));
bungeman@google.come8f05922012-08-16 16:13:40 +0000265template SkAdvancedTypefaceMetrics::WidthRange* getAdvanceData(
266 IDWriteFontFace* fontFace,
267 int num_glyphs,
268 const uint32_t* subsetGlyphIDs,
269 uint32_t subsetGlyphIDsLength,
270 bool (*getAdvance)(IDWriteFontFace* fontFace, int gId, int16_t* data));
djsollen@google.comda957722011-11-16 17:00:46 +0000271#elif defined(SK_BUILD_FOR_UNIX) || defined(SK_BUILD_FOR_ANDROID)
vandebo@chromium.org6f72d1e2011-02-14 23:19:59 +0000272template SkAdvancedTypefaceMetrics::WidthRange* getAdvanceData(
273 FT_Face face,
274 int num_glyphs,
vandebo@chromium.org37ad8fb2011-08-18 02:38:50 +0000275 const uint32_t* subsetGlyphIDs,
276 uint32_t subsetGlyphIDsLength,
vandebo@chromium.org6f72d1e2011-02-14 23:19:59 +0000277 bool (*getAdvance)(FT_Face face, int gId, int16_t* data));
yangsu@google.comccb74ea2011-06-21 13:09:32 +0000278#elif defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_IOS)
caryclark@google.comab0ab4a2011-06-01 20:15:20 +0000279template SkAdvancedTypefaceMetrics::WidthRange* getAdvanceData(
280 CTFontRef ctFont,
281 int num_glyphs,
vandebo@chromium.org37ad8fb2011-08-18 02:38:50 +0000282 const uint32_t* subsetGlyphIDs,
283 uint32_t subsetGlyphIDsLength,
caryclark@google.comab0ab4a2011-06-01 20:15:20 +0000284 bool (*getAdvance)(CTFontRef ctFont, int gId, int16_t* data));
vandebo@chromium.org6f72d1e2011-02-14 23:19:59 +0000285#endif
286template void resetRange(
287 SkAdvancedTypefaceMetrics::WidthRange* range,
288 int startId);
289template SkAdvancedTypefaceMetrics::WidthRange* appendRange(
commit-bot@chromium.orge0294402013-08-29 22:14:04 +0000290 SkAutoTDelete<SkAdvancedTypefaceMetrics::WidthRange >* nextSlot,
vandebo@chromium.org6f72d1e2011-02-14 23:19:59 +0000291 int startId);
292template void finishRange<int16_t>(
293 SkAdvancedTypefaceMetrics::WidthRange* range,
294 int endId,
295 SkAdvancedTypefaceMetrics::WidthRange::MetricType type);
296
297template void resetRange(
298 SkAdvancedTypefaceMetrics::VerticalAdvanceRange* range,
299 int startId);
300template SkAdvancedTypefaceMetrics::VerticalAdvanceRange* appendRange(
commit-bot@chromium.orge0294402013-08-29 22:14:04 +0000301 SkAutoTDelete<SkAdvancedTypefaceMetrics::VerticalAdvanceRange >*
vandebo@chromium.org6f72d1e2011-02-14 23:19:59 +0000302 nextSlot,
303 int startId);
304template void finishRange<SkAdvancedTypefaceMetrics::VerticalMetric>(
305 SkAdvancedTypefaceMetrics::VerticalAdvanceRange* range,
306 int endId,
307 SkAdvancedTypefaceMetrics::VerticalAdvanceRange::MetricType type);
308
djsollen@google.comedae1412012-06-25 17:01:46 +0000309// additional declaration needed for testing with a face of an unknown type
310template SkAdvancedTypefaceMetrics::WidthRange* getAdvanceData(
311 void* fontData,
312 int num_glyphs,
313 const uint32_t* subsetGlyphIDs,
314 uint32_t subsetGlyphIDsLength,
315 bool (*getAdvance)(void* fontData, int gId, int16_t* data));
316
vandebo@chromium.org6f72d1e2011-02-14 23:19:59 +0000317} // namespace skia_advanced_typeface_metrics_utils