21 #include FT_FREETYPE_H
25 #include FT_TRUETYPE_TABLES_H
31 #include <unordered_map>
44 #if defined(ION_USE_ICU)
45 #include "third_party/icu/icu4c/source/common/unicode/udata.h"
46 #include "third_party/iculehb/src/src/LEFontInstance.h"
47 #include "third_party/iculx_hb/include/layout/ParagraphLayout.h"
58 typedef std::vector<math::Point2f> ControlPoints;
62 static bool IsSizeValid(
const Vector2f& target_size) {
63 const float width = target_size[0];
64 const float height = target_size[1];
65 return width >= 0.0f && height >= 0.0f && (width > 0.0f || height > 0.0f);
77 class FreeTypeManager {
84 static FreeTypeManager* GetManagerForAllocator(
88 typedef std::unordered_map<base::Allocator*,
89 std::unique_ptr<FreeTypeManager>>
103 auto it = map->find(allocator_to_use.Get());
104 if (it == map->end()) {
105 auto man =
new FreeTypeManager(allocator);
106 (*map)[allocator_to_use.Get()] = std::unique_ptr<FreeTypeManager>(man);
109 return it->second.get();
115 FT_Face InitFont(
const void* data,
size_t data_size,
116 bool simulate_library_failure);
119 bool LoadGlyph(FT_Face face, uint32 glyph_index);
122 void FreeFont(FT_Face face);
127 static void* Allocate(FT_Memory mem,
long size);
128 static void Free(FT_Memory mem,
void* ptr);
129 static void* Realloc(FT_Memory mem,
long cur_size,
long new_size,
136 FreeTypeManager* mgr =
static_cast<FreeTypeManager*
>(mem->user);
137 DCHECK(mgr->mutex_.IsLocked());
138 DCHECK(mgr->allocator_.Get());
139 return mgr->allocator_;
164 FreeTypeManager::~FreeTypeManager() {
169 FT_Face FreeTypeManager::InitFont(
const void* data,
size_t data_size,
170 bool simulate_library_failure) {
173 if (FT_Library lib = simulate_library_failure ? NULL :
ft_lib_) {
174 if (!FT_New_Memory_Face(lib, reinterpret_cast<const FT_Byte*>(data),
175 static_cast<FT_Long>(data_size), 0, &face)) {
178 LOG(
ERROR) <<
"Could not read the FreeType font data";
182 LOG(
ERROR) <<
"Could not initialize the FreeType library";
187 void FreeTypeManager::FreeFont(FT_Face face) {
194 bool FreeTypeManager::LoadGlyph(FT_Face face, uint32 glyph_index) {
196 const FT_Error result = FT_Load_Glyph(face, glyph_index, FT_LOAD_RENDER);
200 void* FreeTypeManager::Allocate(FT_Memory mem,
long size) {
201 return GetAllocator(mem)->AllocateMemory(size);
204 void FreeTypeManager::Free(FT_Memory mem,
void* ptr) {
205 GetAllocator(mem)->DeallocateMemory(ptr);
208 void* FreeTypeManager::Realloc(FT_Memory mem,
long cur_size,
209 long new_size,
void* ptr) {
211 void* new_ptr = allocator->AllocateMemory(new_size);
212 memcpy(new_ptr, ptr, cur_size);
213 allocator->DeallocateMemory(ptr);
226 static float ToPixels(FT_Pos v26_6) {
227 static const float kToPixels = 1.0f / 64.0f;
228 return kToPixels *
static_cast<float>(v26_6);
232 static const FreeTypeFont::GlyphMetrics GlyphToMetrics(
233 const FT_GlyphSlot& glyph) {
234 FreeTypeFont::GlyphMetrics metrics;
236 metrics.size.Set(ToPixels(glyph->metrics.width),
237 ToPixels(glyph->metrics.height));
238 metrics.bitmap_offset.Set(static_cast<float>(glyph->bitmap_left),
239 static_cast<float>(glyph->bitmap_top));
240 metrics.advance.Set(ToPixels(glyph->advance.x), ToPixels(glyph->advance.y));
245 static void GlyphToControlPoints(
const FT_GlyphSlot& glyph,
246 ControlPoints* control_points) {
248 if (glyph->format != FT_GLYPH_FORMAT_OUTLINE)
return;
249 const FT_Outline& outline = glyph->outline;
250 control_points->reserve(outline.n_points);
251 for (int16 i = 0; i < outline.n_points; ++i) {
252 control_points->push_back(math::Point2f(ToPixels(outline.points[i].x),
253 ToPixels(outline.points[i].y)));
258 static const Font::GlyphGrid GlyphToGrid(
const FT_GlyphSlot& glyph) {
259 const FT_Bitmap bitmap = glyph->bitmap;
260 const size_t width = bitmap.width;
261 const size_t height = bitmap.rows;
262 const size_t pitch = bitmap.pitch;
264 Font::GlyphGrid grid(width, height);
265 for (
size_t y = 0; y < height; ++y) {
266 for (
size_t x = 0; x <
width; ++x) {
268 x, y, static_cast<double>(bitmap.buffer[y * pitch + x]) / 255.0);
280 static uint32 GlyphIndexToGlyphId(
const GlyphIndex glyph) {
281 return static_cast<uint32
>(glyph & 0xFFFFFFFF);
285 static uint32 GlyphIndexToFaceId(
const GlyphIndex glyph) {
286 return static_cast<uint32
>(glyph >> 32);
290 static GlyphIndex BuildGlyphIndex(uint32 glyph, uint32 face) {
291 return static_cast<GlyphIndex>(glyph) | (static_cast<GlyphIndex>(face) << 32);
307 class FreeTypeFont::Helper
308 #if defined(ION_USE_ICU)
309 :
public icu::LEFontInstance
314 struct GlyphMetaData :
public Allocatable {
316 bool IsZeroSize()
const {
return metrics.IsZeroSize(); }
319 GlyphMetrics metrics;
321 ControlPoints control_points;
325 explicit Helper(FreeTypeFont* owning_font)
326 : glyph_metadata_map_(owning_font->GetAllocator()),
327 owning_font_(owning_font),
329 #if defined(ION_USE_ICU)
333 manager_(FreeTypeManager::GetManagerForAllocator(
allocator_)) {
335 ~Helper() { FreeFont(); }
340 bool Init(
const void* data,
size_t data_size,
bool simulate_library_failure);
346 bool LoadGlyph(
GlyphIndex glyph_index, GlyphMetaData* glyph_meta,
347 Font::GlyphGrid* glyph_grid)
const;
350 const FontMetrics GetFontMetrics()
const;
353 const math::Vector2f GetKerning(
CharIndex char_index0,
361 const GlyphMetaData& GetGlyphMetaData(
GlyphIndex glyph_index)
const;
369 void AddFallbackFace(
const std::weak_ptr<Helper>& fallback);
371 #if defined(ION_USE_ICU)
372 const void* getFontTable(LETag tableTag,
size_t&
length)
const override;
374 le_int32 getUnitsPerEM()
const override;
375 LEGlyphID mapCharToGlyph(LEUnicode32 ch)
const override;
376 void getGlyphAdvance(LEGlyphID glyph, LEPoint& advance)
const override;
377 le_bool getGlyphPoint(LEGlyphID glyph, le_int32 pointNumber,
378 LEPoint& point)
const override;
379 float getXPixelsPerEm()
const override;
380 float getYPixelsPerEm()
const override;
381 float getScaleFactorX()
const override;
382 float getScaleFactorY()
const override;
383 le_int32 getAscent()
const override;
384 le_int32 getDescent()
const override;
385 le_int32 getLeading()
const override;
387 const icu::LEFontInstance* GetFace(uint32 index)
const;
388 GlyphIndex GlyphIndexForICUFont(
const icu::LEFontInstance* icu_font,
389 int32 glyph_id)
const;
395 void SetFontSizeLocked()
const;
399 uint32 GetGlyphForChar(
CharIndex char_index)
const;
406 math::Vector2f* kern)
const;
410 const math::Vector2f GetKerningLocked(
CharIndex char_index0,
414 bool LoadGlyphLocked(
GlyphIndex glyph_index, GlyphMetaData* glyph_meta,
415 Font::GlyphGrid* glyph_grid)
const;
418 bool LoadGlyphLockedNoFallback(
GlyphIndex glyph_index,
419 GlyphMetaData* glyph_meta,
420 Font::GlyphGrid* glyph_grid)
const;
423 typedef base::AllocMap<GlyphIndex, GlyphMetaData> GlyphMetaDataMap;
429 mutable GlyphMetaDataMap glyph_metadata_map_;
431 FreeTypeFont* owning_font_;
433 #if defined(ION_USE_ICU)
434 mutable base::AllocMap<LETag, std::pair<base::DataContainerPtr, size_t>>
439 std::vector<std::weak_ptr<Helper>> fallback_helpers_;
440 FreeTypeManager* manager_;
441 mutable port::Mutex
mutex_;
444 bool FreeTypeFont::Helper::Init(
const void* data,
size_t data_size,
445 bool simulate_library_failure) {
448 ft_face_ = manager_->InitFont(data, data_size, simulate_library_failure);
450 LOG(
ERROR) <<
"Could not read the FreeType font data.";
455 bool FreeTypeFont::Helper::LoadGlyph(
GlyphIndex glyph_index,
456 GlyphMetaData* glyph_meta,
457 Font::GlyphGrid* glyph_grid)
const {
459 return LoadGlyphLocked(glyph_index, glyph_meta, glyph_grid);
462 bool FreeTypeFont::Helper::LoadGlyphLocked(
GlyphIndex glyph_index,
463 GlyphMetaData* glyph_meta,
464 Font::GlyphGrid* glyph_grid)
const {
465 uint32 face_id = GlyphIndexToFaceId(glyph_index);
467 return LoadGlyphLockedNoFallback(glyph_index, glyph_meta, glyph_grid);
469 if (
auto helper = fallback_helpers_[face_id - 1].lock()) {
471 return helper->LoadGlyphLockedNoFallback(glyph_index, glyph_meta,
479 bool FreeTypeFont::Helper::LoadGlyphLockedNoFallback(
480 GlyphIndex glyph_index, GlyphMetaData* glyph_meta,
481 Font::GlyphGrid* glyph_grid)
const {
488 if (!manager_->LoadGlyph(ft_face_, GlyphIndexToGlyphId(glyph_index))) {
494 glyph_meta->metrics = GlyphToMetrics(ft_face_->glyph);
495 GlyphToControlPoints(ft_face_->glyph, &glyph_meta->control_points);
498 *glyph_grid = GlyphToGrid(ft_face_->glyph);
503 void FreeTypeFont::Helper::SetFontSizeLocked()
const {
506 const size_t size_in_pixels = owning_font_->GetSizeInPixels();
507 if (FT_IS_SCALABLE(ft_face_)) {
508 FT_Set_Pixel_Sizes(ft_face_, static_cast<FT_UInt>(size_in_pixels),
509 static_cast<FT_UInt>(size_in_pixels));
511 DCHECK(ft_face_->num_fixed_sizes);
512 int closest_face = 0;
513 size_t closest_size = 0xFFFFFFFF;
514 for (
int i = 0; i < ft_face_->num_fixed_sizes; ++i) {
515 FT_Select_Size(ft_face_, i);
516 const size_t size_difference =
517 abs(static_cast<int>(ft_face_->size->metrics.y_ppem) -
518 static_cast<int>(size_in_pixels));
519 if (size_difference < closest_size) {
520 closest_size = size_difference;
524 FT_Select_Size(ft_face_, closest_face);
528 const Font::FontMetrics FreeTypeFont::Helper::GetFontMetrics()
const {
532 metrics.line_advance_height =
533 static_cast<float>(ft_face_->size->metrics.height / 64);
537 const math::Vector2f FreeTypeFont::Helper::GetKerning(
539 math::Vector2f retval = math::Vector2f::Zero();
540 if (GetKerningNoFallback(char_index0, char_index1, &retval)) {
544 for (
auto& fallback_helper : fallback_helpers_) {
545 auto fallback = fallback_helper.lock();
547 fallback->GetKerningNoFallback(char_index0, char_index1, &retval)) {
554 bool FreeTypeFont::Helper::GetKerningNoFallback(
CharIndex char_index0,
556 math::Vector2f* kern)
const {
557 const uint32 idx0 = GetGlyphForChar(char_index0);
558 const uint32 idx1 = GetGlyphForChar(char_index1);
560 if (idx0 != 0 && idx1 != 0) {
562 *kern = GetKerningLocked(char_index0, char_index1);
564 }
else if (idx0 != 0 || idx1 != 0) {
566 *kern = math::Vector2f::Zero();
572 const math::Vector2f FreeTypeFont::Helper::GetKerningLocked(
574 math::Vector2f kerning(0.f, 0.f);
575 FT_Vector ft_kerning;
576 if (ft_face_ && FT_HAS_KERNING(ft_face_) &&
577 !FT_Get_Kerning(ft_face_, static_cast<FT_UInt>(char_index0),
578 static_cast<FT_UInt>(char_index1), FT_KERNING_DEFAULT,
581 kerning.Set(ToPixels(ft_kerning.x), ToPixels(ft_kerning.y));
586 uint32 FreeTypeFont::Helper::GetGlyphForChar(
CharIndex char_index)
const {
588 return FT_Get_Char_Index(ft_face_, char_index);
591 GlyphIndex FreeTypeFont::Helper::GetDefaultGlyphForChar(
593 uint32 idx = GetGlyphForChar(char_index);
595 return BuildGlyphIndex(idx, 0);
597 for (uint32 i = 0; i < fallback_helpers_.size(); ++i) {
598 if (
auto helper = fallback_helpers_[i].lock()) {
599 idx = helper->GetGlyphForChar(char_index);
601 return BuildGlyphIndex(idx, i + 1);
607 return BuildGlyphIndex(GetGlyphForChar(static_cast<CharIndex>(0xfffd)), 0);
610 const FreeTypeFont::Helper::GlyphMetaData&
611 FreeTypeFont::Helper::GetGlyphMetaData(
GlyphIndex glyph_index)
const {
614 return base::InvalidReference<GlyphMetaData>();
616 const auto& it = glyph_metadata_map_.find(glyph_index);
617 if (it == glyph_metadata_map_.end()) {
618 GlyphMetaData glyph_meta;
619 if (LoadGlyphLocked(glyph_index, &glyph_meta, NULL)) {
620 return glyph_metadata_map_[glyph_index] = glyph_meta;
622 return base::InvalidReference<GlyphMetaData>();
627 void FreeTypeFont::Helper::FreeFont() {
630 manager_->FreeFont(ft_face_);
635 void FreeTypeFont::Helper::AddFallbackFace(
636 const std::weak_ptr<Helper>& fallback) {
637 auto locked_fallback = fallback.lock();
638 if (!locked_fallback || locked_fallback.get() ==
this) {
642 fallback_helpers_.push_back(fallback);
645 #if defined(ION_USE_ICU)
646 const void* FreeTypeFont::Helper::getFontTable(LETag tableTag,
648 auto it = font_tables_.find(tableTag);
649 if (it == font_tables_.end()) {
650 FT_ULong table_size = 0;
652 FT_Load_Sfnt_Table(ft_face_, tableTag, 0, NULL, &table_size);
654 if (!error && error != FT_Err_Table_Missing) {
656 base::DataContainer::CreateOverAllocated<FT_Byte>(table_size, NULL,
658 error = FT_Load_Sfnt_Table(ft_face_, tableTag, 0,
659 table->GetMutableData<FT_Byte>(), &table_size);
661 auto inserted = font_tables_.insert(
662 std::make_pair(tableTag, std::make_pair(table, table_size)));
667 if (it == font_tables_.end()) {
671 length = it->second.second;
672 return it->second.first->GetMutableData<uint8>();
675 le_int32 FreeTypeFont::Helper::getUnitsPerEM()
const {
676 return ft_face_->units_per_EM;
679 LEGlyphID FreeTypeFont::Helper::mapCharToGlyph(LEUnicode32 ch)
const {
680 return FT_Get_Char_Index(ft_face_, ch);
683 static void SetLEPointToZero(LEPoint* point) {
688 void FreeTypeFont::Helper::getGlyphAdvance(LEGlyphID glyph,
689 LEPoint& advance)
const {
690 const GlyphMetaData& data = GetGlyphMetaData(glyph);
692 const FreeTypeFont::GlyphMetrics& metrics = data.metrics;
693 advance.fX = metrics.advance[0];
694 advance.fY = metrics.advance[1];
697 le_bool FreeTypeFont::Helper::getGlyphPoint(LEGlyphID glyph,
698 le_int32 pointNumber,
699 LEPoint& point)
const {
700 const GlyphMetaData& data = GetGlyphMetaData(glyph);
702 SetLEPointToZero(&point);
705 const ControlPoints& control_points = data.control_points;
706 if (static_cast<size_t>(pointNumber) < control_points.size()) {
707 point.fX = control_points[pointNumber][0];
708 point.fY = control_points[pointNumber][1];
714 float FreeTypeFont::Helper::getXPixelsPerEm()
const {
715 return ft_face_->size->metrics.x_ppem;
718 float FreeTypeFont::Helper::getYPixelsPerEm()
const {
719 return ft_face_->size->metrics.y_ppem;
722 float FreeTypeFont::Helper::getScaleFactorX()
const {
724 static const float k16_16ToFloat = 1.0f / 65536.0f;
725 return static_cast<float>(ft_face_->size->metrics.x_scale) * k16_16ToFloat;
728 float FreeTypeFont::Helper::getScaleFactorY()
const {
730 static const float k16_16ToFloat = 1.0f / 65536.0f;
731 return static_cast<float>(ft_face_->size->metrics.y_scale) * k16_16ToFloat;
734 le_int32 FreeTypeFont::Helper::getAscent()
const {
735 return static_cast<le_int32
>(
736 FT_MulFix(ft_face_->ascender,
737 static_cast<FT_Int32>(ft_face_->size->metrics.y_scale)) /
741 le_int32 FreeTypeFont::Helper::getDescent()
const {
742 return -
static_cast<le_int32
>(
743 FT_MulFix(ft_face_->descender, ft_face_->size->metrics.y_scale) / 64);
746 le_int32 FreeTypeFont::Helper::getLeading()
const {
747 return static_cast<le_int32
>(
748 FT_MulFix(ft_face_->height,
749 static_cast<FT_Int32>(ft_face_->size->metrics.y_scale)) /
753 const icu::LEFontInstance* FreeTypeFont::Helper::GetFace(uint32 index)
const {
757 auto helper = fallback_helpers_[index - 1].lock();
764 GlyphIndex FreeTypeFont::Helper::GlyphIndexForICUFont(
765 const icu::LEFontInstance* icu_font, int32 glyph_id)
const {
766 for (uint32 i = 0, n = static_cast<uint32>(fallback_helpers_.size()); i <= n;
768 if (icu_font == GetFace(i)) {
769 return BuildGlyphIndex(glyph_id, i);
772 return BuildGlyphIndex(glyph_id, 0);
775 #endif // ION_USE_ICU
785 FreeTypeFont::FreeTypeFont(
const std::string&
name,
size_t size_in_pixels,
786 size_t sdf_padding,
const void* data,
788 :
Font(name, size_in_pixels, sdf_padding), helper_(new Helper(this)) {
790 if (helper_->Init(data, data_size,
false)) {
797 :
Font(name, size_in_pixels, sdf_padding), helper_(new Helper(this)) {
799 helper_->Init(NULL, 0U,
true);
806 return helper_->LoadGlyph(glyph_index, NULL, glyph_grid);
811 return helper_->GetKerning(char_index0, char_index1);
814 #if defined(ION_USE_ICU)
815 void FreeTypeFont::GetFontRunsForText(icu::UnicodeString chars,
816 iculx::FontRuns* runs)
const {
818 for (
int i = 1; i < chars.length(); ++i) {
820 if (this_face != current_face) {
821 runs->add(helper_->GetFace(current_face), i);
822 current_face = this_face;
825 runs->add(helper_->GetFace(current_face), chars.length());
829 GlyphIndex FreeTypeFont::GlyphIndexForICUFont(
830 const icu::LEFontInstance* icu_font, int32 glyph_id)
const {
831 return helper_->GlyphIndexForICUFont(icu_font, glyph_id);
833 #endif // ION_USE_ICU
836 return helper_->GetDefaultGlyphForChar(char_index);
854 #if defined(ION_USE_ICU)
857 bool use_icu =
false;
858 #endif // ION_USE_ICU
860 return LayOutText(*
this, use_icu, lines, transform_data);
864 helper_->AddFallbackFace(std::weak_ptr<Helper>(
865 reinterpret_cast<FreeTypeFont*>(fallback.
Get())->helper_));
871 return base::InvalidReference<FreeTypeFont::GlyphMetrics>();
873 const auto& meta = helper_->GetGlyphMetaData(glyph_index);
875 return base::InvalidReference<FreeTypeFont::GlyphMetrics>();
bool IsInvalidReference(const T &value)
IsInvalidReference() returns true if a passed const reference of type T has an address of InvalidRefe...
std::vector< std::string > Lines
Lines of text from a single string (usually split on ' ').
#define ION_DECLARE_SAFE_STATIC_POINTER(type, variable)
Declare a static non-array pointer and calls a default constructor.
const FreeTypeFontTransformData ComputeTransformData(const Font &font, const LayoutOptions &options, const TextSize &text_size)
Sets the scale and translation fields of the LayoutData instance with the scale and translation requi...
base::AllocatorPtr allocator_
The Allocator for the FreeTypeManager and all its Fonts.
GlyphIndex GetDefaultGlyphForChar(CharIndex char_index) const override
Font overrides.
void SetFontMetrics(const FontMetrics &metrics)
Sets FontMetrics. SetFontMetrics() should only ever be called once.
const Layout LayOutText(const FreeTypeFont &font, bool use_icu, const Lines &lines, const FreeTypeFontTransformData &transform_data)
Returns a Layout populated by glyphs representing lines of text.
void AddFallbackFont(const FontPtr &fallback) override
Causes this font to use the font fallback as a fallback if a requested glyph is not found...
FT_MemoryRec_ ft_mem_
Sets up FreeType to use an Ion Allocator to manage memory.
FT_Library ft_lib_
The shared FT_Library instance.
GenericLockGuard< port::Mutex > LockGuard
Convenient typedefs for ion::port::Mutex.
#define LOG(severity)
Logs the streamed message unconditionally with a severity of severity.
bool LoadGlyphGrid(GlyphIndex glyph_index, GlyphGrid *glyph_grid) const override
Override Font::LoadGlyphGrid to load glyphs on demand.
std::vector< std::string > ION_API SplitString(const std::string &str, const std::string &delimiters)
Splits a string into a vector of substrings, given a set of delimiter characters (expressed as a stri...
uint32 CharIndex
Typedef for a Unicode index of a character.
This struct defines parameters affecting layout of a single text string when passed to BuildLayout()...
SharedPtr< Allocator > AllocatorPtr
T * Get() const
Returns a raw pointer to the instance, which may be NULL.
A LockGuard locks a mutex when created, and unlocks it when destroyed.
const math::Vector2f GetKerning(CharIndex char_index0, CharIndex char_index1) const
Returns the delta that should be made to relative positioning of characters beyond the metrics above...
~FreeTypeFont() override
The destructor is private because all base::Referent classes must have protected or private destructo...
const TextSize ComputeTextSize(const FreeTypeFont &font, const LayoutOptions &options, const Lines &lines)
Computes the size of text and returns it as a TextSize instance.
Copyright 2016 Google Inc.
math::Vector2f target_size
Target width and height of the text rectangle. (Default: 0 in x, 1 in y)
A Layout instance specifies how glyphs are arranged to form text.
#define DCHECK_EQ(val1, val2)
FreeTypeFont(const std::string &name, size_t size_in_pixels, size_t sdf_padding, const void *data, size_t data_size)
Constructs an instance using the given name.
const Layout BuildLayout(const std::string &text, const LayoutOptions &options) const override
Creates a layout as specified by options for a given single- or multi- line string text...
TextSize contains information about the size of multi-line text.
base::ReferentPtr< DataContainer >::Type DataContainerPtr
port::Mutex mutex_
Protects shared access to the Allocator and FT_Library.
kLongTerm is used for objects that have persistent lifetimes, such as managers.
This struct represents the metrics for a single glyph.
A grid representing a rendered glyph, with each grid pixel representing pixel coverage in the range (...
A SharedPtr is a smart shared pointer to an instance of some class that implements reference counting...
This contains the values needed to transform glyph rectangles into the correct coordinates.
A Mutex is used to ensure that only one thread or process can access a block of code at one time...
static const AllocatorPtr & GetDefaultAllocatorForLifetime(AllocationLifetime lifetime)
const GlyphMetrics & GetGlyphMetrics(GlyphIndex glyph_index) const
Returns the GlyphMetrics for a glyph.
Font is a base class for implementation-specific representations of fonts.