summaryrefslogtreecommitdiffstats
path: root/libs
diff options
context:
space:
mode:
authorRaph Levien <raph@google.com>2013-05-22 16:14:27 -0700
committerRaph Levien <raph@google.com>2013-06-14 11:22:35 -0700
commitbcc3dc5a2591a95a57e379e27cbad69c18e91e67 (patch)
tree6ba40e86f2ef0d52b2e0796f1dda0eb6e5ec4377 /libs
parent9cc9bbe1461f359f0b27c5e7645c17dda001ab1d (diff)
downloadandroid_frameworks_minikin-bcc3dc5a2591a95a57e379e27cbad69c18e91e67.tar.gz
android_frameworks_minikin-bcc3dc5a2591a95a57e379e27cbad69c18e91e67.tar.bz2
android_frameworks_minikin-bcc3dc5a2591a95a57e379e27cbad69c18e91e67.zip
Introduce MinikinFont abstraction
This commit removes the direct dependency on FreeType and replaces it with a MinikinFont abstraction, which is designed to support both FreeType and Skia fonts (and possibly others in the future). Also adds a "total advance" to the Layout, with an API for retrieving it. Change-Id: If20f92db9a43fd15b0fe9794b761ba00fb21338c
Diffstat (limited to 'libs')
-rw-r--r--libs/minikin/Android.mk1
-rw-r--r--libs/minikin/FontCollection.cpp13
-rw-r--r--libs/minikin/FontFamily.cpp24
-rw-r--r--libs/minikin/Layout.cpp100
-rw-r--r--libs/minikin/MinikinFontFreeType.cpp95
5 files changed, 172 insertions, 61 deletions
diff --git a/libs/minikin/Android.mk b/libs/minikin/Android.mk
index 9795ad0..723ad1f 100644
--- a/libs/minikin/Android.mk
+++ b/libs/minikin/Android.mk
@@ -24,6 +24,7 @@ LOCAL_SRC_FILES := \
FontCollection.cpp \
FontFamily.cpp \
Layout.cpp \
+ MinikinFontFreeType.cpp \
SparseBitSet.cpp
LOCAL_MODULE := libminikin
diff --git a/libs/minikin/FontCollection.cpp b/libs/minikin/FontCollection.cpp
index 7abbd3b..702bd20 100644
--- a/libs/minikin/FontCollection.cpp
+++ b/libs/minikin/FontCollection.cpp
@@ -45,16 +45,15 @@ FontCollection::FontCollection(const vector<FontFamily*>& typefaces) :
FontInstance* instance = &mInstances.back();
instance->mFamily = family;
instance->mCoverage = new SparseBitSet;
- FT_Face typeface = family->getClosestMatch(defaultStyle);
+ MinikinFont* typeface = family->getClosestMatch(defaultStyle);
#ifdef VERBOSE_DEBUG
printf("closest match = %x, family size = %d\n", typeface, family->getNumFonts());
#endif
- const uint32_t cmapTag = FT_MAKE_TAG('c', 'm', 'a', 'p');
- FT_ULong cmapSize = 0;
- FT_Error error = FT_Load_Sfnt_Table(typeface, cmapTag, 0, NULL, &cmapSize);
+ const uint32_t cmapTag = MinikinFont::MakeTag('c', 'm', 'a', 'p');
+ size_t cmapSize = 0;
+ bool ok = typeface->GetTable(cmapTag, NULL, &cmapSize);
UniquePtr<uint8_t[]> cmapData(new uint8_t[cmapSize]);
- error = FT_Load_Sfnt_Table(typeface, cmapTag, 0,
- cmapData.get(), &cmapSize);
+ ok = typeface->GetTable(cmapTag, cmapData.get(), &cmapSize);
CmapCoverage::getCoverage(*instance->mCoverage, cmapData.get(), cmapSize);
#ifdef VERBOSE_DEBUG
printf("font coverage length=%d, first ch=%x\n", instance->mCoverage->length(),
@@ -138,7 +137,7 @@ void FontCollection::itemize(const uint16_t *string, size_t string_size, FontSty
run->font = NULL; // maybe we should do something different here
} else {
run->font = family->getClosestMatch(style);
- FT_Reference_Face(run->font);
+ run->font->Ref();
}
lastFamily = family;
run->start = i;
diff --git a/libs/minikin/FontFamily.cpp b/libs/minikin/FontFamily.cpp
index dc6e16c..0bc38a7 100644
--- a/libs/minikin/FontFamily.cpp
+++ b/libs/minikin/FontFamily.cpp
@@ -20,9 +20,7 @@
#include <stdlib.h>
#include <stdint.h>
#include <utils/UniquePtr.h>
-#include <ft2build.h>
-#include FT_FREETYPE_H
-#include FT_TRUETYPE_TABLES_H
+#include <minikin/MinikinFont.h>
#include <minikin/AnalyzeStyle.h>
#include <minikin/FontFamily.h>
@@ -30,14 +28,14 @@ using std::vector;
namespace android {
-bool FontFamily::addFont(FT_Face typeface) {
- const uint32_t os2Tag = FT_MAKE_TAG('O', 'S', '/', '2');
- FT_ULong os2Size = 0;
- FT_Error error = FT_Load_Sfnt_Table(typeface, os2Tag, 0, NULL, &os2Size);
- if (error != 0) return false;
+bool FontFamily::addFont(MinikinFont* typeface) {
+ const uint32_t os2Tag = MinikinFont::MakeTag('O', 'S', '/', '2');
+ size_t os2Size = 0;
+ bool ok = typeface->GetTable(os2Tag, NULL, &os2Size);
+ if (!ok) return false;
UniquePtr<uint8_t[]> os2Data(new uint8_t[os2Size]);
- error = FT_Load_Sfnt_Table(typeface, os2Tag, 0, os2Data.get(), &os2Size);
- if (error != 0) return false;
+ ok = typeface->GetTable(os2Tag, os2Data.get(), &os2Size);
+ if (!ok) return false;
int weight;
bool italic;
if (analyzeStyle(os2Data.get(), os2Size, &weight, &italic)) {
@@ -51,7 +49,7 @@ bool FontFamily::addFont(FT_Face typeface) {
return false;
}
-void FontFamily::addFont(FT_Face typeface, FontStyle style) {
+void FontFamily::addFont(MinikinFont* typeface, FontStyle style) {
mFonts.push_back(Font(typeface, style));
ALOGD("added font, mFonts.size() = %d", mFonts.size());
}
@@ -66,7 +64,7 @@ int computeMatch(FontStyle style1, FontStyle style2) {
return score;
}
-FT_Face FontFamily::getClosestMatch(FontStyle style) const {
+MinikinFont* FontFamily::getClosestMatch(FontStyle style) const {
const Font* bestFont = NULL;
int bestMatch = 0;
for (size_t i = 0; i < mFonts.size(); i++) {
@@ -84,7 +82,7 @@ size_t FontFamily::getNumFonts() const {
return mFonts.size();
}
-FT_Face FontFamily::getFont(size_t index) const {
+MinikinFont* FontFamily::getFont(size_t index) const {
return mFonts[index].typeface;
}
diff --git a/libs/minikin/Layout.cpp b/libs/minikin/Layout.cpp
index a8a596d..d4e09c5 100644
--- a/libs/minikin/Layout.cpp
+++ b/libs/minikin/Layout.cpp
@@ -18,7 +18,9 @@
#include <vector>
#include <fstream>
#include <iostream> // for debugging
+#include <stdio.h> // ditto
+#include <minikin/MinikinFontFreeType.h>
#include <minikin/Layout.h>
using std::string;
@@ -45,9 +47,11 @@ void Bitmap::writePnm(std::ofstream &o) const {
o.close();
}
-void Bitmap::drawGlyph(const FT_Bitmap& bitmap, int x, int y) {
+void Bitmap::drawGlyph(const GlyphBitmap& bitmap, int x, int y) {
int bmw = bitmap.width;
- int bmh = bitmap.rows;
+ int bmh = bitmap.height;
+ x += bitmap.left;
+ y -= bitmap.top;
int x0 = std::max(0, x);
int x1 = std::min(width, x + bmw);
int y0 = std::max(0, y);
@@ -74,19 +78,20 @@ void Layout::setFontCollection(const FontCollection *collection) {
}
hb_blob_t* referenceTable(hb_face_t* face, hb_tag_t tag, void* userData) {
- FT_Face ftFace = reinterpret_cast<FT_Face>(userData);
- FT_ULong length = 0;
- FT_Error error = FT_Load_Sfnt_Table(ftFace, tag, 0, NULL, &length);
- if (error) {
+ MinikinFont* font = reinterpret_cast<MinikinFont *>(userData);
+ size_t length = 0;
+ bool ok = font->GetTable(tag, NULL, &length);
+ if (!ok) {
return 0;
}
char *buffer = reinterpret_cast<char*>(malloc(length));
if (!buffer) {
return 0;
}
- error = FT_Load_Sfnt_Table(ftFace, tag, 0,
- reinterpret_cast<FT_Byte*>(buffer), &length);
- if (error) {
+ ok = font->GetTable(tag, reinterpret_cast<uint8_t*>(buffer), &length);
+ printf("referenceTable %c%c%c%c length=%d %d\n",
+ (tag >>24) & 0xff, (tag>>16)&0xff, (tag>>8)&0xff, tag&0xff, length, ok);
+ if (!ok) {
free(buffer);
return 0;
}
@@ -96,23 +101,22 @@ hb_blob_t* referenceTable(hb_face_t* face, hb_tag_t tag, void* userData) {
static hb_bool_t harfbuzzGetGlyph(hb_font_t* hbFont, void* fontData, hb_codepoint_t unicode, hb_codepoint_t variationSelector, hb_codepoint_t* glyph, void* userData)
{
- FT_Face ftFace = reinterpret_cast<FT_Face>(fontData);
- FT_UInt glyph_index = FT_Get_Char_Index(ftFace, unicode);
- *glyph = glyph_index;
- return !!*glyph;
-}
-
-static hb_position_t ft_pos_to_hb(FT_Pos pos) {
- return pos << 2;
+ MinikinPaint* paint = reinterpret_cast<MinikinPaint *>(fontData);
+ MinikinFont* font = paint->font;
+ uint32_t glyph_id;
+ bool ok = font->GetGlyph(unicode, &glyph_id);
+ if (ok) {
+ *glyph = glyph_id;
+ }
+ return ok;
}
static hb_position_t harfbuzzGetGlyphHorizontalAdvance(hb_font_t* hbFont, void* fontData, hb_codepoint_t glyph, void* userData)
{
- FT_Face ftFace = reinterpret_cast<FT_Face>(fontData);
- hb_position_t advance = 0;
-
- FT_Load_Glyph(ftFace, glyph, FT_LOAD_DEFAULT);
- return ft_pos_to_hb(ftFace->glyph->advance.x);
+ MinikinPaint* paint = reinterpret_cast<MinikinPaint *>(fontData);
+ MinikinFont* font = paint->font;
+ float advance = font->GetHorizontalAdvance(glyph, *paint);
+ return 256 * advance + 0.5;
}
static hb_bool_t harfbuzzGetGlyphHorizontalOrigin(hb_font_t* hbFont, void* fontData, hb_codepoint_t glyph, hb_position_t* x, hb_position_t* y, void* userData)
@@ -135,10 +139,10 @@ hb_font_funcs_t* getHbFontFuncs() {
return hbFontFuncs;
}
-hb_font_t* create_hb_font(FT_Face ftFace) {
- hb_face_t* face = hb_face_create_for_tables(referenceTable, ftFace, NULL);
+hb_font_t* create_hb_font(MinikinFont* minikinFont, MinikinPaint* minikinPaint) {
+ hb_face_t* face = hb_face_create_for_tables(referenceTable, minikinFont, NULL);
hb_font_t* font = hb_font_create(face);
- hb_font_set_funcs(font, getHbFontFuncs(), ftFace, 0);
+ hb_font_set_funcs(font, getHbFontFuncs(), minikinPaint, 0);
// TODO: manage ownership of face
return font;
}
@@ -164,19 +168,15 @@ void Layout::dump() const {
// 1. Deal with multiple sizes in a layout
// 2. We'll probably store FT_Face as primary and then use a cache
// for the hb fonts
-int Layout::findFace(FT_Face face) {
+int Layout::findFace(MinikinFont* face, MinikinPaint* paint) {
unsigned int ix;
for (ix = 0; ix < mFaces.size(); ix++) {
if (mFaces[ix] == face) {
return ix;
}
}
- double size = mProps.value(fontSize).getFloatValue();
- FT_Error error = FT_Set_Pixel_Sizes(face, 0, size);
mFaces.push_back(face);
- hb_font_t *font = create_hb_font(face);
- hb_font_set_ppem(font, size, size);
- hb_font_set_scale(font, HBFloatToFixed(size), HBFloatToFixed(size));
+ hb_font_t *font = create_hb_font(face, paint);
mHbFonts.push_back(font);
return ix;
}
@@ -190,7 +190,6 @@ static FontStyle styleFromCss(const CssProperties &props) {
if (props.hasTag(fontStyle)) {
italic = props.value(fontStyle).getIntValue() != 0;
}
- // TODO: italic property from CSS
return FontStyle(weight, italic);
}
@@ -202,6 +201,10 @@ void Layout::doLayout(const uint16_t* buf, size_t nchars) {
FontStyle style = styleFromCss(mProps);
mCollection->itemize(buf, nchars, style, &items);
+ MinikinPaint paint;
+ double size = mProps.value(fontSize).getFloatValue();
+ paint.size = size;
+
mGlyphs.clear();
mFaces.clear();
mHbFonts.clear();
@@ -209,12 +212,15 @@ void Layout::doLayout(const uint16_t* buf, size_t nchars) {
float y = 0;
for (size_t run_ix = 0; run_ix < items.size(); run_ix++) {
FontCollection::Run &run = items[run_ix];
- int font_ix = findFace(run.font);
+ int font_ix = findFace(run.font, &paint);
+ paint.font = mFaces[font_ix];
hb_font_t *hbFont = mHbFonts[font_ix];
#ifdef VERBOSE
std::cout << "Run " << run_ix << ", font " << font_ix <<
" [" << run.start << ":" << run.end << "]" << std::endl;
#endif
+ hb_font_set_ppem(hbFont, size, size);
+ hb_font_set_scale(hbFont, HBFloatToFixed(size), HBFloatToFixed(size));
hb_buffer_reset(buffer);
hb_buffer_set_direction(buffer, HB_DIRECTION_LTR);
@@ -236,24 +242,32 @@ void Layout::doLayout(const uint16_t* buf, size_t nchars) {
x += HBFixedToFloat(positions[i].x_advance);
}
}
+ mAdvance = x;
}
void Layout::draw(Bitmap* surface, int x0, int y0) const {
- FT_Error error;
- FT_Int32 load_flags = FT_LOAD_DEFAULT;
+ /*
+ TODO: redo as MinikinPaint settings
if (mProps.hasTag(minikinHinting)) {
int hintflags = mProps.value(minikinHinting).getIntValue();
if (hintflags & 1) load_flags |= FT_LOAD_NO_HINTING;
if (hintflags & 2) load_flags |= FT_LOAD_NO_AUTOHINT;
}
+ */
for (size_t i = 0; i < mGlyphs.size(); i++) {
const LayoutGlyph& glyph = mGlyphs[i];
- FT_Face face = mFaces[glyph.font_ix];
- error = FT_Load_Glyph(face, glyph.glyph_id, load_flags);
- error = FT_Render_Glyph(face->glyph, FT_RENDER_MODE_NORMAL);
- surface->drawGlyph(face->glyph->bitmap,
- x0 + int(floor(glyph.x + 0.5)) + face->glyph->bitmap_left,
- y0 + int(floor(glyph.y + 0.5)) - face->glyph->bitmap_top);
+ MinikinFont *mf = mFaces[glyph.font_ix];
+ MinikinFontFreeType *face = static_cast<MinikinFontFreeType *>(mf);
+ GlyphBitmap glyphBitmap;
+ MinikinPaint paint;
+ paint.size = mProps.value(fontSize).getFloatValue();
+ bool ok = face->Render(glyph.glyph_id, paint, &glyphBitmap);
+ printf("glyphBitmap.width=%d, glyphBitmap.height=%d (%d, %d) x=%f, y=%f, ok=%d\n",
+ glyphBitmap.width, glyphBitmap.height, glyphBitmap.left, glyphBitmap.top, glyph.x, glyph.y, ok);
+ if (ok) {
+ surface->drawGlyph(glyphBitmap,
+ x0 + int(floor(glyph.x + 0.5)), y0 + int(floor(glyph.y + 0.5)));
+ }
}
}
@@ -261,4 +275,8 @@ void Layout::setProperties(string css) {
mProps.parse(css);
}
+float Layout::getAdvance() const {
+ return mAdvance;
+}
+
} // namespace android
diff --git a/libs/minikin/MinikinFontFreeType.cpp b/libs/minikin/MinikinFontFreeType.cpp
new file mode 100644
index 0000000..be61345
--- /dev/null
+++ b/libs/minikin/MinikinFontFreeType.cpp
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * 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.
+ */
+
+// Implementation of MinikinFont abstraction specialized for FreeType
+
+#include <stdint.h>
+
+#include <ft2build.h>
+#include FT_FREETYPE_H
+#include FT_TRUETYPE_TABLES_H
+#include FT_ADVANCES_H
+
+#include <minikin/MinikinFontFreeType.h>
+
+namespace android {
+
+int32_t MinikinFontFreeType::sIdCounter = 0;
+
+MinikinFontFreeType::MinikinFontFreeType(FT_Face typeface) :
+ mTypeface(typeface) {
+ mUniqueId = sIdCounter++;
+}
+
+MinikinFontFreeType::~MinikinFontFreeType() {
+ FT_Done_Face(mTypeface);
+}
+
+bool MinikinFontFreeType::GetGlyph(uint32_t codepoint, uint32_t *glyph) const {
+ FT_UInt glyph_index = FT_Get_Char_Index(mTypeface, codepoint);
+ *glyph = glyph_index;
+ return !!glyph_index;
+}
+
+float MinikinFontFreeType::GetHorizontalAdvance(uint32_t glyph_id,
+ const MinikinPaint &paint) const {
+ FT_Set_Pixel_Sizes(mTypeface, 0, paint.size);
+ FT_UInt32 flags = FT_LOAD_DEFAULT; // TODO: respect hinting settings
+ FT_Fixed advance;
+ FT_Error error = FT_Get_Advance(mTypeface, glyph_id, flags, &advance);
+ return advance * (1.0 / 65536);
+}
+
+bool MinikinFontFreeType::GetTable(uint32_t tag, uint8_t *buf, size_t *size) {
+ FT_ULong ftsize = *size;
+ FT_Error error = FT_Load_Sfnt_Table(mTypeface, tag, 0, buf, &ftsize);
+ if (error != 0) {
+ return false;
+ }
+ *size = ftsize;
+ return true;
+}
+
+int32_t MinikinFontFreeType::GetUniqueId() const {
+ return mUniqueId;
+}
+
+bool MinikinFontFreeType::Render(uint32_t glyph_id,
+ const MinikinPaint &paint, GlyphBitmap *result) {
+ FT_Error error;
+ FT_Int32 load_flags = FT_LOAD_DEFAULT; // TODO: respect hinting settings
+ error = FT_Load_Glyph(mTypeface, glyph_id, load_flags);
+ if (error != 0) {
+ return false;
+ }
+ error = FT_Render_Glyph(mTypeface->glyph, FT_RENDER_MODE_NORMAL);
+ if (error != 0) {
+ return false;
+ }
+ FT_Bitmap &bitmap = mTypeface->glyph->bitmap;
+ result->buffer = bitmap.buffer;
+ result->width = bitmap.width;
+ result->height = bitmap.rows;
+ result->left = mTypeface->glyph->bitmap_left;
+ result->top = mTypeface->glyph->bitmap_top;
+ return true;
+}
+
+MinikinFontFreeType* MinikinFontFreeType::GetFreeType() {
+ return this;
+}
+
+} // namespace android