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:
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
70
engine/src/flutter/include/minikin/MinikinFont.h
Normal file
70
engine/src/flutter/include/minikin/MinikinFont.h
Normal 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
|
||||
71
engine/src/flutter/include/minikin/MinikinFontFreeType.h
Normal file
71
engine/src/flutter/include/minikin/MinikinFontFreeType.h
Normal 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
|
||||
@@ -24,6 +24,7 @@ LOCAL_SRC_FILES := \
|
||||
FontCollection.cpp \
|
||||
FontFamily.cpp \
|
||||
Layout.cpp \
|
||||
MinikinFontFreeType.cpp \
|
||||
SparseBitSet.cpp
|
||||
|
||||
LOCAL_MODULE := libminikin
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
95
engine/src/flutter/libs/minikin/MinikinFontFreeType.cpp
Normal file
95
engine/src/flutter/libs/minikin/MinikinFontFreeType.cpp
Normal 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
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user