xref: /aosp_15_r20/frameworks/minikin/tests/util/FreeTypeMinikinFontForTest.cpp (revision 834a2baab5fdfc28e9a428ee87c7ea8f6a06a53d)
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 #include "FreeTypeMinikinFontForTest.h"
18 
19 #include <fcntl.h>
20 #include <sys/mman.h>
21 #include <sys/stat.h>
22 #include <sys/types.h>
23 #include <unistd.h>
24 #include <string>
25 
26 #include <ft2build.h>
27 #include <log/log.h>
28 #include FT_OUTLINE_H
29 
30 #include "minikin/MinikinExtent.h"
31 #include "minikin/MinikinFont.h"
32 #include "minikin/MinikinPaint.h"
33 #include "minikin/MinikinRect.h"
34 
35 namespace minikin {
36 namespace {
37 
38 constexpr FT_Int32 LOAD_FLAG =
39         FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
40 
FTPosToFloat(FT_Pos x)41 constexpr float FTPosToFloat(FT_Pos x) {
42     return x / 64.0;
43 }
44 
FTFloatToF26Dot6(float x)45 constexpr FT_F26Dot6 FTFloatToF26Dot6(float x) {
46     return static_cast<FT_F26Dot6>(x * 64);
47 }
48 
loadGlyphOrDie(uint32_t glyphId,float size,FT_Face face)49 void loadGlyphOrDie(uint32_t glyphId, float size, FT_Face face) {
50     const FT_F26Dot6 scale = FTFloatToF26Dot6(size);
51     LOG_ALWAYS_FATAL_IF(FT_Set_Char_Size(face, scale, scale, 72 /* dpi */, 72 /* dpi */),
52                         "Failed to set character size.");
53     LOG_ALWAYS_FATAL_IF(FT_Load_Glyph(face, glyphId, LOAD_FLAG), "Failed to load glyph");
54     LOG_ALWAYS_FATAL_IF(face->glyph->format != FT_GLYPH_FORMAT_OUTLINE,
55                         "Only outline font is supported.");
56 }
57 
58 }  // namespace
59 
FreeTypeMinikinFontForTest(const std::string & font_path,int index,const VariationSettings & axes)60 FreeTypeMinikinFontForTest::FreeTypeMinikinFontForTest(const std::string& font_path, int index,
61                                                        const VariationSettings& axes)
62         : mFontPath(font_path), mFontIndex(index), mAxes(axes) {
63     int fd = open(font_path.c_str(), O_RDONLY);
64     LOG_ALWAYS_FATAL_IF(fd == -1, "Open failed: %s", font_path.c_str());
65     struct stat st = {};
66     LOG_ALWAYS_FATAL_IF(fstat(fd, &st) != 0);
67     mFontSize = st.st_size;
68     mFontData = mmap(NULL, mFontSize, PROT_READ, MAP_SHARED, fd, 0);
69     LOG_ALWAYS_FATAL_IF(mFontData == nullptr);
70     close(fd);
71 
72     LOG_ALWAYS_FATAL_IF(FT_Init_FreeType(&mFtLibrary), "Failed to initialize FreeType");
73 
74     FT_Open_Args args;
75     args.flags = FT_OPEN_MEMORY;
76     args.memory_base = static_cast<const FT_Byte*>(mFontData);
77     args.memory_size = mFontSize;
78     LOG_ALWAYS_FATAL_IF(FT_Open_Face(mFtLibrary, &args, index, &mFtFace), "Failed to open FT_Face");
79 }
80 
~FreeTypeMinikinFontForTest()81 FreeTypeMinikinFontForTest::~FreeTypeMinikinFontForTest() {
82     FT_Done_Face(mFtFace);
83     FT_Done_FreeType(mFtLibrary);
84     munmap(mFontData, mFontSize);
85 }
86 
GetHorizontalAdvance(uint32_t glyphId,const MinikinPaint & paint,const FontFakery &) const87 float FreeTypeMinikinFontForTest::GetHorizontalAdvance(uint32_t glyphId, const MinikinPaint& paint,
88                                                        const FontFakery& /* fakery */) const {
89     loadGlyphOrDie(glyphId, paint.size, mFtFace);
90     return FTPosToFloat(mFtFace->glyph->advance.x);
91 }
92 
GetBounds(MinikinRect * bounds,uint32_t glyphId,const MinikinPaint & paint,const FontFakery &) const93 void FreeTypeMinikinFontForTest::GetBounds(MinikinRect* bounds, uint32_t glyphId,
94                                            const MinikinPaint& paint,
95                                            const FontFakery& /* fakery */) const {
96     loadGlyphOrDie(glyphId, paint.size, mFtFace);
97 
98     FT_BBox bbox;
99     FT_Outline_Get_CBox(&mFtFace->glyph->outline, &bbox);
100 
101     bounds->mLeft = FTPosToFloat(bbox.xMin);
102     bounds->mTop = -FTPosToFloat(bbox.yMax);
103     bounds->mRight = FTPosToFloat(bbox.xMax);
104     bounds->mBottom = -FTPosToFloat(bbox.yMin);
105 }
106 
GetFontExtent(MinikinExtent * extent,const MinikinPaint & paint,const FontFakery &) const107 void FreeTypeMinikinFontForTest::GetFontExtent(MinikinExtent* extent, const MinikinPaint& paint,
108                                                const FontFakery& /* fakery */) const {
109     float upem = mFtFace->units_per_EM;
110     extent->ascent = -static_cast<float>(mFtFace->ascender) * paint.size / upem;
111     extent->descent = -static_cast<float>(mFtFace->descender) * paint.size / upem;
112 }
113 
FreeTypeMinikinFontForTestFactory()114 FreeTypeMinikinFontForTestFactory::FreeTypeMinikinFontForTestFactory() : MinikinFontFactory() {
115     MinikinFontFactory::setInstance(this);
116 }
117 
118 // static
init()119 void FreeTypeMinikinFontForTestFactory::init() {
120     static FreeTypeMinikinFontForTestFactory factory;
121 }
122 
write(BufferWriter * writer,const MinikinFont * typeface) const123 void FreeTypeMinikinFontForTestFactory::write(BufferWriter* writer,
124                                               const MinikinFont* typeface) const {
125     writer->writeString(typeface->GetFontPath());
126 }
127 
create(BufferReader reader) const128 std::shared_ptr<MinikinFont> FreeTypeMinikinFontForTestFactory::create(BufferReader reader) const {
129     std::string fontPath(reader.readString());
130     return std::make_shared<FreeTypeMinikinFontForTest>(fontPath);
131 }
132 
skip(BufferReader * reader) const133 void FreeTypeMinikinFontForTestFactory::skip(BufferReader* reader) const {
134     reader->skipString();  // fontPath
135 }
136 
createFontWithVariation(const VariationSettings & axes) const137 std::shared_ptr<MinikinFont> FreeTypeMinikinFontForTest::createFontWithVariation(
138         const VariationSettings& axes) const {
139     return std::make_shared<FreeTypeMinikinFontForTest>(mFontPath, mFontIndex, axes);
140 }
141 
142 }  // namespace minikin
143