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
This commit is contained in:
Raph Levien
2013-05-22 16:14:27 -07:00
parent c1a6032ce6
commit 8d9541c5fb
11 changed files with 343 additions and 90 deletions

View File

@@ -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;
};

View File

@@ -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;

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -24,6 +24,7 @@ LOCAL_SRC_FILES := \
FontCollection.cpp \
FontFamily.cpp \
Layout.cpp \
MinikinFontFreeType.cpp \
SparseBitSet.cpp
LOCAL_MODULE := libminikin

View File

@@ -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;

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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

View File

@@ -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();
}
}