blob: 7e8a03087b2cbf5042015a87e9cf29b006a39d08 [file] [log] [blame]
/*
* 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 <ft2build.h>
#include FT_FREETYPE_H
#endif
namespace skia_advanced_typeface_metrics_utils {
template <typename Data>
void resetRange(SkAdvancedTypefaceMetrics::AdvanceMetric<Data>* range,
int startId) {
range->fStartId = startId;
range->fAdvance.setCount(0);
}
template <typename Data>
SkAdvancedTypefaceMetrics::AdvanceMetric<Data>* appendRange(
SkTScopedPtr<SkAdvancedTypefaceMetrics::AdvanceMetric<Data> >* nextSlot,
int startId) {
nextSlot->reset(new SkAdvancedTypefaceMetrics::AdvanceMetric<Data>);
resetRange(nextSlot->get(), startId);
return nextSlot->get();
}
template <typename Data>
void finishRange(
SkAdvancedTypefaceMetrics::AdvanceMetric<Data>* range,
int endId,
typename SkAdvancedTypefaceMetrics::AdvanceMetric<Data>::MetricType
type) {
range->fEndId = endId;
range->fType = type;
int newLength;
if (type == SkAdvancedTypefaceMetrics::AdvanceMetric<Data>::kRange) {
newLength = endId - range->fStartId + 1;
} else {
newLength = 1;
}
SkASSERT(range->fAdvance.count() >= newLength);
range->fAdvance.setCount(newLength);
}
template <typename Data, typename FontHandle>
SkAdvancedTypefaceMetrics::AdvanceMetric<Data>* 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<SkAdvancedTypefaceMetrics::AdvanceMetric<Data> > result;
SkAdvancedTypefaceMetrics::AdvanceMetric<Data>* curRange;
SkAdvancedTypefaceMetrics::AdvanceMetric<Data>* 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));
#endif
template void resetRange(
SkAdvancedTypefaceMetrics::WidthRange* range,
int startId);
template SkAdvancedTypefaceMetrics::WidthRange* appendRange(
SkTScopedPtr<SkAdvancedTypefaceMetrics::WidthRange >* nextSlot,
int startId);
template void finishRange<int16_t>(
SkAdvancedTypefaceMetrics::WidthRange* range,
int endId,
SkAdvancedTypefaceMetrics::WidthRange::MetricType type);
template void resetRange(
SkAdvancedTypefaceMetrics::VerticalAdvanceRange* range,
int startId);
template SkAdvancedTypefaceMetrics::VerticalAdvanceRange* appendRange(
SkTScopedPtr<SkAdvancedTypefaceMetrics::VerticalAdvanceRange >*
nextSlot,
int startId);
template void finishRange<SkAdvancedTypefaceMetrics::VerticalMetric>(
SkAdvancedTypefaceMetrics::VerticalAdvanceRange* range,
int endId,
SkAdvancedTypefaceMetrics::VerticalAdvanceRange::MetricType type);
} // namespace skia_advanced_typeface_metrics_utils