/* * Copyright (C) 2011 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "SkAdvancedTypefaceMetrics.h" #include "SkTypes.h" #ifdef SK_BUILD_FOR_UNIX #include #include FT_FREETYPE_H #endif #ifdef SK_BUILD_FOR_MAC #import #endif #ifdef SK_BUILD_FOR_IOS #include #include #include #endif namespace skia_advanced_typeface_metrics_utils { template void resetRange(SkAdvancedTypefaceMetrics::AdvanceMetric* range, int startId) { range->fStartId = startId; range->fAdvance.setCount(0); } template SkAdvancedTypefaceMetrics::AdvanceMetric* appendRange( SkTScopedPtr >* nextSlot, int startId) { nextSlot->reset(new SkAdvancedTypefaceMetrics::AdvanceMetric); resetRange(nextSlot->get(), startId); return nextSlot->get(); } template void finishRange( SkAdvancedTypefaceMetrics::AdvanceMetric* range, int endId, typename SkAdvancedTypefaceMetrics::AdvanceMetric::MetricType type) { range->fEndId = endId; range->fType = type; int newLength; if (type == SkAdvancedTypefaceMetrics::AdvanceMetric::kRange) { newLength = endId - range->fStartId + 1; } else { newLength = 1; } SkASSERT(range->fAdvance.count() >= newLength); range->fAdvance.setCount(newLength); } template SkAdvancedTypefaceMetrics::AdvanceMetric* getAdvanceData( FontHandle fontHandle, int num_glyphs, bool (*getAdvance)(FontHandle fontHandle, int gId, Data* data)) { // Assuming that an ASCII representation of a width or a glyph id is, // on average, 3 characters long gives the following cut offs for // using different range types: // When currently in a range // - Removing 4 0's is a win // - Removing 5 repeats is a win // When not currently in a range // - Removing 1 0 is a win // - Removing 3 repeats is a win SkTScopedPtr > result; SkAdvancedTypefaceMetrics::AdvanceMetric* curRange; SkAdvancedTypefaceMetrics::AdvanceMetric* prevRange = NULL; curRange = appendRange(&result, 0); Data lastAdvance = SK_MinS16; int repeats = 0; for (int gId = 0; gId <= num_glyphs; gId++) { Data advance; if (gId < num_glyphs) { SkAssertResult(getAdvance(fontHandle, gId, &advance)); } else { advance = SK_MinS16; } if (advance == lastAdvance) { repeats++; } else if (curRange->fAdvance.count() == repeats + 1) { if (lastAdvance == 0 && repeats >= 0) { resetRange(curRange, gId); } else if (repeats >= 2) { finishRange(curRange, gId - 1, SkAdvancedTypefaceMetrics::WidthRange::kRun); prevRange = curRange; curRange = appendRange(&curRange->fNext, gId); } repeats = 0; } else { if (lastAdvance == 0 && repeats >= 3) { finishRange(curRange, gId - repeats - 2, SkAdvancedTypefaceMetrics::WidthRange::kRange); prevRange = curRange; curRange = appendRange(&curRange->fNext, gId); } else if (repeats >= 4) { finishRange(curRange, gId - repeats - 2, SkAdvancedTypefaceMetrics::WidthRange::kRange); curRange = appendRange(&curRange->fNext, gId - repeats - 1); curRange->fAdvance.append(1, &lastAdvance); finishRange(curRange, gId - 1, SkAdvancedTypefaceMetrics::WidthRange::kRun); prevRange = curRange; curRange = appendRange(&curRange->fNext, gId); } repeats = 0; } curRange->fAdvance.append(1, &advance); lastAdvance = advance; } if (curRange->fStartId == num_glyphs) { SkASSERT(prevRange); SkASSERT(prevRange->fNext->fStartId == num_glyphs); prevRange->fNext.reset(); } else { finishRange(curRange, num_glyphs - 1, SkAdvancedTypefaceMetrics::WidthRange::kRange); } return result.release(); } // Make AdvanceMetric template functions available for linking with typename // WidthRange and VerticalAdvanceRange. #if defined(SK_BUILD_FOR_WIN) template SkAdvancedTypefaceMetrics::WidthRange* getAdvanceData( HDC hdc, int num_glyphs, bool (*getAdvance)(HDC hdc, int gId, int16_t* data)); #elif defined(SK_BUILD_FOR_UNIX) template SkAdvancedTypefaceMetrics::WidthRange* getAdvanceData( FT_Face face, int num_glyphs, bool (*getAdvance)(FT_Face face, int gId, int16_t* data)); #elif defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_IOS) template SkAdvancedTypefaceMetrics::WidthRange* getAdvanceData( CTFontRef ctFont, int num_glyphs, bool (*getAdvance)(CTFontRef ctFont, int gId, int16_t* data)); #endif template void resetRange( SkAdvancedTypefaceMetrics::WidthRange* range, int startId); template SkAdvancedTypefaceMetrics::WidthRange* appendRange( SkTScopedPtr* nextSlot, int startId); template void finishRange( SkAdvancedTypefaceMetrics::WidthRange* range, int endId, SkAdvancedTypefaceMetrics::WidthRange::MetricType type); template void resetRange( SkAdvancedTypefaceMetrics::VerticalAdvanceRange* range, int startId); template SkAdvancedTypefaceMetrics::VerticalAdvanceRange* appendRange( SkTScopedPtr* nextSlot, int startId); template void finishRange( SkAdvancedTypefaceMetrics::VerticalAdvanceRange* range, int endId, SkAdvancedTypefaceMetrics::VerticalAdvanceRange::MetricType type); } // namespace skia_advanced_typeface_metrics_utils