1 /*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #define LOG_TAG "Minikin"
18
19 #include "FreeTypeMinikinFontForTest.h"
20
21 #include <fcntl.h>
22 #include <sys/mman.h>
23 #include <sys/stat.h>
24 #include <sys/types.h>
25 #include <unistd.h>
26 #include <string>
27
28 #include <ft2build.h>
29 #include <log/log.h>
30 #include FT_OUTLINE_H
31
32 #include "minikin/MinikinExtent.h"
33 #include "minikin/MinikinFont.h"
34 #include "minikin/MinikinPaint.h"
35 #include "minikin/MinikinRect.h"
36
37 namespace minikin {
38 namespace {
39
40 constexpr FT_Int32 LOAD_FLAG =
41 FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
42
FTPosToFloat(FT_Pos x)43 constexpr float FTPosToFloat(FT_Pos x) {
44 return x / 64.0;
45 }
46
FTFloatToF26Dot6(float x)47 constexpr FT_F26Dot6 FTFloatToF26Dot6(float x) {
48 return static_cast<FT_F26Dot6>(x * 64);
49 }
50
loadGlyphOrDie(uint32_t glyphId,float size,FT_Face face)51 void loadGlyphOrDie(uint32_t glyphId, float size, FT_Face face) {
52 const FT_F26Dot6 scale = FTFloatToF26Dot6(size);
53 LOG_ALWAYS_FATAL_IF(FT_Set_Char_Size(face, scale, scale, 72 /* dpi */, 72 /* dpi */),
54 "Failed to set character size.");
55 LOG_ALWAYS_FATAL_IF(FT_Load_Glyph(face, glyphId, LOAD_FLAG), "Failed to load glyph");
56 LOG_ALWAYS_FATAL_IF(face->glyph->format != FT_GLYPH_FORMAT_OUTLINE,
57 "Only outline font is supported.");
58 }
59
60 } // namespace
61
FreeTypeMinikinFontForTest(const std::string & font_path,int index)62 FreeTypeMinikinFontForTest::FreeTypeMinikinFontForTest(const std::string& font_path, int index)
63 : mFontPath(font_path), mFontIndex(index) {
64 int fd = open(font_path.c_str(), O_RDONLY);
65 LOG_ALWAYS_FATAL_IF(fd == -1, "Open failed: %s", font_path.c_str());
66 struct stat st = {};
67 LOG_ALWAYS_FATAL_IF(fstat(fd, &st) != 0);
68 mFontSize = st.st_size;
69 mFontData = mmap(NULL, mFontSize, PROT_READ, MAP_SHARED, fd, 0);
70 LOG_ALWAYS_FATAL_IF(mFontData == nullptr);
71 close(fd);
72
73 LOG_ALWAYS_FATAL_IF(FT_Init_FreeType(&mFtLibrary), "Failed to initialize FreeType");
74
75 FT_Open_Args args;
76 args.flags = FT_OPEN_MEMORY;
77 args.memory_base = static_cast<const FT_Byte*>(mFontData);
78 args.memory_size = mFontSize;
79 LOG_ALWAYS_FATAL_IF(FT_Open_Face(mFtLibrary, &args, index, &mFtFace), "Failed to open FT_Face");
80 }
81
~FreeTypeMinikinFontForTest()82 FreeTypeMinikinFontForTest::~FreeTypeMinikinFontForTest() {
83 FT_Done_Face(mFtFace);
84 FT_Done_FreeType(mFtLibrary);
85 munmap(mFontData, mFontSize);
86 }
87
GetHorizontalAdvance(uint32_t glyphId,const MinikinPaint & paint,const FontFakery &) const88 float FreeTypeMinikinFontForTest::GetHorizontalAdvance(uint32_t glyphId, const MinikinPaint& paint,
89 const FontFakery& /* fakery */) const {
90 loadGlyphOrDie(glyphId, paint.size, mFtFace);
91 return FTPosToFloat(mFtFace->glyph->advance.x);
92 }
93
GetBounds(MinikinRect * bounds,uint32_t glyphId,const MinikinPaint & paint,const FontFakery &) const94 void FreeTypeMinikinFontForTest::GetBounds(MinikinRect* bounds, uint32_t glyphId,
95 const MinikinPaint& paint,
96 const FontFakery& /* fakery */) const {
97 loadGlyphOrDie(glyphId, paint.size, mFtFace);
98
99 FT_BBox bbox;
100 FT_Outline_Get_CBox(&mFtFace->glyph->outline, &bbox);
101
102 bounds->mLeft = FTPosToFloat(bbox.xMin);
103 bounds->mTop = FTPosToFloat(bbox.yMax);
104 bounds->mRight = FTPosToFloat(bbox.xMax);
105 bounds->mBottom = FTPosToFloat(bbox.yMin);
106 }
107
GetFontExtent(MinikinExtent * extent,const MinikinPaint & paint,const FontFakery &) const108 void FreeTypeMinikinFontForTest::GetFontExtent(MinikinExtent* extent, const MinikinPaint& paint,
109 const FontFakery& /* fakery */) const {
110 float upem = mFtFace->units_per_EM;
111 extent->ascent = -static_cast<float>(mFtFace->ascender) * paint.size / upem;
112 extent->descent = -static_cast<float>(mFtFace->descender) * paint.size / upem;
113 }
114
writeFreeTypeMinikinFontForTest(BufferWriter * writer,const MinikinFont * typeface)115 void writeFreeTypeMinikinFontForTest(BufferWriter* writer, const MinikinFont* typeface) {
116 writer->writeString(typeface->GetFontPath());
117 }
118
loadFreeTypeMinikinFontForTest(BufferReader reader)119 std::shared_ptr<MinikinFont> loadFreeTypeMinikinFontForTest(BufferReader reader) {
120 std::string fontPath(reader.readString());
121 return std::make_shared<FreeTypeMinikinFontForTest>(fontPath);
122 }
123
readFreeTypeMinikinFontForTest(BufferReader * reader)124 Font::TypefaceLoader* readFreeTypeMinikinFontForTest(BufferReader* reader) {
125 reader->skipString(); // fontPath
126 return &loadFreeTypeMinikinFontForTest;
127 }
128
129 } // namespace minikin
130