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