aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar reed@google.com <reed@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2014-04-08 15:04:29 +0000
committerGravatar reed@google.com <reed@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2014-04-08 15:04:29 +0000
commit43c27586e8b02243c16649de1cd7d95dcea0a712 (patch)
tree33e2ac282ac7e0683dadca9a9c658fd4beb7da04
parent667240a2e8dbe24b805d466e5bd0307ab2898418 (diff)
WIP -- SkFont
BUG=skia: R=bungeman@google.com, fmalita@chromium.org Review URL: https://codereview.chromium.org/185293018 git-svn-id: http://skia.googlecode.com/svn/trunk@14090 2bbb7eff-a529-9590-31e7-b0007b416f81
-rw-r--r--gyp/core.gypi1
-rw-r--r--include/core/SkFont.h151
-rw-r--r--src/core/SkFont.cpp158
-rw-r--r--tests/FontMgrTest.cpp39
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);
}