SkTScopedPtr<SkAutoTArray<SkString> > fGlyphNames;
};
+namespace skia_advanced_typeface_metrics_utils {
+
+template <typename Data>
+void resetRange(SkAdvancedTypefaceMetrics::AdvanceMetric<Data>* range,
+ int startId);
+
+template <typename Data>
+SkAdvancedTypefaceMetrics::AdvanceMetric<Data>* appendRange(
+ SkTScopedPtr<SkAdvancedTypefaceMetrics::AdvanceMetric<Data> >* nextSlot,
+ int startId);
+
+template <typename Data>
+void finishRange(
+ SkAdvancedTypefaceMetrics::AdvanceMetric<Data>* range,
+ int endId,
+ typename SkAdvancedTypefaceMetrics::AdvanceMetric<Data>::MetricType
+ type);
+
+template <typename Data, typename FontHandle>
+SkAdvancedTypefaceMetrics::AdvanceMetric<Data>* getAdvanceData(
+ FontHandle fontHandle,
+ int num_glyphs,
+ bool (*getAdvance)(FontHandle fontHandle, int gId, Data* data));
+
+} // namespace skia_advanced_typeface_metrics_utils
+
#endif
--- /dev/null
+/*
+ * 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;
+ curRange = appendRange(&result, 0);
+ Data lastAdvance = SK_MinS16;
+ int repeats = 0;
+ for (int gId = 0; gId < num_glyphs; gId++) {
+ Data advance;
+ if (!getAdvance(fontHandle, gId, &advance)) {
+ num_glyphs = (gId > 0) ? gId - 1 : 0;
+ break;
+ }
+ 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);
+ curRange = appendRange(&curRange->fNext, gId);
+ }
+ repeats = 0;
+ } else {
+ if (lastAdvance == 0 && repeats >= 3) {
+ finishRange(curRange, gId - repeats - 2,
+ SkAdvancedTypefaceMetrics::WidthRange::kRange);
+ 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);
+ curRange = appendRange(&curRange->fNext, gId);
+ }
+ repeats = 0;
+ }
+ curRange->fAdvance.append(1, &advance);
+ lastAdvance = advance;
+ }
+ finishRange(curRange, num_glyphs - 1,
+ SkAdvancedTypefaceMetrics::WidthRange::kRange);
+ return result.release();
+}
+
+// Make AdvanceMetric template functions available for linking with typename
+// WidthRange and VerticalAdvanceRange.
+#ifdef SK_BUILD_FOR_WIN
+template SkAdvancedTypefaceMetrics::WidthRange* getAdvanceData(
+ HDC hdc,
+ int num_glyphs,
+ bool (*getAdvance)(HDC hdc, int gId, int16_t* data));
+#elif 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
SOURCE := \
Sk64.cpp \
+ SkAdvancedTypefaceMetrics.cpp \
SkAlphaRuns.cpp \
SkBitmap.cpp \
SkBitmapProcShader.cpp \
#define SkASSERT_CONTINUE(pred)
#endif
+using namespace skia_advanced_typeface_metrics_utils;
+
//////////////////////////////////////////////////////////////////////////
struct SkFaceRec;
return true;
}
-static int16_t getWidthAdvance(FT_Face face, int gId) {
+static bool getWidthAdvance(FT_Face face, int gId, int16_t* data) {
FT_Fixed advance = 0;
- SkAssertResult(getAdvances(face, gId, 1, FT_LOAD_NO_SCALE, &advance) == 0);
- return advance;
-}
-
-template <typename Data>
-static void resetRange(SkAdvancedTypefaceMetrics::AdvanceMetric<Data>* range,
- int startId) {
- range->fStartId = startId;
- range->fAdvance.setCount(0);
-}
-
-template <typename Data>
-static 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>
-static 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>
-static SkAdvancedTypefaceMetrics::AdvanceMetric<Data>* getAdvanceData(
- FT_Face face, Data (*getAdvance)(FT_Face face, int gId)) {
- // 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;
- curRange = appendRange(&result, 0);
- Data lastAdvance = SHRT_MIN;
- int repeats = 0;
- for (int gId = 0; gId < face->num_glyphs; gId++) {
- Data advance = getAdvance(face, gId);
- 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);
- curRange = appendRange(&curRange->fNext, gId);
- }
- repeats = 0;
- } else {
- if (lastAdvance == 0 && repeats >= 3) {
- finishRange(curRange, gId - repeats - 2,
- SkAdvancedTypefaceMetrics::WidthRange::kRange);
- 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);
- curRange = appendRange(&curRange->fNext, gId);
- }
- repeats = 0;
- }
- curRange->fAdvance.append(1, &advance);
- lastAdvance = advance;
+ if (getAdvances(face, gId, 1, FT_LOAD_NO_SCALE, &advance)) {
+ return false;
}
- finishRange(curRange, face->num_glyphs - 1,
- SkAdvancedTypefaceMetrics::WidthRange::kRange);
- return result.release();
+ SkASSERT(data);
+ *data = advance;
+ return true;
}
// static
// Figure out a good guess for StemV - Min width of i, I, !, 1.
// This probably isn't very good with an italic font.
int16_t min_width = SHRT_MAX;
+ info->fStemV = 0;
char stem_chars[] = {'i', 'I', '!', '1'};
for (size_t i = 0; i < SK_ARRAY_COUNT(stem_chars); i++) {
FT_BBox bbox;
info->fGlyphWidths->fAdvance.append(1, &advance);
finishRange(info->fGlyphWidths.get(), 0,
SkAdvancedTypefaceMetrics::WidthRange::kDefault);
- } else if(!cid) {
+ } else if (!cid) {
appendRange(&info->fGlyphWidths, 0);
// So as to not blow out the stack, get advances in batches.
for (int gID = 0; gID < face->num_glyphs; gID += 128) {
finishRange(info->fGlyphWidths.get(), face->num_glyphs - 1,
SkAdvancedTypefaceMetrics::WidthRange::kRange);
} else {
- info->fGlyphWidths.reset(getAdvanceData(face, &getWidthAdvance));
+ info->fGlyphWidths.reset(
+ getAdvanceData(face, face->num_glyphs, &getWidthAdvance));
}
if (info->fType == SkAdvancedTypefaceMetrics::kType1_Font) {
\r
#include "SkFontHost.h"\r
#include "SkDescriptor.h"\r
+#include "SkAdvancedTypefaceMetrics.h"\r
+#include "SkStream.h"\r
#include "SkThread.h"\r
\r
#ifdef WIN32\r
// client3d has to undefine this for now\r
#define CAN_USE_LOGFONT_NAME\r
\r
+using namespace skia_advanced_typeface_metrics_utils;\r
+\r
static SkMutex gFTMutex;\r
\r
static const uint16_t BUFFERSIZE = (16384 - 32);\r
return NULL;\r
}\r
\r
+static bool getWidthAdvance(HDC hdc, int gId, int16_t* advance) {\r
+ // Initialize the MAT2 structure to the identify transformation matrix.\r
+ static const MAT2 mat2 = {SkScalarToFIXED(1), SkScalarToFIXED(0),\r
+ SkScalarToFIXED(0), SkScalarToFIXED(1)};\r
+ int flags = GGO_METRICS | GGO_GLYPH_INDEX;\r
+ GLYPHMETRICS gm;\r
+ if (GDI_ERROR == GetGlyphOutline(hdc, gId, flags, &gm, 0, NULL, &mat2)) {\r
+ return false;\r
+ }\r
+ SkASSERT(advance);\r
+ *advance = gm.gmCellIncX;\r
+ return true;\r
+}\r
+\r
// static\r
SkAdvancedTypefaceMetrics* SkFontHost::GetAdvancedTypefaceMetrics(\r
uint32_t fontID, bool perGlyphInfo) {\r
- SkASSERT(!"SkFontHost::GetAdvancedTypefaceMetrics unimplemented");\r
- return NULL;\r
+ SkAutoMutexAcquire ac(gFTMutex);\r
+ LogFontTypeface* rec = LogFontTypeface::FindById(fontID);\r
+ LOGFONT lf = rec->logFont();\r
+ SkAdvancedTypefaceMetrics* info = NULL;\r
+\r
+ HDC hdc = CreateCompatibleDC(NULL);\r
+ HFONT font = CreateFontIndirect(&lf);\r
+ HFONT savefont = (HFONT)SelectObject(hdc, font);\r
+ HFONT designFont = NULL;\r
+\r
+ // To request design units, create a logical font whose height is specified\r
+ // as unitsPerEm.\r
+ OUTLINETEXTMETRIC otm;\r
+ if (!GetOutlineTextMetrics(hdc, sizeof(otm), &otm) ||\r
+ !GetTextFace(hdc, LF_FACESIZE, lf.lfFaceName)) {\r
+ goto Error;\r
+ }\r
+ lf.lfHeight = -SkToS32(otm.otmEMSquare);\r
+ designFont = CreateFontIndirect(&lf);\r
+ SelectObject(hdc, designFont);\r
+ if (!GetOutlineTextMetrics(hdc, sizeof(otm), &otm)) {\r
+ goto Error;\r
+ }\r
+\r
+ info = new SkAdvancedTypefaceMetrics;\r
+#ifdef UNICODE\r
+ // Get the buffer size needed first.\r
+ size_t str_len = WideCharToMultiByte(CP_UTF8, 0, lf.lfFaceName, -1, NULL,\r
+ 0, NULL, NULL);\r
+ // Allocate a buffer (str_len already has terminating null accounted for).\r
+ char *familyName = new char[str_len];\r
+ // Now actually convert the string.\r
+ WideCharToMultiByte(CP_UTF8, 0, lf.lfFaceName, -1, familyName, str_len,\r
+ NULL, NULL);\r
+ info->fFontName.set(familyName);\r
+ delete [] familyName;\r
+#else\r
+ info->fFontName.set(lf.lfFaceName);\r
+#endif\r
+\r
+ if (otm.otmTextMetrics.tmPitchAndFamily & TMPF_TRUETYPE) {\r
+ info->fType = SkAdvancedTypefaceMetrics::kTrueType_Font;\r
+ } else {\r
+ info->fType = SkAdvancedTypefaceMetrics::kOther_Font;\r
+ }\r
+ info->fEmSize = otm.otmEMSquare;\r
+ info->fMultiMaster = false;\r
+\r
+ info->fStyle = 0;\r
+ // If this bit is clear the font is a fixed pitch font.\r
+ if (!(otm.otmTextMetrics.tmPitchAndFamily & TMPF_FIXED_PITCH)) {\r
+ info->fStyle |= SkAdvancedTypefaceMetrics::kFixedPitch_Style;\r
+ }\r
+ if (otm.otmTextMetrics.tmItalic) {\r
+ info->fStyle |= SkAdvancedTypefaceMetrics::kItalic_Style;\r
+ }\r
+ // Setting symbolic style by default for now.\r
+ info->fStyle |= SkAdvancedTypefaceMetrics::kSymbolic_Style;\r
+ if (otm.otmTextMetrics.tmPitchAndFamily & FF_ROMAN) {\r
+ info->fStyle |= SkAdvancedTypefaceMetrics::kSerif_Style;\r
+ } else if (otm.otmTextMetrics.tmPitchAndFamily & FF_SCRIPT) {\r
+ info->fStyle |= SkAdvancedTypefaceMetrics::kScript_Style;\r
+ }\r
+\r
+ // The main italic angle of the font, in tenths of a degree counterclockwise\r
+ // from vertical.\r
+ info->fItalicAngle = otm.otmItalicAngle / 10;\r
+ info->fAscent = SkToS16(otm.otmTextMetrics.tmAscent);\r
+ info->fDescent = SkToS16(-otm.otmTextMetrics.tmDescent);\r
+ // TODO(ctguil): Use alternate cap height calculation.\r
+ // MSDN says otmsCapEmHeight is not support but it is returning a value on\r
+ // my Win7 box.\r
+ info->fCapHeight = otm.otmsCapEmHeight;\r
+ info->fBBox =\r
+ SkIRect::MakeLTRB(otm.otmrcFontBox.left, otm.otmrcFontBox.top,\r
+ otm.otmrcFontBox.right, otm.otmrcFontBox.bottom);\r
+\r
+ // Figure out a good guess for StemV - Min width of i, I, !, 1.\r
+ // This probably isn't very good with an italic font.\r
+ int16_t min_width = SHRT_MAX;\r
+ info->fStemV = 0;\r
+ char stem_chars[] = {'i', 'I', '!', '1'};\r
+ for (size_t i = 0; i < SK_ARRAY_COUNT(stem_chars); i++) {\r
+ ABC abcWidths;\r
+ if (GetCharABCWidths(hdc, stem_chars[i], stem_chars[i], &abcWidths)) {\r
+ int16_t width = abcWidths.abcB;\r
+ if (width > 0 && width < min_width) {\r
+ min_width = width;\r
+ info->fStemV = min_width;\r
+ }\r
+ }\r
+ }\r
+\r
+ // If bit 1 is set, the font may not be embedded in a document.\r
+ // If bit 1 is clear, the font can be embedded.\r
+ // If bit 2 is set, the embedding is read-only.\r
+ if (otm.otmfsType & 0x1) {\r
+ info->fType = SkAdvancedTypefaceMetrics::kNotEmbeddable_Font;\r
+ } else if (perGlyphInfo) {\r
+ info->fGlyphWidths.reset(\r
+ getAdvanceData(hdc, SHRT_MAX, &getWidthAdvance));\r
+ }\r
+\r
+Error:\r
+ SelectObject(hdc, savefont);\r
+ DeleteObject(designFont);\r
+ DeleteObject(font);\r
+ DeleteDC(hdc);\r
+\r
+ return info;\r
}\r
\r
SkTypeface* SkFontHost::CreateTypefaceFromStream(SkStream* stream) {\r
}\r
\r
SkStream* SkFontHost::OpenStream(SkFontID uniqueID) {\r
- SkASSERT(!"SkFontHost::OpenStream unimplemented");\r
- return NULL;\r
+ SkAutoMutexAcquire ac(gFTMutex);\r
+ LogFontTypeface* rec = LogFontTypeface::FindById(uniqueID);\r
+\r
+ HDC hdc = ::CreateCompatibleDC(NULL);\r
+ HFONT font = CreateFontIndirect(&rec->logFont());\r
+ HFONT savefont = (HFONT)SelectObject(hdc, font);\r
+\r
+ size_t bufferSize = GetFontData(hdc, 0, 0, NULL, 0);\r
+ SkMemoryStream* stream = new SkMemoryStream(bufferSize);\r
+ if (!GetFontData(hdc, 0, 0, (void*)stream->getMemoryBase(), bufferSize)) {\r
+ delete stream;\r
+ stream = NULL;\r
+ }\r
+\r
+ SelectObject(hdc, savefont);\r
+ DeleteObject(font);\r
+ DeleteDC(hdc);\r
+\r
+ return stream;\r
}\r
\r
SkScalerContext* SkFontHost::CreateScalerContext(const SkDescriptor* desc) {\r
<ClCompile Include="..\..\samplecode\SampleVertices.cpp" />\r
<ClCompile Include="..\..\samplecode\SampleXfermodes.cpp" />\r
<ClCompile Include="..\..\src\core\Sk64.cpp" />\r
+ <ClCompile Include="..\..\src\core\SkAdvancedTypefaceMetrics.cpp" />\r
<ClCompile Include="..\..\src\core\SkAlphaRuns.cpp" />\r
<ClCompile Include="..\..\src\core\SkBitmap.cpp" />\r
<ClCompile Include="..\..\src\core\SkBitmapProcShader.cpp" />\r
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />\r
<ImportGroup Label="ExtensionTargets">\r
</ImportGroup>\r
-</Project>
\ No newline at end of file
+</Project>\r