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 34namespace minikin { 35namespace { 36 37static int uniqueId = 0; 38 39constexpr FT_Int32 LOAD_FLAG = 40 FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH; 41 42constexpr float FTPosToFloat(FT_Pos x) { 43 return x / 64.0; 44} 45 46constexpr FT_F26Dot6 FTFloatToF26Dot6(float x) { 47 return static_cast<FT_F26Dot6>(x * 64); 48} 49 50void 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 61FreeTypeMinikinFontForTest::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 81FreeTypeMinikinFontForTest::~FreeTypeMinikinFontForTest() { 82 FT_Done_Face(mFtFace); 83 FT_Done_FreeType(mFtLibrary); 84 munmap(mFontData, mFontSize); 85} 86 87float 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 93void 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 107void 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