summaryrefslogtreecommitdiffstats
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
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
-rw-r--r--include/minikin/FontCollection.h19
-rw-r--r--include/minikin/FontFamily.h12
-rw-r--r--include/minikin/Layout.h13
-rw-r--r--include/minikin/MinikinFont.h70
-rw-r--r--include/minikin/MinikinFontFreeType.h71
-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
-rw-r--r--sample/example.cpp15
11 files changed, 343 insertions, 90 deletions
diff --git a/include/minikin/FontCollection.h b/include/minikin/FontCollection.h
index 3aa2aca..a2a5391 100644
--- a/include/minikin/FontCollection.h
+++ b/include/minikin/FontCollection.h
@@ -19,12 +19,9 @@
#include <vector>
-#include <ft2build.h>
-#include FT_FREETYPE_H
-#include FT_TRUETYPE_TABLES_H
-
-#include "SparseBitSet.h"
-#include "FontFamily.h"
+#include <minikin/MinikinFont.h>
+#include <minikin/SparseBitSet.h>
+#include <minikin/FontFamily.h>
namespace android {
@@ -40,19 +37,19 @@ public:
// Do copy constructor, assignment, destructor so it can be used in vectors
Run() : font(NULL) { }
Run(const Run& other): font(other.font), start(other.start), end(other.end) {
- if (font) FT_Reference_Face(font);
+ if (font) font->Ref();
}
Run& operator=(const Run& other) {
- if (other.font) FT_Reference_Face(other.font);
- if (font) FT_Done_Face(font);
+ if (other.font) other.font->Ref();
+ if (font) font->Unref();
font = other.font;
start = other.start;
end = other.end;
return *this;
}
- ~Run() { if (font) FT_Done_Face(font); }
+ ~Run() { if (font) font->Unref(); }
- FT_Face font;
+ MinikinFont* font;
int start;
int end;
};
diff --git a/include/minikin/FontFamily.h b/include/minikin/FontFamily.h
index 01ea232..290220b 100644
--- a/include/minikin/FontFamily.h
+++ b/include/minikin/FontFamily.h
@@ -42,21 +42,21 @@ private:
class FontFamily {
public:
// Add font to family, extracting style information from the font
- bool addFont(FT_Face typeface);
+ bool addFont(MinikinFont* typeface);
- void addFont(FT_Face typeface, FontStyle style);
- FT_Face getClosestMatch(FontStyle style) const;
+ void addFont(MinikinFont* typeface, FontStyle style);
+ MinikinFont* getClosestMatch(FontStyle style) const;
// API's for enumerating the fonts in a family. These don't guarantee any particular order
size_t getNumFonts() const;
- FT_Face getFont(size_t index) const;
+ MinikinFont* getFont(size_t index) const;
FontStyle getStyle(size_t index) const;
private:
class Font {
public:
- Font(FT_Face typeface, FontStyle style) :
+ Font(MinikinFont* typeface, FontStyle style) :
typeface(typeface), style(style) { }
- FT_Face typeface;
+ MinikinFont* typeface;
FontStyle style;
};
std::vector<Font> mFonts;
diff --git a/include/minikin/Layout.h b/include/minikin/Layout.h
index 7a6c6cf..fd0ed75 100644
--- a/include/minikin/Layout.h
+++ b/include/minikin/Layout.h
@@ -17,15 +17,13 @@
#ifndef MINIKIN_LAYOUT_H
#define MINIKIN_LAYOUT_H
-#include <ft2build.h>
-#include FT_FREETYPE_H
-
#include <hb.h>
#include <vector>
#include <minikin/CssParse.h>
#include <minikin/FontCollection.h>
+#include <minikin/MinikinFontFreeType.h>
namespace android {
@@ -37,7 +35,7 @@ public:
Bitmap(int width, int height);
~Bitmap();
void writePnm(std::ofstream& o) const;
- void drawGlyph(const FT_Bitmap& bitmap, int x, int y);
+ void drawGlyph(const GlyphBitmap& bitmap, int x, int y);
private:
int width;
int height;
@@ -65,12 +63,14 @@ public:
void draw(Bitmap*, int x0, int y0) const;
void setProperties(const std::string css);
+ float getAdvance() const;
+
// This must be called before any invocations.
// TODO: probably have a factory instead
static void init();
private:
// Find a face in the mFaces vector, or create a new entry
- int findFace(FT_Face face);
+ int findFace(MinikinFont* face, MinikinPaint* paint);
CssProperties mProps; // TODO: want spans
std::vector<LayoutGlyph> mGlyphs;
@@ -80,8 +80,9 @@ private:
// But for the time being, it should be ok to have just one
// per layout.
const FontCollection *mCollection;
- std::vector<FT_Face> mFaces;
+ std::vector<MinikinFont *> mFaces;
std::vector<hb_font_t *> mHbFonts;
+ float mAdvance;
};
} // namespace android
diff --git a/include/minikin/MinikinFont.h b/include/minikin/MinikinFont.h
new file mode 100644
index 0000000..2c265c3
--- /dev/null
+++ b/include/minikin/MinikinFont.h
@@ -0,0 +1,70 @@
+/*
+ * 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.
+ */
+
+#ifndef MINIKIN_FONT_H
+#define MINIKIN_FONT_H
+
+// An abstraction for platform fonts, allowing Minikin to be used with
+// multiple actual implementations of fonts.
+
+namespace android {
+
+class MinikinFont;
+
+// Possibly move into own .h file?
+struct MinikinPaint {
+ MinikinFont *font;
+ float size;
+ // todo: skew, stretch, hinting
+};
+
+class MinikinFontFreeType;
+
+class MinikinFont {
+public:
+ void Ref() { mRefcount_++; }
+ void Unref() { if (--mRefcount_ == 0) { delete this; } }
+
+ //MinikinFont();
+ virtual ~MinikinFont() = 0;
+
+ virtual bool GetGlyph(uint32_t codepoint, uint32_t *glyph) const = 0;
+
+ virtual float GetHorizontalAdvance(uint32_t glyph_id,
+ const MinikinPaint &paint) const = 0;
+
+ // If buf is NULL, just update size
+ virtual bool GetTable(uint32_t tag, uint8_t *buf, size_t *size) = 0;
+
+ virtual int32_t GetUniqueId() const = 0;
+
+ static uint32_t MakeTag(char c1, char c2, char c3, char c4) {
+ return ((uint32_t)c1 << 24) | ((uint32_t)c2 << 16) |
+ ((uint32_t)c3 << 8) | (uint32_t)c4;
+ }
+
+ // This is used to implement a downcast without RTTI
+ virtual MinikinFontFreeType* GetFreeType() {
+ return NULL;
+ }
+
+private:
+ int mRefcount_;
+};
+
+} // namespace android
+
+#endif // MINIKIN_FONT_H
diff --git a/include/minikin/MinikinFontFreeType.h b/include/minikin/MinikinFontFreeType.h
new file mode 100644
index 0000000..7051831
--- /dev/null
+++ b/include/minikin/MinikinFontFreeType.h
@@ -0,0 +1,71 @@
+/*
+ * 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.
+ */
+
+#ifndef MINIKIN_FONT_FREETYPE_H
+#define MINIKIN_FONT_FREETYPE_H
+
+#include <ft2build.h>
+#include FT_FREETYPE_H
+#include FT_TRUETYPE_TABLES_H
+
+#include <minikin/MinikinFont.h>
+
+// An abstraction for platform fonts, allowing Minikin to be used with
+// multiple actual implementations of fonts.
+
+namespace android {
+
+struct GlyphBitmap {
+ uint8_t *buffer;
+ int width;
+ int height;
+ int left;
+ int top;
+};
+
+class MinikinFontFreeType : public MinikinFont {
+public:
+ explicit MinikinFontFreeType(FT_Face typeface);
+
+ ~MinikinFontFreeType();
+
+ bool GetGlyph(uint32_t codepoint, uint32_t *glyph) const;
+
+ float GetHorizontalAdvance(uint32_t glyph_id,
+ const MinikinPaint &paint) const;
+
+ // If buf is NULL, just update size
+ bool GetTable(uint32_t tag, uint8_t *buf, size_t *size);
+
+ int32_t GetUniqueId() const;
+
+ // Not a virtual method, as the protocol to access rendered
+ // glyph bitmaps is probably different depending on the
+ // backend.
+ bool Render(uint32_t glyph_id,
+ const MinikinPaint &paint, GlyphBitmap *result);
+
+ MinikinFontFreeType* GetFreeType();
+
+private:
+ FT_Face mTypeface;
+ int32_t mUniqueId;
+ static int32_t sIdCounter;
+};
+
+} // namespace android
+
+#endif // MINIKIN_FONT_FREETYPE_H
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
diff --git a/sample/example.cpp b/sample/example.cpp
index 3f0ad9d..9b012ef 100644
--- a/sample/example.cpp
+++ b/sample/example.cpp
@@ -24,6 +24,7 @@
#include <unicode/unistr.h>
#include <unicode/utf16.h>
+#include <minikin/MinikinFontFreeType.h>
#include <minikin/Layout.h>
using std::vector;
@@ -55,15 +56,17 @@ FontCollection *makeFontCollection() {
if (error != 0) {
printf("error loading %s, %d\n", fn, error);
}
- family->addFont(face);
+ MinikinFont *font = new MinikinFontFreeType(face);
+ family->addFont(font);
}
typefaces.push_back(family);
-#if 0
+#if 1
family = new FontFamily();
const char *fn = "/system/fonts/DroidSansDevanagari-Regular.ttf";
error = FT_New_Face(library, fn, 0, &face);
- family->addFont(face);
+ MinikinFont *font = new MinikinFontFreeType(face);
+ family->addFont(font);
typefaces.push_back(family);
#endif
@@ -81,11 +84,11 @@ int runMinikinTest() {
Layout layout;
layout.setFontCollection(collection);
layout.setProperties("font-size: 32;");
- const char *text = "hello world";
+ const char *text = "fine world \xe0\xa4\xa8\xe0\xa4\xae\xe0\xa4\xb8\xe0\xa5\x8d\xe0\xa4\xa4\xe0\xa5\x87";
icu::UnicodeString icuText = icu::UnicodeString::fromUTF8(text);
layout.doLayout(icuText.getBuffer(), icuText.length());
layout.dump();
- Bitmap bitmap(200, 50);
+ Bitmap bitmap(250, 50);
layout.draw(&bitmap, 10, 40);
std::ofstream o;
o.open("/data/local/tmp/foo.pgm", std::ios::out | std::ios::binary);
@@ -97,4 +100,4 @@ int runMinikinTest() {
int main(int argc, const char** argv) {
return android::runMinikinTest();
-} \ No newline at end of file
+}