diff options
-rw-r--r-- | gyp/core.gypi | 1 | ||||
-rw-r--r-- | include/core/SkFont.h | 151 | ||||
-rw-r--r-- | src/core/SkFont.cpp | 158 | ||||
-rw-r--r-- | tests/FontMgrTest.cpp | 39 |
4 files changed, 349 insertions, 0 deletions
diff --git a/gyp/core.gypi b/gyp/core.gypi index 9093368016..df026a4957 100644 --- a/gyp/core.gypi +++ b/gyp/core.gypi @@ -88,6 +88,7 @@ '<(skia_src_path)/core/SkFloat.cpp', '<(skia_src_path)/core/SkFloat.h', '<(skia_src_path)/core/SkFloatBits.cpp', + '<(skia_src_path)/core/SkFont.cpp', '<(skia_src_path)/core/SkFontHost.cpp', '<(skia_src_path)/core/SkFontDescriptor.cpp', '<(skia_src_path)/core/SkFontDescriptor.h', diff --git a/include/core/SkFont.h b/include/core/SkFont.h new file mode 100644 index 0000000000..45722285be --- /dev/null +++ b/include/core/SkFont.h @@ -0,0 +1,151 @@ +/* + * Copyright 2014 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "SkRefCnt.h" +#include "SkScalar.h" + +class SkPaint; +class SkTypeface; + +enum SkTextEncoding { + kUTF8_SkTextEncoding, + kUTF16_SkTextEncoding, + kUTF32_SkTextEncoding, + kGlyphID_SkTextEncoding, +}; + +/* + 1. The Hinting enum in SkPaint is gone entirely, absorbed into SkFont's flags. + + 2. SkPaint Flags look like this today + + enum Flags { + kAntiAlias_Flag = 0x01, //!< mask to enable antialiasing + kDither_Flag = 0x04, //!< mask to enable dithering + kUnderlineText_Flag = 0x08, //!< mask to enable underline text + kStrikeThruText_Flag = 0x10, //!< mask to enable strike-thru text + kFakeBoldText_Flag = 0x20, //!< mask to enable fake-bold text + kLinearText_Flag = 0x40, //!< mask to enable linear-text + kSubpixelText_Flag = 0x80, //!< mask to enable subpixel text positioning + kDevKernText_Flag = 0x100, //!< mask to enable device kerning text + kLCDRenderText_Flag = 0x200, //!< mask to enable subpixel glyph renderering + kEmbeddedBitmapText_Flag = 0x400, //!< mask to enable embedded bitmap strikes + kAutoHinting_Flag = 0x800, //!< mask to force Freetype's autohinter + kVerticalText_Flag = 0x1000, + kGenA8FromLCD_Flag = 0x2000, // hack for GDI -- do not use if you can help it + }; + + SkFont would absorb these: + + kFakeBoldText_Flag = 0x20, //!< mask to enable fake-bold text + kLinearText_Flag = 0x40, //!< mask to enable linear-text + kSubpixelText_Flag = 0x80, //!< mask to enable subpixel text positioning + kDevKernText_Flag = 0x100, //!< mask to enable device kerning text + kLCDRenderText_Flag = 0x200, //!< mask to enable subpixel glyph renderering + kEmbeddedBitmapText_Flag = 0x400, //!< mask to enable embedded bitmap strikes + kAutoHinting_Flag = 0x800, //!< mask to force Freetype's autohinter + kVerticalText_Flag = 0x1000, + kGenA8FromLCD_Flag = 0x2000, // hack for GDI -- do not use if you can help it + + leaving these still in paint + + kAntiAlias_Flag = 0x01, //!< mask to enable antialiasing + kDither_Flag = 0x04, //!< mask to enable dithering + kUnderlineText_Flag = 0x08, //!< mask to enable underline text + kStrikeThruText_Flag = 0x10, //!< mask to enable strike-thru text + + 3. Antialiasing + + SkFont has a mask-type: BW, AA, LCD + SkPaint has antialias boolean + + What to do if the font's mask-type disagrees with the paint? + + */ + +class SkFont : public SkRefCnt { +public: + enum Flags { + /** + * Use the system's automatic hinting mechanism to hint the typeface. + * If both bytecode and auto hints are specified, attempt to use the bytecodes first. + * If that fails (e.g. there are no codes), then attempt to autohint. + */ + kEnableAutoHints_Flag = 1 << 0, + + /** + * If the typeface contains explicit bytecodes for hinting, use them. + * If both bytecode and auto hints are specified, attempt to use the bytecodes first; + * if that fails (e.g. there are no codes), then attempt to autohint. + */ + kEnableByteCodeHints_Flag = 1 << 1, + + /** + * Use rounded metric values (e.g. advance). + * If either auto or bytecode hinting was used, apply those results to the metrics of the + * glyphs as well. If no hinting was applied, the metrics will just be rounded to the + * nearest integer. + * + * This applies to calls that return metrics (e.g. measureText) and to drawing the glyphs + * (see SkCanvas drawText and drawPosText). + */ + kUseNonlinearMetrics_Flag = 1 << 2, + + kVertical_Flag = 1 << 3, + kEmbeddedBitmaps_Flag = 1 << 4, + kGenA8FromLCD_Flag = 1 << 5, + kEmbolden_Flag = 1 << 6, + kDevKern_Flag = 1 << 7, // ifdef ANDROID ? + }; + + enum MaskType { + kBW_MaskType, + kA8_MaskType, + kLCD_MaskType, + }; + + static SkFont* Create(SkTypeface*, SkScalar size, MaskType, uint32_t flags); + static SkFont* Create(SkTypeface*, SkScalar size, SkScalar scaleX, SkScalar skewX, + MaskType, uint32_t flags); + + /** + * Return a font with the same attributes of this font, but with the specified size. + * If size is not supported (e.g. <= 0 or non-finite) NULL will be returned. + */ + SkFont* cloneWithSize(SkScalar size) const; + + SkTypeface* getTypeface() const { return fTypeface; } + SkScalar getSize() const { return fSize; } + SkScalar getScaleX() const { return fScaleX; } + SkScalar getSkewX() const { return fSkewX; } + uint32_t getFlags() const { return fFlags; } + MaskType getMaskType() const { return (MaskType)fMaskType; } + + int textToGlyphs(const void* text, size_t byteLength, SkTextEncoding, + uint16_t glyphs[], int maxGlyphCount) const; + + SkScalar measureText(const void* text, size_t byteLength, SkTextEncoding) const; + + static SkFont* Testing_CreateFromPaint(const SkPaint&); + +private: + enum { + kAllFlags = 0xFF, + }; + + SkFont(SkTypeface*, SkScalar size, SkScalar scaleX, SkScalar skewX, MaskType, uint32_t flags); + virtual ~SkFont(); + + SkTypeface* fTypeface; + SkScalar fSize; + SkScalar fScaleX; + SkScalar fSkewX; + uint16_t fFlags; + uint8_t fMaskType; + uint8_t fPad; +}; + diff --git a/src/core/SkFont.cpp b/src/core/SkFont.cpp new file mode 100644 index 0000000000..2c16186c11 --- /dev/null +++ b/src/core/SkFont.cpp @@ -0,0 +1,158 @@ +/* + * Copyright 2014 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "SkFont.h" +#include "SkTypeface.h" +#include "SkUtils.h" + +static SkTypeface* ref_or_default(SkTypeface* face) { + return face ? SkRef(face) : SkTypeface::RefDefault(); +} + +SkFont::SkFont(SkTypeface* face, SkScalar size, SkScalar scaleX, SkScalar skewX, MaskType mt, + uint32_t flags) + : fTypeface(ref_or_default(face)) + , fSize(size) + , fScaleX(scaleX) + , fSkewX(skewX) + , fFlags(flags) + , fMaskType(SkToU8(mt)) + , fPad(0) +{ + SkASSERT(size > 0); + SkASSERT(scaleX > 0); + SkASSERT(SkScalarIsFinite(skewX)); + SkASSERT(0 == (flags & ~kAllFlags)); +} + +SkFont* SkFont::Create(SkTypeface* face, SkScalar size, SkScalar scaleX, SkScalar skewX, + MaskType mt, uint32_t flags) { + if (size <= 0 || !SkScalarIsFinite(size)) { + return NULL; + } + if (scaleX <= 0 || !SkScalarIsFinite(scaleX)) { + return NULL; + } + if (!SkScalarIsFinite(skewX)) { + return NULL; + } + flags &= kAllFlags; + return SkNEW_ARGS(SkFont, (face, size, scaleX, skewX, mt, flags)); +} + +SkFont* SkFont::Create(SkTypeface* face, SkScalar size, MaskType mt, uint32_t flags) { + return SkFont::Create(face, size, 1, 0, mt, flags); +} + +SkFont* SkFont::cloneWithSize(SkScalar newSize) const { + return SkFont::Create(this->getTypeface(), newSize, this->getScaleX(), this->getSkewX(), + this->getMaskType(), this->getFlags()); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +SkFont::~SkFont() { + SkSafeUnref(fTypeface); +} + +int SkFont::textToGlyphs(const void* text, size_t byteLength, SkTextEncoding encoding, + uint16_t glyphs[], int maxGlyphCount) const { + if (0 == byteLength) { + return 0; + } + + SkASSERT(text); + + int count; + switch (encoding) { + case kUTF8_SkTextEncoding: + count = SkUTF8_CountUnichars((const char*)text, byteLength); + break; + case kUTF16_SkTextEncoding: + count = SkUTF16_CountUnichars((const uint16_t*)text, SkToInt(byteLength >> 1)); + break; + case kUTF32_SkTextEncoding: + count = SkToInt(byteLength >> 2); + break; + case kGlyphID_SkTextEncoding: + count = SkToInt(byteLength >> 1); + break; + } + if (NULL == glyphs) { + return count; + } + + if (kGlyphID_SkTextEncoding == encoding) { + memcpy(glyphs, text, count << 1); + return count; + } + + // TODO: unify/eliminate SkTypeface::Encoding with SkTextEncoding + SkTypeface::Encoding typeface_encoding; + switch (encoding) { + case kUTF8_SkTextEncoding: + typeface_encoding = SkTypeface::kUTF8_Encoding; + break; + case kUTF16_SkTextEncoding: + typeface_encoding = SkTypeface::kUTF16_Encoding; + break; + case kUTF32_SkTextEncoding: + typeface_encoding = SkTypeface::kUTF32_Encoding; + break; + case kGlyphID_SkTextEncoding: + SkASSERT(0); // can't get here + } + + (void)fTypeface->charsToGlyphs(text, typeface_encoding, glyphs, count); + return count; +} + +SkScalar SkFont::measureText(const void* text, size_t byteLength, SkTextEncoding encoding) const { + // TODO: need access to the cache + return -1; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +#include "SkPaint.h" + +SkFont* SkFont::Testing_CreateFromPaint(const SkPaint& paint) { + uint32_t flags = 0; + if (paint.isVerticalText()) { + flags |= kVertical_Flag; + } + if (paint.isEmbeddedBitmapText()) { + flags |= kEmbeddedBitmaps_Flag; + } + if (paint.getFlags() & SkPaint::kGenA8FromLCD_Flag) { + flags |= kGenA8FromLCD_Flag; + } + if (paint.isFakeBoldText()) { + flags |= kEmbolden_Flag; + } + + if (SkPaint::kFull_Hinting == paint.getHinting()) { + flags |= kEnableByteCodeHints_Flag; + } + if (paint.isAutohinted()) { + flags |= kEnableAutoHints_Flag; + } + if (paint.isSubpixelText() || paint.isLinearText()) { + // this is our default + } else { + flags |= kUseNonlinearMetrics_Flag; + } + + MaskType maskType = SkFont::kBW_MaskType; + if (paint.isAntiAlias()) { + maskType = paint.isLCDRenderText() ? kLCD_MaskType : kA8_MaskType; + } + + return Create(paint.getTypeface(), + paint.getTextSize(), paint.getTextScaleX(), paint.getTextSkewX(), + maskType, flags); +} diff --git a/tests/FontMgrTest.cpp b/tests/FontMgrTest.cpp index 6e59364684..69e2088c66 100644 --- a/tests/FontMgrTest.cpp +++ b/tests/FontMgrTest.cpp @@ -10,6 +10,44 @@ #include "SkTypeface.h" #include "Test.h" +#include "SkFont.h" +#include "SkPaint.h" +static void test_font(skiatest::Reporter* reporter) { + uint32_t flags = 0; + SkAutoTUnref<SkFont> font(SkFont::Create(NULL, 24, SkFont::kA8_MaskType, flags)); + + REPORTER_ASSERT(reporter, NULL != font->getTypeface()); + REPORTER_ASSERT(reporter, 24 == font->getSize()); + REPORTER_ASSERT(reporter, 1 == font->getScaleX()); + REPORTER_ASSERT(reporter, 0 == font->getSkewX()); + REPORTER_ASSERT(reporter, SkFont::kA8_MaskType == font->getMaskType()); + + uint16_t glyphs[5]; + sk_bzero(glyphs, sizeof(glyphs)); + + int count = font->textToGlyphs("Hello", 5, kUTF8_SkTextEncoding, glyphs, SK_ARRAY_COUNT(glyphs)); + + REPORTER_ASSERT(reporter, 5 == count); + for (int i = 0; i < count; ++i) { + REPORTER_ASSERT(reporter, 0 != glyphs[i]); + } + REPORTER_ASSERT(reporter, glyphs[0] != glyphs[1]); // 'h' != 'e' + REPORTER_ASSERT(reporter, glyphs[2] == glyphs[3]); // 'l' == 'l' + + SkAutoTUnref<SkFont> newFont(font->cloneWithSize(36)); + REPORTER_ASSERT(reporter, newFont.get()); + REPORTER_ASSERT(reporter, font->getTypeface() == newFont->getTypeface()); + REPORTER_ASSERT(reporter, 36 == newFont->getSize()); // double check we haven't changed + REPORTER_ASSERT(reporter, 24 == font->getSize()); // double check we haven't changed + + SkPaint paint; + paint.setTextSize(18); + font.reset(SkFont::Testing_CreateFromPaint(paint)); + REPORTER_ASSERT(reporter, font.get()); + REPORTER_ASSERT(reporter, font->getSize() == paint.getTextSize()); + REPORTER_ASSERT(reporter, SkFont::kBW_MaskType == font->getMaskType()); +} + /* * If the font backend is going to "alias" some font names to other fonts * (e.g. sans -> Arial) then we want to at least get the same typeface back @@ -78,4 +116,5 @@ DEFINE_bool(verboseFontMgr, false, "run verbose fontmgr tests."); DEF_TEST(FontMgr, reporter) { test_fontiter(reporter, FLAGS_verboseFontMgr); test_alias_names(reporter); + test_font(reporter); } |