| // Copyright 2017 Google Inc. All Rights Reserved. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| #include "cobalt/renderer/rasterizer/skia/skia/src/ports/SkFreeType_cobalt.h" |
| |
| #include <ft2build.h> |
| #include FT_FREETYPE_H |
| #include FT_TRUETYPE_TABLES_H |
| #include FT_TYPE1_TABLES_H |
| |
| #include "SkFontStyle.h" |
| #include "SkTSearch.h" |
| #include "base/debug/trace_event.h" |
| #include "base/logging.h" |
| |
| namespace { |
| |
| // This logic is taken from SkTypeface_FreeType::ScanFont() and should be kept |
| // in sync with it. |
| SkTypeface::Style GenerateSkTypefaceStyleFromFace(FT_Face face) { |
| int weight = SkFontStyle::kNormal_Weight; |
| if (face->style_flags & FT_STYLE_FLAG_BOLD) { |
| weight = SkFontStyle::kBold_Weight; |
| } |
| |
| PS_FontInfoRec psFontInfo; |
| TT_OS2* os2 = static_cast<TT_OS2*>(FT_Get_Sfnt_Table(face, ft_sfnt_os2)); |
| if (os2 && os2->version != 0xffff) { |
| weight = os2->usWeightClass; |
| } else if (0 == FT_Get_PS_Font_Info(face, &psFontInfo) && psFontInfo.weight) { |
| static const struct { |
| char const* const name; |
| int const weight; |
| } commonWeights[] = { |
| // There are probably more common names, but these are known to exist. |
| {"all", SkFontStyle::kNormal_Weight}, // Multiple Masters usually |
| // default to normal. |
| {"black", SkFontStyle::kBlack_Weight}, |
| {"bold", SkFontStyle::kBold_Weight}, |
| {"book", |
| (SkFontStyle::kNormal_Weight + SkFontStyle::kLight_Weight) / 2}, |
| {"demi", SkFontStyle::kSemiBold_Weight}, |
| {"demibold", SkFontStyle::kSemiBold_Weight}, |
| {"extra", SkFontStyle::kExtraBold_Weight}, |
| {"extrabold", SkFontStyle::kExtraBold_Weight}, |
| {"extralight", SkFontStyle::kExtraLight_Weight}, |
| {"hairline", SkFontStyle::kThin_Weight}, |
| {"heavy", SkFontStyle::kBlack_Weight}, |
| {"light", SkFontStyle::kLight_Weight}, |
| {"medium", SkFontStyle::kMedium_Weight}, |
| {"normal", SkFontStyle::kNormal_Weight}, |
| {"plain", SkFontStyle::kNormal_Weight}, |
| {"regular", SkFontStyle::kNormal_Weight}, |
| {"roman", SkFontStyle::kNormal_Weight}, |
| {"semibold", SkFontStyle::kSemiBold_Weight}, |
| {"standard", SkFontStyle::kNormal_Weight}, |
| {"thin", SkFontStyle::kThin_Weight}, |
| {"ultra", SkFontStyle::kExtraBold_Weight}, |
| {"ultrabold", SkFontStyle::kExtraBold_Weight}, |
| {"ultralight", SkFontStyle::kExtraLight_Weight}, |
| }; |
| int const index = |
| SkStrLCSearch(&commonWeights[0].name, SK_ARRAY_COUNT(commonWeights), |
| psFontInfo.weight, sizeof(commonWeights[0])); |
| if (index >= 0) { |
| weight = commonWeights[index].weight; |
| } else { |
| DLOG(ERROR) << "Do not recognize weight for:" << face->family_name << "(" |
| << psFontInfo.weight << ")"; |
| } |
| } |
| |
| int face_style = SkTypeface::kNormal; |
| if (weight > 500) { |
| face_style |= SkTypeface::kBold; |
| } |
| if (face->style_flags & FT_STYLE_FLAG_ITALIC) { |
| face_style |= SkTypeface::kItalic; |
| } |
| |
| return static_cast<SkTypeface::Style>(face_style); |
| } |
| |
| void GenerateCharacterMapFromFace( |
| FT_Face face, font_character_map::CharacterMap* character_map) { |
| TRACE_EVENT0("cobalt::renderer", "GenerateCharacterMapFromFace"); |
| |
| FT_UInt glyph_index; |
| |
| int last_page = -1; |
| font_character_map::PageCharacters* page_characters = NULL; |
| |
| SkUnichar code_point = FT_Get_First_Char(face, &glyph_index); |
| while (glyph_index) { |
| int page = font_character_map::GetPage(code_point); |
| if (page != last_page) { |
| page_characters = &(*character_map)[page]; |
| last_page = page; |
| } |
| page_characters->set(font_character_map::GetPageCharacterIndex(code_point)); |
| |
| code_point = FT_Get_Next_Char(face, code_point, &glyph_index); |
| } |
| } |
| |
| } // namespace |
| |
| // These functions are used by FreeType during FT_Open_Face. |
| extern "C" { |
| |
| static unsigned long sk_freetype_cobalt_stream_io(FT_Stream ftStream, |
| unsigned long offset, |
| unsigned char* buffer, |
| unsigned long count) { |
| SkStreamAsset* stream = |
| static_cast<SkStreamAsset*>(ftStream->descriptor.pointer); |
| stream->seek(offset); |
| return stream->read(buffer, count); |
| } |
| |
| static void sk_freetype_cobalt_stream_close(FT_Stream) {} |
| } |
| |
| namespace sk_freetype_cobalt { |
| |
| bool ScanFont(SkStreamAsset* stream, int face_index, SkString* name, |
| SkTypeface::Style* style, bool* is_fixed_pitch, |
| font_character_map::CharacterMap* maybe_character_map /*=NULL*/) { |
| TRACE_EVENT0("cobalt::renderer", "SkFreeTypeUtil::ScanFont()"); |
| |
| FT_Library freetype_lib; |
| if (FT_Init_FreeType(&freetype_lib) != 0) { |
| return false; |
| } |
| |
| FT_StreamRec streamRec; |
| memset(&streamRec, 0, sizeof(streamRec)); |
| streamRec.size = stream->getLength(); |
| streamRec.descriptor.pointer = stream; |
| streamRec.read = sk_freetype_cobalt_stream_io; |
| streamRec.close = sk_freetype_cobalt_stream_close; |
| |
| FT_Open_Args args; |
| memset(&args, 0, sizeof(args)); |
| args.flags = FT_OPEN_STREAM; |
| args.stream = &streamRec; |
| |
| FT_Face face; |
| FT_Error err = FT_Open_Face(freetype_lib, &args, face_index, &face); |
| if (err) { |
| FT_Done_FreeType(freetype_lib); |
| return false; |
| } |
| |
| name->set(face->family_name); |
| *style = GenerateSkTypefaceStyleFromFace(face); |
| *is_fixed_pitch = FT_IS_FIXED_WIDTH(face); |
| |
| if (maybe_character_map) { |
| GenerateCharacterMapFromFace(face, maybe_character_map); |
| } |
| |
| // release this font. |
| FT_Done_Face(face); |
| |
| // shut down FreeType. |
| FT_Done_FreeType(freetype_lib); |
| return true; |
| } |
| |
| } // namespace sk_freetype_cobalt |