| /* |
| * Copyright (C) 2014 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 "MinikinUtils.h" |
| |
| #include <log/log.h> |
| #include <minikin/FamilyVariant.h> |
| #include <minikin/MeasuredText.h> |
| #include <minikin/Measurement.h> |
| |
| #include <optional> |
| #include <string> |
| |
| #include "FeatureFlags.h" |
| #include "Paint.h" |
| #include "SkPathMeasure.h" |
| #include "Typeface.h" |
| |
| namespace android { |
| |
| minikin::MinikinPaint MinikinUtils::prepareMinikinPaint(const Paint* paint, |
| const Typeface* typeface) { |
| const Typeface* resolvedFace = Typeface::resolveDefault(typeface); |
| const SkFont& font = paint->getSkFont(); |
| |
| minikin::MinikinPaint minikinPaint(resolvedFace->fFontCollection); |
| /* Prepare minikin Paint */ |
| minikinPaint.size = |
| font.isLinearMetrics() ? font.getSize() : static_cast<int>(font.getSize()); |
| minikinPaint.scaleX = font.getScaleX(); |
| minikinPaint.skewX = font.getSkewX(); |
| minikinPaint.letterSpacing = paint->getLetterSpacing(); |
| minikinPaint.wordSpacing = paint->getWordSpacing(); |
| minikinPaint.fontFlags = MinikinFontSkia::packFontFlags(font); |
| minikinPaint.localeListId = paint->getMinikinLocaleListId(); |
| minikinPaint.fontStyle = resolvedFace->fStyle; |
| minikinPaint.fontFeatureSettings = paint->getFontFeatureSettings(); |
| |
| const std::optional<minikin::FamilyVariant>& familyVariant = paint->getFamilyVariant(); |
| if (familyVariant.has_value()) { |
| minikinPaint.familyVariant = familyVariant.value(); |
| } else { |
| minikinPaint.familyVariant = text_feature::deprecate_ui_fonts() |
| ? minikin::FamilyVariant::ELEGANT |
| : minikin::FamilyVariant::DEFAULT; |
| } |
| return minikinPaint; |
| } |
| |
| minikin::Layout MinikinUtils::doLayout(const Paint* paint, minikin::Bidi bidiFlags, |
| const Typeface* typeface, const uint16_t* buf, |
| size_t bufSize, size_t start, size_t count, |
| size_t contextStart, size_t contextCount, |
| minikin::MeasuredText* mt) { |
| minikin::MinikinPaint minikinPaint = prepareMinikinPaint(paint, typeface); |
| |
| const minikin::U16StringPiece textBuf(buf, bufSize); |
| const minikin::Range range(start, start + count); |
| const minikin::Range contextRange(contextStart, contextStart + contextCount); |
| const minikin::StartHyphenEdit startHyphen = paint->getStartHyphenEdit(); |
| const minikin::EndHyphenEdit endHyphen = paint->getEndHyphenEdit(); |
| |
| if (mt == nullptr) { |
| return minikin::Layout(textBuf.substr(contextRange), range - contextStart, bidiFlags, |
| minikinPaint, startHyphen, endHyphen); |
| } else { |
| return mt->buildLayout(textBuf, range, contextRange, minikinPaint, startHyphen, endHyphen); |
| } |
| } |
| |
| void MinikinUtils::getBounds(const Paint* paint, minikin::Bidi bidiFlags, const Typeface* typeface, |
| const uint16_t* buf, size_t bufSize, minikin::MinikinRect* out) { |
| minikin::MinikinPaint minikinPaint = prepareMinikinPaint(paint, typeface); |
| |
| const minikin::U16StringPiece textBuf(buf, bufSize); |
| const minikin::StartHyphenEdit startHyphen = paint->getStartHyphenEdit(); |
| const minikin::EndHyphenEdit endHyphen = paint->getEndHyphenEdit(); |
| |
| minikin::getBounds(textBuf, minikin::Range(0, textBuf.size()), bidiFlags, minikinPaint, |
| startHyphen, endHyphen, out); |
| } |
| |
| float MinikinUtils::measureText(const Paint* paint, minikin::Bidi bidiFlags, |
| const Typeface* typeface, const uint16_t* buf, size_t start, |
| size_t count, size_t bufSize, float* advances, |
| minikin::MinikinRect* bounds, uint32_t* clusterCount) { |
| minikin::MinikinPaint minikinPaint = prepareMinikinPaint(paint, typeface); |
| const minikin::U16StringPiece textBuf(buf, bufSize); |
| const minikin::Range range(start, start + count); |
| const minikin::StartHyphenEdit startHyphen = paint->getStartHyphenEdit(); |
| const minikin::EndHyphenEdit endHyphen = paint->getEndHyphenEdit(); |
| |
| return minikin::Layout::measureText(textBuf, range, bidiFlags, minikinPaint, startHyphen, |
| endHyphen, advances, bounds, clusterCount); |
| } |
| |
| minikin::MinikinExtent MinikinUtils::getFontExtent(const Paint* paint, minikin::Bidi bidiFlags, |
| const Typeface* typeface, const uint16_t* buf, |
| size_t start, size_t count, size_t bufSize) { |
| minikin::MinikinPaint minikinPaint = prepareMinikinPaint(paint, typeface); |
| const minikin::U16StringPiece textBuf(buf, bufSize); |
| const minikin::Range range(start, start + count); |
| |
| return minikin::getFontExtent(textBuf, range, bidiFlags, minikinPaint); |
| } |
| |
| bool MinikinUtils::hasVariationSelector(const Typeface* typeface, uint32_t codepoint, uint32_t vs) { |
| const Typeface* resolvedFace = Typeface::resolveDefault(typeface); |
| return resolvedFace->fFontCollection->hasVariationSelector(codepoint, vs); |
| } |
| |
| float MinikinUtils::xOffsetForTextAlign(Paint* paint, const minikin::Layout& layout) { |
| switch (paint->getTextAlign()) { |
| case Paint::kCenter_Align: |
| return layout.getAdvance() * -0.5f; |
| break; |
| case Paint::kRight_Align: |
| return -layout.getAdvance(); |
| break; |
| default: |
| break; |
| } |
| return 0; |
| } |
| |
| float MinikinUtils::hOffsetForTextAlign(Paint* paint, const minikin::Layout& layout, |
| const SkPath& path) { |
| float align = 0; |
| switch (paint->getTextAlign()) { |
| case Paint::kCenter_Align: |
| align = -0.5f; |
| break; |
| case Paint::kRight_Align: |
| align = -1; |
| break; |
| default: |
| return 0; |
| } |
| SkPathMeasure measure(path, false); |
| return align * (layout.getAdvance() - measure.getLength()); |
| } |
| } // namespace android |