blob: 370616ef95dc6f6dd20169368d9228ff4c9e2f06 [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
robertphillips@google.com15e9d3e2012-06-21 20:25:03 +000013SK_DEFINE_INST_COUNT(SkAdvancedTypefaceMetrics)
14
bungeman@google.comb49d9892012-08-16 17:35:58 +000015#if defined(SK_BUILD_FOR_WIN)
bungeman@google.come8f05922012-08-16 16:13:40 +000016#include <DWrite.h>
17#endif
18
djsollen@google.comda957722011-11-16 17:00:46 +000019#if defined(SK_BUILD_FOR_UNIX) || defined(SK_BUILD_FOR_ANDROID)
vandebo@chromium.org6f72d1e2011-02-14 23:19:59 +000020#include <ft2build.h>
21#include FT_FREETYPE_H
22#endif
23
caryclark@google.comab0ab4a2011-06-01 20:15:20 +000024#ifdef SK_BUILD_FOR_MAC
yangsu@google.comccb74ea2011-06-21 13:09:32 +000025#import <ApplicationServices/ApplicationServices.h>
26#endif
27
28#ifdef SK_BUILD_FOR_IOS
29#include <CoreText/CoreText.h>
30#include <CoreGraphics/CoreGraphics.h>
yangsu@google.com900d8772011-06-24 18:56:00 +000031#include <CoreFoundation/CoreFoundation.h>
caryclark@google.comab0ab4a2011-06-01 20:15:20 +000032#endif
33
vandebo@chromium.org6f72d1e2011-02-14 23:19:59 +000034namespace skia_advanced_typeface_metrics_utils {
35
vandebo@chromium.orgbeb7fe12011-11-11 19:38:54 +000036const int16_t kInvalidAdvance = SK_MinS16;
37const int16_t kDontCareAdvance = SK_MinS16 + 1;
38
vandebo@chromium.org6f72d1e2011-02-14 23:19:59 +000039template <typename Data>
reed@google.comb42403b2011-11-14 13:12:47 +000040void stripUninterestingTrailingAdvancesFromRange(
41 SkAdvancedTypefaceMetrics::AdvanceMetric<Data>* range) {
42 SkASSERT(false);
43}
44
45template <>
46void stripUninterestingTrailingAdvancesFromRange<int16_t>(
47 SkAdvancedTypefaceMetrics::AdvanceMetric<int16_t>* range) {
48 SkASSERT(range);
rmistry@google.comfbfcd562012-08-23 18:09:54 +000049
reed@google.comb42403b2011-11-14 13:12:47 +000050 int expectedAdvanceCount = range->fEndId - range->fStartId + 1;
51 if (range->fAdvance.count() < expectedAdvanceCount) {
52 return;
53 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +000054
reed@google.comb42403b2011-11-14 13:12:47 +000055 for (int i = expectedAdvanceCount - 1; i >= 0; --i) {
56 if (range->fAdvance[i] != kDontCareAdvance &&
57 range->fAdvance[i] != kInvalidAdvance &&
58 range->fAdvance[i] != 0) {
59 range->fEndId = range->fStartId + i;
60 break;
61 }
62 }
63}
64
65template <typename Data>
vandebo@chromium.org6f72d1e2011-02-14 23:19:59 +000066void resetRange(SkAdvancedTypefaceMetrics::AdvanceMetric<Data>* range,
67 int startId) {
68 range->fStartId = startId;
69 range->fAdvance.setCount(0);
70}
71
72template <typename Data>
73SkAdvancedTypefaceMetrics::AdvanceMetric<Data>* appendRange(
74 SkTScopedPtr<SkAdvancedTypefaceMetrics::AdvanceMetric<Data> >* nextSlot,
75 int startId) {
76 nextSlot->reset(new SkAdvancedTypefaceMetrics::AdvanceMetric<Data>);
77 resetRange(nextSlot->get(), startId);
78 return nextSlot->get();
79}
80
81template <typename Data>
reed@google.comb42403b2011-11-14 13:12:47 +000082void zeroWildcardsInRange(
83 SkAdvancedTypefaceMetrics::AdvanceMetric<Data>* range) {
84 SkASSERT(false);
85}
86
87template <>
88void zeroWildcardsInRange<int16_t>(
89 SkAdvancedTypefaceMetrics::AdvanceMetric<int16_t>* range) {
90 SkASSERT(range);
91 if (range->fType != SkAdvancedTypefaceMetrics::WidthRange::kRange) {
92 return;
93 }
94 SkASSERT(range->fAdvance.count() == range->fEndId - range->fStartId + 1);
rmistry@google.comfbfcd562012-08-23 18:09:54 +000095
reed@google.comb42403b2011-11-14 13:12:47 +000096 // Zero out wildcards.
97 for (int i = 0; i < range->fAdvance.count(); ++i) {
98 if (range->fAdvance[i] == kDontCareAdvance) {
99 range->fAdvance[i] = 0;
100 }
101 }
102}
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000103
reed@google.comb42403b2011-11-14 13:12:47 +0000104template <typename Data>
vandebo@chromium.org6f72d1e2011-02-14 23:19:59 +0000105void finishRange(
106 SkAdvancedTypefaceMetrics::AdvanceMetric<Data>* range,
107 int endId,
108 typename SkAdvancedTypefaceMetrics::AdvanceMetric<Data>::MetricType
109 type) {
110 range->fEndId = endId;
111 range->fType = type;
vandebo@chromium.orgbeb7fe12011-11-11 19:38:54 +0000112 stripUninterestingTrailingAdvancesFromRange(range);
vandebo@chromium.org6f72d1e2011-02-14 23:19:59 +0000113 int newLength;
114 if (type == SkAdvancedTypefaceMetrics::AdvanceMetric<Data>::kRange) {
vandebo@chromium.orgbeb7fe12011-11-11 19:38:54 +0000115 newLength = range->fEndId - range->fStartId + 1;
vandebo@chromium.org6f72d1e2011-02-14 23:19:59 +0000116 } else {
vandebo@chromium.orgbeb7fe12011-11-11 19:38:54 +0000117 if (range->fEndId == range->fStartId) {
118 range->fType =
119 SkAdvancedTypefaceMetrics::AdvanceMetric<Data>::kRange;
120 }
vandebo@chromium.org6f72d1e2011-02-14 23:19:59 +0000121 newLength = 1;
122 }
123 SkASSERT(range->fAdvance.count() >= newLength);
124 range->fAdvance.setCount(newLength);
vandebo@chromium.orgbeb7fe12011-11-11 19:38:54 +0000125 zeroWildcardsInRange(range);
126}
127
vandebo@chromium.org6f72d1e2011-02-14 23:19:59 +0000128template <typename Data, typename FontHandle>
129SkAdvancedTypefaceMetrics::AdvanceMetric<Data>* getAdvanceData(
130 FontHandle fontHandle,
131 int num_glyphs,
vandebo@chromium.org37ad8fb2011-08-18 02:38:50 +0000132 const uint32_t* subsetGlyphIDs,
133 uint32_t subsetGlyphIDsLength,
vandebo@chromium.org6f72d1e2011-02-14 23:19:59 +0000134 bool (*getAdvance)(FontHandle fontHandle, int gId, Data* data)) {
vandebo@chromium.orgbeb7fe12011-11-11 19:38:54 +0000135 // Assuming that on average, the ASCII representation of an advance plus
136 // a space is 8 characters and the ASCII representation of a glyph id is 3
137 // characters, then the following cut offs for using different range types
138 // apply:
139 // The cost of stopping and starting the range is 7 characers
140 // a. Removing 4 0's or don't care's is a win
141 // The cost of stopping and starting the range plus a run is 22
142 // characters
143 // b. Removing 3 repeating advances is a win
144 // c. Removing 2 repeating advances and 3 don't cares is a win
145 // When not currently in a range the cost of a run over a range is 16
146 // characaters, so:
147 // d. Removing a leading 0/don't cares is a win because it is omitted
148 // e. Removing 2 repeating advances is a win
vandebo@chromium.org6f72d1e2011-02-14 23:19:59 +0000149
150 SkTScopedPtr<SkAdvancedTypefaceMetrics::AdvanceMetric<Data> > result;
151 SkAdvancedTypefaceMetrics::AdvanceMetric<Data>* curRange;
vandebo@chromium.org34dae872011-05-10 23:25:03 +0000152 SkAdvancedTypefaceMetrics::AdvanceMetric<Data>* prevRange = NULL;
vandebo@chromium.orgbeb7fe12011-11-11 19:38:54 +0000153 Data lastAdvance = kInvalidAdvance;
154 int repeatedAdvances = 0;
155 int wildCardsInRun = 0;
156 int leadingWildCards = 0;
157 int trailingWildCards = 0;
vandebo@chromium.org37ad8fb2011-08-18 02:38:50 +0000158 uint32_t subsetIndex = 0;
vandebo@chromium.orgbeb7fe12011-11-11 19:38:54 +0000159
160 // Limit the loop count to glyph id ranges provided.
161 int firstIndex = 0;
162 int lastIndex = num_glyphs;
163 if (subsetGlyphIDs) {
164 firstIndex = static_cast<int>(subsetGlyphIDs[0]);
165 lastIndex =
166 static_cast<int>(subsetGlyphIDs[subsetGlyphIDsLength - 1]) + 1;
167 }
168 curRange = appendRange(&result, firstIndex);
169
170 for (int gId = firstIndex; gId <= lastIndex; gId++) {
171 Data advance = kInvalidAdvance;
172 if (gId < lastIndex) {
vandebo@chromium.org37ad8fb2011-08-18 02:38:50 +0000173 // Get glyph id only when subset is NULL, or the id is in subset.
174 if (!subsetGlyphIDs ||
175 (subsetIndex < subsetGlyphIDsLength &&
vandebo@chromium.orgbeb7fe12011-11-11 19:38:54 +0000176 static_cast<uint32_t>(gId) == subsetGlyphIDs[subsetIndex])) {
vandebo@chromium.org37ad8fb2011-08-18 02:38:50 +0000177 SkAssertResult(getAdvance(fontHandle, gId, &advance));
178 ++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;
203 leadingWildCards = trailingWildCards;
204 trailingWildCards = 0;
vandebo@chromium.org6f72d1e2011-02-14 23:19:59 +0000205 } else {
vandebo@chromium.orgbeb7fe12011-11-11 19:38:54 +0000206 if (lastAdvance == 0 &&
207 repeatedAdvances + 1 + wildCardsInRun >= 4) {
208 finishRange(curRange,
209 gId - repeatedAdvances - wildCardsInRun - 2,
vandebo@chromium.org6f72d1e2011-02-14 23:19:59 +0000210 SkAdvancedTypefaceMetrics::WidthRange::kRange);
vandebo@chromium.org34dae872011-05-10 23:25:03 +0000211 prevRange = curRange;
vandebo@chromium.org6f72d1e2011-02-14 23:19:59 +0000212 curRange = appendRange(&curRange->fNext, gId);
vandebo@chromium.orgbeb7fe12011-11-11 19:38:54 +0000213 trailingWildCards = 0;
214 } else if (trailingWildCards >= 4 && repeatedAdvances + 1 < 2) {
215 finishRange(curRange,
216 gId - trailingWildCards - 1,
vandebo@chromium.org6f72d1e2011-02-14 23:19:59 +0000217 SkAdvancedTypefaceMetrics::WidthRange::kRange);
vandebo@chromium.orgbeb7fe12011-11-11 19:38:54 +0000218 prevRange = curRange;
219 curRange = appendRange(&curRange->fNext, gId);
220 trailingWildCards = 0;
221 } else if (lastAdvance != 0 &&
222 (repeatedAdvances + 1 >= 3 ||
223 (repeatedAdvances + 1 >= 2 && wildCardsInRun >= 3))) {
224 finishRange(curRange,
225 gId - repeatedAdvances - wildCardsInRun - 2,
226 SkAdvancedTypefaceMetrics::WidthRange::kRange);
227 curRange =
228 appendRange(&curRange->fNext,
229 gId - repeatedAdvances - wildCardsInRun - 1);
vandebo@chromium.org6f72d1e2011-02-14 23:19:59 +0000230 curRange->fAdvance.append(1, &lastAdvance);
231 finishRange(curRange, gId - 1,
232 SkAdvancedTypefaceMetrics::WidthRange::kRun);
vandebo@chromium.org34dae872011-05-10 23:25:03 +0000233 prevRange = curRange;
vandebo@chromium.org6f72d1e2011-02-14 23:19:59 +0000234 curRange = appendRange(&curRange->fNext, gId);
vandebo@chromium.orgbeb7fe12011-11-11 19:38:54 +0000235 trailingWildCards = 0;
vandebo@chromium.org6f72d1e2011-02-14 23:19:59 +0000236 }
vandebo@chromium.orgbeb7fe12011-11-11 19:38:54 +0000237 repeatedAdvances = 0;
238 wildCardsInRun = trailingWildCards;
239 leadingWildCards = trailingWildCards;
240 trailingWildCards = 0;
vandebo@chromium.org6f72d1e2011-02-14 23:19:59 +0000241 }
242 curRange->fAdvance.append(1, &advance);
vandebo@chromium.orgbeb7fe12011-11-11 19:38:54 +0000243 if (advance != kDontCareAdvance) {
244 lastAdvance = advance;
245 }
vandebo@chromium.org6f72d1e2011-02-14 23:19:59 +0000246 }
vandebo@chromium.orgbeb7fe12011-11-11 19:38:54 +0000247 if (curRange->fStartId == lastIndex) {
vandebo@chromium.org34dae872011-05-10 23:25:03 +0000248 SkASSERT(prevRange);
vandebo@chromium.orgbeb7fe12011-11-11 19:38:54 +0000249 SkASSERT(prevRange->fNext->fStartId == lastIndex);
vandebo@chromium.org34dae872011-05-10 23:25:03 +0000250 prevRange->fNext.reset();
251 } else {
vandebo@chromium.orgbeb7fe12011-11-11 19:38:54 +0000252 finishRange(curRange, lastIndex - 1,
vandebo@chromium.org34dae872011-05-10 23:25:03 +0000253 SkAdvancedTypefaceMetrics::WidthRange::kRange);
254 }
vandebo@chromium.org6f72d1e2011-02-14 23:19:59 +0000255 return result.release();
256}
257
258// Make AdvanceMetric template functions available for linking with typename
259// WidthRange and VerticalAdvanceRange.
bungeman@google.comb49d9892012-08-16 17:35:58 +0000260#if defined(SK_BUILD_FOR_WIN)
vandebo@chromium.org6f72d1e2011-02-14 23:19:59 +0000261template SkAdvancedTypefaceMetrics::WidthRange* getAdvanceData(
262 HDC hdc,
263 int num_glyphs,
vandebo@chromium.org37ad8fb2011-08-18 02:38:50 +0000264 const uint32_t* subsetGlyphIDs,
265 uint32_t subsetGlyphIDsLength,
vandebo@chromium.org6f72d1e2011-02-14 23:19:59 +0000266 bool (*getAdvance)(HDC hdc, int gId, int16_t* data));
bungeman@google.come8f05922012-08-16 16:13:40 +0000267template SkAdvancedTypefaceMetrics::WidthRange* getAdvanceData(
268 IDWriteFontFace* fontFace,
269 int num_glyphs,
270 const uint32_t* subsetGlyphIDs,
271 uint32_t subsetGlyphIDsLength,
272 bool (*getAdvance)(IDWriteFontFace* fontFace, int gId, int16_t* data));
djsollen@google.comda957722011-11-16 17:00:46 +0000273#elif defined(SK_BUILD_FOR_UNIX) || defined(SK_BUILD_FOR_ANDROID)
vandebo@chromium.org6f72d1e2011-02-14 23:19:59 +0000274template SkAdvancedTypefaceMetrics::WidthRange* getAdvanceData(
275 FT_Face face,
276 int num_glyphs,
vandebo@chromium.org37ad8fb2011-08-18 02:38:50 +0000277 const uint32_t* subsetGlyphIDs,
278 uint32_t subsetGlyphIDsLength,
vandebo@chromium.org6f72d1e2011-02-14 23:19:59 +0000279 bool (*getAdvance)(FT_Face face, int gId, int16_t* data));
yangsu@google.comccb74ea2011-06-21 13:09:32 +0000280#elif defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_IOS)
caryclark@google.comab0ab4a2011-06-01 20:15:20 +0000281template SkAdvancedTypefaceMetrics::WidthRange* getAdvanceData(
282 CTFontRef ctFont,
283 int num_glyphs,
vandebo@chromium.org37ad8fb2011-08-18 02:38:50 +0000284 const uint32_t* subsetGlyphIDs,
285 uint32_t subsetGlyphIDsLength,
caryclark@google.comab0ab4a2011-06-01 20:15:20 +0000286 bool (*getAdvance)(CTFontRef ctFont, int gId, int16_t* data));
vandebo@chromium.org6f72d1e2011-02-14 23:19:59 +0000287#endif
288template void resetRange(
289 SkAdvancedTypefaceMetrics::WidthRange* range,
290 int startId);
291template SkAdvancedTypefaceMetrics::WidthRange* appendRange(
292 SkTScopedPtr<SkAdvancedTypefaceMetrics::WidthRange >* nextSlot,
293 int startId);
294template void finishRange<int16_t>(
295 SkAdvancedTypefaceMetrics::WidthRange* range,
296 int endId,
297 SkAdvancedTypefaceMetrics::WidthRange::MetricType type);
298
299template void resetRange(
300 SkAdvancedTypefaceMetrics::VerticalAdvanceRange* range,
301 int startId);
302template SkAdvancedTypefaceMetrics::VerticalAdvanceRange* appendRange(
303 SkTScopedPtr<SkAdvancedTypefaceMetrics::VerticalAdvanceRange >*
304 nextSlot,
305 int startId);
306template void finishRange<SkAdvancedTypefaceMetrics::VerticalMetric>(
307 SkAdvancedTypefaceMetrics::VerticalAdvanceRange* range,
308 int endId,
309 SkAdvancedTypefaceMetrics::VerticalAdvanceRange::MetricType type);
310
djsollen@google.comedae1412012-06-25 17:01:46 +0000311// additional declaration needed for testing with a face of an unknown type
312template SkAdvancedTypefaceMetrics::WidthRange* getAdvanceData(
313 void* fontData,
314 int num_glyphs,
315 const uint32_t* subsetGlyphIDs,
316 uint32_t subsetGlyphIDsLength,
317 bool (*getAdvance)(void* fontData, int gId, int16_t* data));
318
vandebo@chromium.org6f72d1e2011-02-14 23:19:59 +0000319} // namespace skia_advanced_typeface_metrics_utils