| /* |
| * Copyright (C) 2013 The Android Open Source Project |
| * |
| * 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 "MinikinSkia.h" |
| |
| #include <SkFontDescriptor.h> |
| #include <SkFont.h> |
| #include <SkFontMetrics.h> |
| #include <SkFontMgr.h> |
| #include <SkTypeface.h> |
| #include <log/log.h> |
| |
| #include <minikin/Font.h> |
| #include <minikin/MinikinExtent.h> |
| #include <minikin/MinikinPaint.h> |
| #include <minikin/MinikinRect.h> |
| |
| namespace android { |
| |
| MinikinFontSkia::MinikinFontSkia(sk_sp<SkTypeface> typeface, const void* fontData, size_t fontSize, |
| std::string_view filePath, int ttcIndex, |
| const std::vector<minikin::FontVariation>& axes) |
| : minikin::MinikinFont(typeface->uniqueID()) |
| , mTypeface(std::move(typeface)) |
| , mFontData(fontData) |
| , mFontSize(fontSize) |
| , mTtcIndex(ttcIndex) |
| , mAxes(axes) |
| , mFilePath(filePath) {} |
| |
| static void MinikinFontSkia_SetSkiaFont(const minikin::MinikinFont* font, SkFont* skFont, |
| const minikin::MinikinPaint& paint, |
| const minikin::FontFakery& fakery) { |
| skFont->setSize(paint.size); |
| skFont->setScaleX(paint.scaleX); |
| skFont->setSkewX(paint.skewX); |
| MinikinFontSkia::unpackFontFlags(skFont, paint.fontFlags); |
| // Apply font fakery on top of user-supplied flags. |
| MinikinFontSkia::populateSkFont(skFont, font, fakery); |
| } |
| |
| float MinikinFontSkia::GetHorizontalAdvance(uint32_t glyph_id, const minikin::MinikinPaint& paint, |
| const minikin::FontFakery& fakery) const { |
| SkFont skFont; |
| uint16_t glyph16 = glyph_id; |
| SkScalar skWidth; |
| MinikinFontSkia_SetSkiaFont(this, &skFont, paint, fakery); |
| skFont.getWidths(&glyph16, 1, &skWidth); |
| #ifdef VERBOSE |
| ALOGD("width for typeface %d glyph %d = %f", mTypeface->uniqueID(), glyph_id, skWidth); |
| #endif |
| return skWidth; |
| } |
| |
| void MinikinFontSkia::GetBounds(minikin::MinikinRect* bounds, uint32_t glyph_id, |
| const minikin::MinikinPaint& paint, |
| const minikin::FontFakery& fakery) const { |
| SkFont skFont; |
| uint16_t glyph16 = glyph_id; |
| SkRect skBounds; |
| MinikinFontSkia_SetSkiaFont(this, &skFont, paint, fakery); |
| skFont.getWidths(&glyph16, 1, nullptr, &skBounds); |
| bounds->mLeft = skBounds.fLeft; |
| bounds->mTop = skBounds.fTop; |
| bounds->mRight = skBounds.fRight; |
| bounds->mBottom = skBounds.fBottom; |
| } |
| |
| void MinikinFontSkia::GetFontExtent(minikin::MinikinExtent* extent, |
| const minikin::MinikinPaint& paint, |
| const minikin::FontFakery& fakery) const { |
| SkFont skFont; |
| MinikinFontSkia_SetSkiaFont(this, &skFont, paint, fakery); |
| SkFontMetrics metrics; |
| skFont.getMetrics(&metrics); |
| extent->ascent = metrics.fAscent; |
| extent->descent = metrics.fDescent; |
| } |
| |
| SkTypeface* MinikinFontSkia::GetSkTypeface() const { |
| return mTypeface.get(); |
| } |
| |
| sk_sp<SkTypeface> MinikinFontSkia::RefSkTypeface() const { |
| return mTypeface; |
| } |
| |
| const void* MinikinFontSkia::GetFontData() const { |
| return mFontData; |
| } |
| |
| size_t MinikinFontSkia::GetFontSize() const { |
| return mFontSize; |
| } |
| |
| int MinikinFontSkia::GetFontIndex() const { |
| return mTtcIndex; |
| } |
| |
| const std::vector<minikin::FontVariation>& MinikinFontSkia::GetAxes() const { |
| return mAxes; |
| } |
| |
| std::shared_ptr<minikin::MinikinFont> MinikinFontSkia::createFontWithVariation( |
| const std::vector<minikin::FontVariation>& variations) const { |
| SkFontArguments params; |
| |
| int ttcIndex; |
| std::unique_ptr<SkStreamAsset> stream(mTypeface->openStream(&ttcIndex)); |
| LOG_ALWAYS_FATAL_IF(stream == nullptr, "openStream failed"); |
| |
| params.setCollectionIndex(ttcIndex); |
| std::vector<SkFontArguments::Axis> skAxes; |
| skAxes.resize(variations.size()); |
| for (size_t i = 0; i < variations.size(); i++) { |
| skAxes[i].fTag = variations[i].axisTag; |
| skAxes[i].fStyleValue = SkFloatToScalar(variations[i].value); |
| } |
| params.setAxes(skAxes.data(), skAxes.size()); |
| sk_sp<SkFontMgr> fm(SkFontMgr::RefDefault()); |
| sk_sp<SkTypeface> face(fm->makeFromStream(std::move(stream), params)); |
| |
| return std::make_shared<MinikinFontSkia>(std::move(face), mFontData, mFontSize, mFilePath, |
| ttcIndex, variations); |
| } |
| |
| // hinting<<16 | edging<<8 | bools:5bits |
| uint32_t MinikinFontSkia::packFontFlags(const SkFont& font) { |
| uint32_t flags = (unsigned)font.getHinting() << 16; |
| flags |= (unsigned)font.getEdging() << 8; |
| flags |= font.isEmbolden() << minikin::Embolden_Shift; |
| flags |= font.isLinearMetrics() << minikin::LinearMetrics_Shift; |
| flags |= font.isSubpixel() << minikin::Subpixel_Shift; |
| flags |= font.isEmbeddedBitmaps() << minikin::EmbeddedBitmaps_Shift; |
| flags |= font.isForceAutoHinting() << minikin::ForceAutoHinting_Shift; |
| return flags; |
| } |
| |
| void MinikinFontSkia::unpackFontFlags(SkFont* font, uint32_t flags) { |
| // We store hinting in the top 16 bits (only need 2 of them) |
| font->setHinting((SkFontHinting)(flags >> 16)); |
| // We store edging in bits 8:15 (only need 2 of them) |
| font->setEdging((SkFont::Edging)((flags >> 8) & 0xFF)); |
| font->setEmbolden( (flags & minikin::Embolden_Flag) != 0); |
| font->setLinearMetrics( (flags & minikin::LinearMetrics_Flag) != 0); |
| font->setSubpixel( (flags & minikin::Subpixel_Flag) != 0); |
| font->setEmbeddedBitmaps( (flags & minikin::EmbeddedBitmaps_Flag) != 0); |
| font->setForceAutoHinting((flags & minikin::ForceAutoHinting_Flag) != 0); |
| } |
| |
| void MinikinFontSkia::populateSkFont(SkFont* skFont, const MinikinFont* font, |
| minikin::FontFakery fakery) { |
| skFont->setTypeface(reinterpret_cast<const MinikinFontSkia*>(font)->RefSkTypeface()); |
| skFont->setEmbolden(skFont->isEmbolden() || fakery.isFakeBold()); |
| if (fakery.isFakeItalic()) { |
| skFont->setSkewX(skFont->getSkewX() - 0.25f); |
| } |
| } |
| } |