blob: 8af70fb902d8c11344b9df2e9454272109136dba [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
djsollen@google.comda957722011-11-16 17:00:46 +000013#if defined(SK_BUILD_FOR_UNIX) || defined(SK_BUILD_FOR_ANDROID)
vandebo@chromium.org6f72d1e2011-02-14 23:19:59 +000014#include <ft2build.h>
15#include FT_FREETYPE_H
16#endif
17
caryclark@google.comab0ab4a2011-06-01 20:15:20 +000018#ifdef SK_BUILD_FOR_MAC
yangsu@google.comccb74ea2011-06-21 13:09:32 +000019#import <ApplicationServices/ApplicationServices.h>
20#endif
21
22#ifdef SK_BUILD_FOR_IOS
23#include <CoreText/CoreText.h>
24#include <CoreGraphics/CoreGraphics.h>
yangsu@google.com900d8772011-06-24 18:56:00 +000025#include <CoreFoundation/CoreFoundation.h>
caryclark@google.comab0ab4a2011-06-01 20:15:20 +000026#endif
27
vandebo@chromium.org6f72d1e2011-02-14 23:19:59 +000028namespace skia_advanced_typeface_metrics_utils {
29
vandebo@chromium.orgbeb7fe12011-11-11 19:38:54 +000030const int16_t kInvalidAdvance = SK_MinS16;
31const int16_t kDontCareAdvance = SK_MinS16 + 1;
32
vandebo@chromium.org6f72d1e2011-02-14 23:19:59 +000033template <typename Data>
reed@google.comb42403b2011-11-14 13:12:47 +000034void stripUninterestingTrailingAdvancesFromRange(
35 SkAdvancedTypefaceMetrics::AdvanceMetric<Data>* range) {
36 SkASSERT(false);
37}
38
39template <>
40void stripUninterestingTrailingAdvancesFromRange<int16_t>(
41 SkAdvancedTypefaceMetrics::AdvanceMetric<int16_t>* range) {
42 SkASSERT(range);
43
44 int expectedAdvanceCount = range->fEndId - range->fStartId + 1;
45 if (range->fAdvance.count() < expectedAdvanceCount) {
46 return;
47 }
48
49 for (int i = expectedAdvanceCount - 1; i >= 0; --i) {
50 if (range->fAdvance[i] != kDontCareAdvance &&
51 range->fAdvance[i] != kInvalidAdvance &&
52 range->fAdvance[i] != 0) {
53 range->fEndId = range->fStartId + i;
54 break;
55 }
56 }
57}
58
59template <typename Data>
vandebo@chromium.org6f72d1e2011-02-14 23:19:59 +000060void resetRange(SkAdvancedTypefaceMetrics::AdvanceMetric<Data>* range,
61 int startId) {
62 range->fStartId = startId;
63 range->fAdvance.setCount(0);
64}
65
66template <typename Data>
67SkAdvancedTypefaceMetrics::AdvanceMetric<Data>* appendRange(
68 SkTScopedPtr<SkAdvancedTypefaceMetrics::AdvanceMetric<Data> >* nextSlot,
69 int startId) {
70 nextSlot->reset(new SkAdvancedTypefaceMetrics::AdvanceMetric<Data>);
71 resetRange(nextSlot->get(), startId);
72 return nextSlot->get();
73}
74
75template <typename Data>
reed@google.comb42403b2011-11-14 13:12:47 +000076void zeroWildcardsInRange(
77 SkAdvancedTypefaceMetrics::AdvanceMetric<Data>* range) {
78 SkASSERT(false);
79}
80
81template <>
82void zeroWildcardsInRange<int16_t>(
83 SkAdvancedTypefaceMetrics::AdvanceMetric<int16_t>* range) {
84 SkASSERT(range);
85 if (range->fType != SkAdvancedTypefaceMetrics::WidthRange::kRange) {
86 return;
87 }
88 SkASSERT(range->fAdvance.count() == range->fEndId - range->fStartId + 1);
89
90 // Zero out wildcards.
91 for (int i = 0; i < range->fAdvance.count(); ++i) {
92 if (range->fAdvance[i] == kDontCareAdvance) {
93 range->fAdvance[i] = 0;
94 }
95 }
96}
97
98template <typename Data>
vandebo@chromium.org6f72d1e2011-02-14 23:19:59 +000099void finishRange(
100 SkAdvancedTypefaceMetrics::AdvanceMetric<Data>* range,
101 int endId,
102 typename SkAdvancedTypefaceMetrics::AdvanceMetric<Data>::MetricType
103 type) {
104 range->fEndId = endId;
105 range->fType = type;
vandebo@chromium.orgbeb7fe12011-11-11 19:38:54 +0000106 stripUninterestingTrailingAdvancesFromRange(range);
vandebo@chromium.org6f72d1e2011-02-14 23:19:59 +0000107 int newLength;
108 if (type == SkAdvancedTypefaceMetrics::AdvanceMetric<Data>::kRange) {
vandebo@chromium.orgbeb7fe12011-11-11 19:38:54 +0000109 newLength = range->fEndId - range->fStartId + 1;
vandebo@chromium.org6f72d1e2011-02-14 23:19:59 +0000110 } else {
vandebo@chromium.orgbeb7fe12011-11-11 19:38:54 +0000111 if (range->fEndId == range->fStartId) {
112 range->fType =
113 SkAdvancedTypefaceMetrics::AdvanceMetric<Data>::kRange;
114 }
vandebo@chromium.org6f72d1e2011-02-14 23:19:59 +0000115 newLength = 1;
116 }
117 SkASSERT(range->fAdvance.count() >= newLength);
118 range->fAdvance.setCount(newLength);
vandebo@chromium.orgbeb7fe12011-11-11 19:38:54 +0000119 zeroWildcardsInRange(range);
120}
121
vandebo@chromium.org6f72d1e2011-02-14 23:19:59 +0000122template <typename Data, typename FontHandle>
123SkAdvancedTypefaceMetrics::AdvanceMetric<Data>* getAdvanceData(
124 FontHandle fontHandle,
125 int num_glyphs,
vandebo@chromium.org37ad8fb2011-08-18 02:38:50 +0000126 const uint32_t* subsetGlyphIDs,
127 uint32_t subsetGlyphIDsLength,
vandebo@chromium.org6f72d1e2011-02-14 23:19:59 +0000128 bool (*getAdvance)(FontHandle fontHandle, int gId, Data* data)) {
vandebo@chromium.orgbeb7fe12011-11-11 19:38:54 +0000129 // Assuming that on average, the ASCII representation of an advance plus
130 // a space is 8 characters and the ASCII representation of a glyph id is 3
131 // characters, then the following cut offs for using different range types
132 // apply:
133 // The cost of stopping and starting the range is 7 characers
134 // a. Removing 4 0's or don't care's is a win
135 // The cost of stopping and starting the range plus a run is 22
136 // characters
137 // b. Removing 3 repeating advances is a win
138 // c. Removing 2 repeating advances and 3 don't cares is a win
139 // When not currently in a range the cost of a run over a range is 16
140 // characaters, so:
141 // d. Removing a leading 0/don't cares is a win because it is omitted
142 // e. Removing 2 repeating advances is a win
vandebo@chromium.org6f72d1e2011-02-14 23:19:59 +0000143
144 SkTScopedPtr<SkAdvancedTypefaceMetrics::AdvanceMetric<Data> > result;
145 SkAdvancedTypefaceMetrics::AdvanceMetric<Data>* curRange;
vandebo@chromium.org34dae872011-05-10 23:25:03 +0000146 SkAdvancedTypefaceMetrics::AdvanceMetric<Data>* prevRange = NULL;
vandebo@chromium.orgbeb7fe12011-11-11 19:38:54 +0000147 Data lastAdvance = kInvalidAdvance;
148 int repeatedAdvances = 0;
149 int wildCardsInRun = 0;
150 int leadingWildCards = 0;
151 int trailingWildCards = 0;
vandebo@chromium.org37ad8fb2011-08-18 02:38:50 +0000152 uint32_t subsetIndex = 0;
vandebo@chromium.orgbeb7fe12011-11-11 19:38:54 +0000153
154 // Limit the loop count to glyph id ranges provided.
155 int firstIndex = 0;
156 int lastIndex = num_glyphs;
157 if (subsetGlyphIDs) {
158 firstIndex = static_cast<int>(subsetGlyphIDs[0]);
159 lastIndex =
160 static_cast<int>(subsetGlyphIDs[subsetGlyphIDsLength - 1]) + 1;
161 }
162 curRange = appendRange(&result, firstIndex);
163
164 for (int gId = firstIndex; gId <= lastIndex; gId++) {
165 Data advance = kInvalidAdvance;
166 if (gId < lastIndex) {
vandebo@chromium.org37ad8fb2011-08-18 02:38:50 +0000167 // Get glyph id only when subset is NULL, or the id is in subset.
168 if (!subsetGlyphIDs ||
169 (subsetIndex < subsetGlyphIDsLength &&
vandebo@chromium.orgbeb7fe12011-11-11 19:38:54 +0000170 static_cast<uint32_t>(gId) == subsetGlyphIDs[subsetIndex])) {
vandebo@chromium.org37ad8fb2011-08-18 02:38:50 +0000171 SkAssertResult(getAdvance(fontHandle, gId, &advance));
172 ++subsetIndex;
vandebo@chromium.orgbeb7fe12011-11-11 19:38:54 +0000173 } else {
174 advance = kDontCareAdvance;
vandebo@chromium.org37ad8fb2011-08-18 02:38:50 +0000175 }
vandebo@chromium.org34dae872011-05-10 23:25:03 +0000176 }
vandebo@chromium.org6f72d1e2011-02-14 23:19:59 +0000177 if (advance == lastAdvance) {
vandebo@chromium.orgbeb7fe12011-11-11 19:38:54 +0000178 repeatedAdvances++;
179 trailingWildCards = 0;
180 } else if (advance == kDontCareAdvance) {
181 wildCardsInRun++;
182 trailingWildCards++;
183 } else if (curRange->fAdvance.count() ==
184 repeatedAdvances + 1 + wildCardsInRun) { // All in run.
185 if (lastAdvance == 0) {
vandebo@chromium.org6f72d1e2011-02-14 23:19:59 +0000186 resetRange(curRange, gId);
vandebo@chromium.orgbeb7fe12011-11-11 19:38:54 +0000187 trailingWildCards = 0;
188 } else if (repeatedAdvances + 1 >= 2 || trailingWildCards >= 4) {
vandebo@chromium.org6f72d1e2011-02-14 23:19:59 +0000189 finishRange(curRange, gId - 1,
190 SkAdvancedTypefaceMetrics::WidthRange::kRun);
vandebo@chromium.org34dae872011-05-10 23:25:03 +0000191 prevRange = curRange;
vandebo@chromium.org6f72d1e2011-02-14 23:19:59 +0000192 curRange = appendRange(&curRange->fNext, gId);
vandebo@chromium.orgbeb7fe12011-11-11 19:38:54 +0000193 trailingWildCards = 0;
vandebo@chromium.org6f72d1e2011-02-14 23:19:59 +0000194 }
vandebo@chromium.orgbeb7fe12011-11-11 19:38:54 +0000195 repeatedAdvances = 0;
196 wildCardsInRun = trailingWildCards;
197 leadingWildCards = trailingWildCards;
198 trailingWildCards = 0;
vandebo@chromium.org6f72d1e2011-02-14 23:19:59 +0000199 } else {
vandebo@chromium.orgbeb7fe12011-11-11 19:38:54 +0000200 if (lastAdvance == 0 &&
201 repeatedAdvances + 1 + wildCardsInRun >= 4) {
202 finishRange(curRange,
203 gId - repeatedAdvances - wildCardsInRun - 2,
vandebo@chromium.org6f72d1e2011-02-14 23:19:59 +0000204 SkAdvancedTypefaceMetrics::WidthRange::kRange);
vandebo@chromium.org34dae872011-05-10 23:25:03 +0000205 prevRange = curRange;
vandebo@chromium.org6f72d1e2011-02-14 23:19:59 +0000206 curRange = appendRange(&curRange->fNext, gId);
vandebo@chromium.orgbeb7fe12011-11-11 19:38:54 +0000207 trailingWildCards = 0;
208 } else if (trailingWildCards >= 4 && repeatedAdvances + 1 < 2) {
209 finishRange(curRange,
210 gId - trailingWildCards - 1,
vandebo@chromium.org6f72d1e2011-02-14 23:19:59 +0000211 SkAdvancedTypefaceMetrics::WidthRange::kRange);
vandebo@chromium.orgbeb7fe12011-11-11 19:38:54 +0000212 prevRange = curRange;
213 curRange = appendRange(&curRange->fNext, gId);
214 trailingWildCards = 0;
215 } else if (lastAdvance != 0 &&
216 (repeatedAdvances + 1 >= 3 ||
217 (repeatedAdvances + 1 >= 2 && wildCardsInRun >= 3))) {
218 finishRange(curRange,
219 gId - repeatedAdvances - wildCardsInRun - 2,
220 SkAdvancedTypefaceMetrics::WidthRange::kRange);
221 curRange =
222 appendRange(&curRange->fNext,
223 gId - repeatedAdvances - wildCardsInRun - 1);
vandebo@chromium.org6f72d1e2011-02-14 23:19:59 +0000224 curRange->fAdvance.append(1, &lastAdvance);
225 finishRange(curRange, gId - 1,
226 SkAdvancedTypefaceMetrics::WidthRange::kRun);
vandebo@chromium.org34dae872011-05-10 23:25:03 +0000227 prevRange = curRange;
vandebo@chromium.org6f72d1e2011-02-14 23:19:59 +0000228 curRange = appendRange(&curRange->fNext, gId);
vandebo@chromium.orgbeb7fe12011-11-11 19:38:54 +0000229 trailingWildCards = 0;
vandebo@chromium.org6f72d1e2011-02-14 23:19:59 +0000230 }
vandebo@chromium.orgbeb7fe12011-11-11 19:38:54 +0000231 repeatedAdvances = 0;
232 wildCardsInRun = trailingWildCards;
233 leadingWildCards = trailingWildCards;
234 trailingWildCards = 0;
vandebo@chromium.org6f72d1e2011-02-14 23:19:59 +0000235 }
236 curRange->fAdvance.append(1, &advance);
vandebo@chromium.orgbeb7fe12011-11-11 19:38:54 +0000237 if (advance != kDontCareAdvance) {
238 lastAdvance = advance;
239 }
vandebo@chromium.org6f72d1e2011-02-14 23:19:59 +0000240 }
vandebo@chromium.orgbeb7fe12011-11-11 19:38:54 +0000241 if (curRange->fStartId == lastIndex) {
vandebo@chromium.org34dae872011-05-10 23:25:03 +0000242 SkASSERT(prevRange);
vandebo@chromium.orgbeb7fe12011-11-11 19:38:54 +0000243 SkASSERT(prevRange->fNext->fStartId == lastIndex);
vandebo@chromium.org34dae872011-05-10 23:25:03 +0000244 prevRange->fNext.reset();
245 } else {
vandebo@chromium.orgbeb7fe12011-11-11 19:38:54 +0000246 finishRange(curRange, lastIndex - 1,
vandebo@chromium.org34dae872011-05-10 23:25:03 +0000247 SkAdvancedTypefaceMetrics::WidthRange::kRange);
248 }
vandebo@chromium.org6f72d1e2011-02-14 23:19:59 +0000249 return result.release();
250}
251
252// Make AdvanceMetric template functions available for linking with typename
253// WidthRange and VerticalAdvanceRange.
reed@google.com369ca402011-02-15 16:21:24 +0000254#if defined(SK_BUILD_FOR_WIN)
vandebo@chromium.org6f72d1e2011-02-14 23:19:59 +0000255template SkAdvancedTypefaceMetrics::WidthRange* getAdvanceData(
256 HDC hdc,
257 int num_glyphs,
vandebo@chromium.org37ad8fb2011-08-18 02:38:50 +0000258 const uint32_t* subsetGlyphIDs,
259 uint32_t subsetGlyphIDsLength,
vandebo@chromium.org6f72d1e2011-02-14 23:19:59 +0000260 bool (*getAdvance)(HDC hdc, int gId, int16_t* data));
djsollen@google.comda957722011-11-16 17:00:46 +0000261#elif defined(SK_BUILD_FOR_UNIX) || defined(SK_BUILD_FOR_ANDROID)
vandebo@chromium.org6f72d1e2011-02-14 23:19:59 +0000262template SkAdvancedTypefaceMetrics::WidthRange* getAdvanceData(
263 FT_Face face,
264 int num_glyphs,
vandebo@chromium.org37ad8fb2011-08-18 02:38:50 +0000265 const uint32_t* subsetGlyphIDs,
266 uint32_t subsetGlyphIDsLength,
vandebo@chromium.org6f72d1e2011-02-14 23:19:59 +0000267 bool (*getAdvance)(FT_Face face, int gId, int16_t* data));
yangsu@google.comccb74ea2011-06-21 13:09:32 +0000268#elif defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_IOS)
caryclark@google.comab0ab4a2011-06-01 20:15:20 +0000269template SkAdvancedTypefaceMetrics::WidthRange* getAdvanceData(
270 CTFontRef ctFont,
271 int num_glyphs,
vandebo@chromium.org37ad8fb2011-08-18 02:38:50 +0000272 const uint32_t* subsetGlyphIDs,
273 uint32_t subsetGlyphIDsLength,
caryclark@google.comab0ab4a2011-06-01 20:15:20 +0000274 bool (*getAdvance)(CTFontRef ctFont, int gId, int16_t* data));
vandebo@chromium.org6f72d1e2011-02-14 23:19:59 +0000275#endif
276template void resetRange(
277 SkAdvancedTypefaceMetrics::WidthRange* range,
278 int startId);
279template SkAdvancedTypefaceMetrics::WidthRange* appendRange(
280 SkTScopedPtr<SkAdvancedTypefaceMetrics::WidthRange >* nextSlot,
281 int startId);
282template void finishRange<int16_t>(
283 SkAdvancedTypefaceMetrics::WidthRange* range,
284 int endId,
285 SkAdvancedTypefaceMetrics::WidthRange::MetricType type);
286
287template void resetRange(
288 SkAdvancedTypefaceMetrics::VerticalAdvanceRange* range,
289 int startId);
290template SkAdvancedTypefaceMetrics::VerticalAdvanceRange* appendRange(
291 SkTScopedPtr<SkAdvancedTypefaceMetrics::VerticalAdvanceRange >*
292 nextSlot,
293 int startId);
294template void finishRange<SkAdvancedTypefaceMetrics::VerticalMetric>(
295 SkAdvancedTypefaceMetrics::VerticalAdvanceRange* range,
296 int endId,
297 SkAdvancedTypefaceMetrics::VerticalAdvanceRange::MetricType type);
298
299} // namespace skia_advanced_typeface_metrics_utils