blob: ce64a42d0a9bfb2cbce7d7d405c3db4d217b2254 [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
19struct FT_FaceRec;
20typedef 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.
172 if (!subsetGlyphIDs ||
173 (subsetIndex < subsetGlyphIDsLength &&
vandebo@chromium.orgbeb7fe12011-11-11 19:38:54 +0000174 static_cast<uint32_t>(gId) == subsetGlyphIDs[subsetIndex])) {
edisonn@google.comf91c63e2013-01-23 20:12:31 +0000175 SkAssertResult(getAdvance(fontHandle, gId, &advance));
vandebo@chromium.org37ad8fb2011-08-18 02:38:50 +0000176 ++subsetIndex;
vandebo@chromium.orgbeb7fe12011-11-11 19:38:54 +0000177 } else {
178 advance = kDontCareAdvance;
vandebo@chromium.org37ad8fb2011-08-18 02:38:50 +0000179 }
vandebo@chromium.org34dae872011-05-10 23:25:03 +0000180 }
vandebo@chromium.org6f72d1e2011-02-14 23:19:59 +0000181 if (advance == lastAdvance) {
vandebo@chromium.orgbeb7fe12011-11-11 19:38:54 +0000182 repeatedAdvances++;
183 trailingWildCards = 0;
184 } else if (advance == kDontCareAdvance) {
185 wildCardsInRun++;
186 trailingWildCards++;
187 } else if (curRange->fAdvance.count() ==
188 repeatedAdvances + 1 + wildCardsInRun) { // All in run.
189 if (lastAdvance == 0) {
vandebo@chromium.org6f72d1e2011-02-14 23:19:59 +0000190 resetRange(curRange, gId);
vandebo@chromium.orgbeb7fe12011-11-11 19:38:54 +0000191 trailingWildCards = 0;
192 } else if (repeatedAdvances + 1 >= 2 || trailingWildCards >= 4) {
vandebo@chromium.org6f72d1e2011-02-14 23:19:59 +0000193 finishRange(curRange, gId - 1,
194 SkAdvancedTypefaceMetrics::WidthRange::kRun);
vandebo@chromium.org34dae872011-05-10 23:25:03 +0000195 prevRange = curRange;
vandebo@chromium.org6f72d1e2011-02-14 23:19:59 +0000196 curRange = appendRange(&curRange->fNext, gId);
vandebo@chromium.orgbeb7fe12011-11-11 19:38:54 +0000197 trailingWildCards = 0;
vandebo@chromium.org6f72d1e2011-02-14 23:19:59 +0000198 }
vandebo@chromium.orgbeb7fe12011-11-11 19:38:54 +0000199 repeatedAdvances = 0;
200 wildCardsInRun = trailingWildCards;
vandebo@chromium.orgbeb7fe12011-11-11 19:38:54 +0000201 trailingWildCards = 0;
vandebo@chromium.org6f72d1e2011-02-14 23:19:59 +0000202 } else {
vandebo@chromium.orgbeb7fe12011-11-11 19:38:54 +0000203 if (lastAdvance == 0 &&
204 repeatedAdvances + 1 + wildCardsInRun >= 4) {
205 finishRange(curRange,
206 gId - repeatedAdvances - wildCardsInRun - 2,
vandebo@chromium.org6f72d1e2011-02-14 23:19:59 +0000207 SkAdvancedTypefaceMetrics::WidthRange::kRange);
vandebo@chromium.org34dae872011-05-10 23:25:03 +0000208 prevRange = curRange;
vandebo@chromium.org6f72d1e2011-02-14 23:19:59 +0000209 curRange = appendRange(&curRange->fNext, gId);
vandebo@chromium.orgbeb7fe12011-11-11 19:38:54 +0000210 trailingWildCards = 0;
211 } else if (trailingWildCards >= 4 && repeatedAdvances + 1 < 2) {
212 finishRange(curRange,
213 gId - trailingWildCards - 1,
vandebo@chromium.org6f72d1e2011-02-14 23:19:59 +0000214 SkAdvancedTypefaceMetrics::WidthRange::kRange);
vandebo@chromium.orgbeb7fe12011-11-11 19:38:54 +0000215 prevRange = curRange;
216 curRange = appendRange(&curRange->fNext, gId);
217 trailingWildCards = 0;
218 } else if (lastAdvance != 0 &&
219 (repeatedAdvances + 1 >= 3 ||
220 (repeatedAdvances + 1 >= 2 && wildCardsInRun >= 3))) {
221 finishRange(curRange,
222 gId - repeatedAdvances - wildCardsInRun - 2,
223 SkAdvancedTypefaceMetrics::WidthRange::kRange);
224 curRange =
225 appendRange(&curRange->fNext,
226 gId - repeatedAdvances - wildCardsInRun - 1);
vandebo@chromium.org6f72d1e2011-02-14 23:19:59 +0000227 curRange->fAdvance.append(1, &lastAdvance);
228 finishRange(curRange, gId - 1,
229 SkAdvancedTypefaceMetrics::WidthRange::kRun);
vandebo@chromium.org34dae872011-05-10 23:25:03 +0000230 prevRange = curRange;
vandebo@chromium.org6f72d1e2011-02-14 23:19:59 +0000231 curRange = appendRange(&curRange->fNext, gId);
vandebo@chromium.orgbeb7fe12011-11-11 19:38:54 +0000232 trailingWildCards = 0;
vandebo@chromium.org6f72d1e2011-02-14 23:19:59 +0000233 }
vandebo@chromium.orgbeb7fe12011-11-11 19:38:54 +0000234 repeatedAdvances = 0;
235 wildCardsInRun = trailingWildCards;
vandebo@chromium.orgbeb7fe12011-11-11 19:38:54 +0000236 trailingWildCards = 0;
vandebo@chromium.org6f72d1e2011-02-14 23:19:59 +0000237 }
238 curRange->fAdvance.append(1, &advance);
vandebo@chromium.orgbeb7fe12011-11-11 19:38:54 +0000239 if (advance != kDontCareAdvance) {
240 lastAdvance = advance;
241 }
vandebo@chromium.org6f72d1e2011-02-14 23:19:59 +0000242 }
vandebo@chromium.orgbeb7fe12011-11-11 19:38:54 +0000243 if (curRange->fStartId == lastIndex) {
vandebo@chromium.org34dae872011-05-10 23:25:03 +0000244 SkASSERT(prevRange);
vandebo@chromium.orgbeb7fe12011-11-11 19:38:54 +0000245 SkASSERT(prevRange->fNext->fStartId == lastIndex);
commit-bot@chromium.orge0294402013-08-29 22:14:04 +0000246 prevRange->fNext.free();
vandebo@chromium.org34dae872011-05-10 23:25:03 +0000247 } else {
vandebo@chromium.orgbeb7fe12011-11-11 19:38:54 +0000248 finishRange(curRange, lastIndex - 1,
vandebo@chromium.org34dae872011-05-10 23:25:03 +0000249 SkAdvancedTypefaceMetrics::WidthRange::kRange);
250 }
commit-bot@chromium.orge0294402013-08-29 22:14:04 +0000251 return result.detach();
vandebo@chromium.org6f72d1e2011-02-14 23:19:59 +0000252}
253
254// Make AdvanceMetric template functions available for linking with typename
255// WidthRange and VerticalAdvanceRange.
bungeman@google.comb49d9892012-08-16 17:35:58 +0000256#if defined(SK_BUILD_FOR_WIN)
vandebo@chromium.org6f72d1e2011-02-14 23:19:59 +0000257template SkAdvancedTypefaceMetrics::WidthRange* getAdvanceData(
258 HDC hdc,
259 int num_glyphs,
vandebo@chromium.org37ad8fb2011-08-18 02:38:50 +0000260 const uint32_t* subsetGlyphIDs,
261 uint32_t subsetGlyphIDsLength,
vandebo@chromium.org6f72d1e2011-02-14 23:19:59 +0000262 bool (*getAdvance)(HDC hdc, int gId, int16_t* data));
bungeman@google.come8f05922012-08-16 16:13:40 +0000263template SkAdvancedTypefaceMetrics::WidthRange* getAdvanceData(
264 IDWriteFontFace* fontFace,
265 int num_glyphs,
266 const uint32_t* subsetGlyphIDs,
267 uint32_t subsetGlyphIDsLength,
268 bool (*getAdvance)(IDWriteFontFace* fontFace, int gId, int16_t* data));
djsollen@google.comda957722011-11-16 17:00:46 +0000269#elif defined(SK_BUILD_FOR_UNIX) || defined(SK_BUILD_FOR_ANDROID)
vandebo@chromium.org6f72d1e2011-02-14 23:19:59 +0000270template SkAdvancedTypefaceMetrics::WidthRange* getAdvanceData(
271 FT_Face face,
272 int num_glyphs,
vandebo@chromium.org37ad8fb2011-08-18 02:38:50 +0000273 const uint32_t* subsetGlyphIDs,
274 uint32_t subsetGlyphIDsLength,
vandebo@chromium.org6f72d1e2011-02-14 23:19:59 +0000275 bool (*getAdvance)(FT_Face face, int gId, int16_t* data));
yangsu@google.comccb74ea2011-06-21 13:09:32 +0000276#elif defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_IOS)
caryclark@google.comab0ab4a2011-06-01 20:15:20 +0000277template SkAdvancedTypefaceMetrics::WidthRange* getAdvanceData(
278 CTFontRef ctFont,
279 int num_glyphs,
vandebo@chromium.org37ad8fb2011-08-18 02:38:50 +0000280 const uint32_t* subsetGlyphIDs,
281 uint32_t subsetGlyphIDsLength,
caryclark@google.comab0ab4a2011-06-01 20:15:20 +0000282 bool (*getAdvance)(CTFontRef ctFont, int gId, int16_t* data));
vandebo@chromium.org6f72d1e2011-02-14 23:19:59 +0000283#endif
284template void resetRange(
285 SkAdvancedTypefaceMetrics::WidthRange* range,
286 int startId);
287template SkAdvancedTypefaceMetrics::WidthRange* appendRange(
commit-bot@chromium.orge0294402013-08-29 22:14:04 +0000288 SkAutoTDelete<SkAdvancedTypefaceMetrics::WidthRange >* nextSlot,
vandebo@chromium.org6f72d1e2011-02-14 23:19:59 +0000289 int startId);
290template void finishRange<int16_t>(
291 SkAdvancedTypefaceMetrics::WidthRange* range,
292 int endId,
293 SkAdvancedTypefaceMetrics::WidthRange::MetricType type);
294
295template void resetRange(
296 SkAdvancedTypefaceMetrics::VerticalAdvanceRange* range,
297 int startId);
298template SkAdvancedTypefaceMetrics::VerticalAdvanceRange* appendRange(
commit-bot@chromium.orge0294402013-08-29 22:14:04 +0000299 SkAutoTDelete<SkAdvancedTypefaceMetrics::VerticalAdvanceRange >*
vandebo@chromium.org6f72d1e2011-02-14 23:19:59 +0000300 nextSlot,
301 int startId);
302template void finishRange<SkAdvancedTypefaceMetrics::VerticalMetric>(
303 SkAdvancedTypefaceMetrics::VerticalAdvanceRange* range,
304 int endId,
305 SkAdvancedTypefaceMetrics::VerticalAdvanceRange::MetricType type);
306
djsollen@google.comedae1412012-06-25 17:01:46 +0000307// additional declaration needed for testing with a face of an unknown type
308template SkAdvancedTypefaceMetrics::WidthRange* getAdvanceData(
309 void* fontData,
310 int num_glyphs,
311 const uint32_t* subsetGlyphIDs,
312 uint32_t subsetGlyphIDsLength,
313 bool (*getAdvance)(void* fontData, int gId, int16_t* data));
314
vandebo@chromium.org6f72d1e2011-02-14 23:19:59 +0000315} // namespace skia_advanced_typeface_metrics_utils