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/MinikinFont.h"
33
34 namespace minikin {
35 namespace {
36
37 static int uniqueId = 0;
38
39 constexpr FT_Int32 LOAD_FLAG =
40 FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
41
FTPosToFloat(FT_Pos x)42 constexpr float FTPosToFloat(FT_Pos x) {
43 return x / 64.0;
44 }
45
FTFloatToF26Dot6(float x)46 constexpr FT_F26Dot6 FTFloatToF26Dot6(float x) {
47 return static_cast<FT_F26Dot6>(x * 64);
48 }
49
loadGlyphOrDie(uint32_t glyphId,float size,FT_Face face)50 void loadGlyphOrDie(uint32_t glyphId, float size, FT_Face face) {
51 const FT_F26Dot6 scale = FTFloatToF26Dot6(size);
52 LOG_ALWAYS_FATAL_IF(FT_Set_Char_Size(face, scale, scale, 72 /* dpi */, 72 /* dpi */),
53 "Failed to set character size.");
54 LOG_ALWAYS_FATAL_IF(FT_Load_Glyph(face, glyphId, LOAD_FLAG), "Failed to load glyph");
55 LOG_ALWAYS_FATAL_IF(face->glyph->format != FT_GLYPH_FORMAT_OUTLINE,
56 "Only outline font is supported.");
57 }
58
59 } // namespace
60
FreeTypeMinikinFontForTest(const std::string & font_path,int index)61 FreeTypeMinikinFontForTest::FreeTypeMinikinFontForTest(const std::string& font_path, int index)
62 : MinikinFont(uniqueId++), mFontPath(font_path), mFontIndex(index) {
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 &,const FontFakery &) const107 void FreeTypeMinikinFontForTest::GetFontExtent(MinikinExtent* extent,
108 const MinikinPaint& /* paint */,
109 const FontFakery& /* fakery */) const {
110 // TODO: Retrieve font metrics from FreeType.
111 extent->ascent = -10.0f;
112 extent->descent = 20.0f;
113 extent->line_gap = 0.0f;
114 }
115
116 } // namespace minikin
117