MinikinUtils.cpp revision da252ac5c17426f28b8e18a2b8942c6880e4055b
11a73f732f91e97c9c66b808c245ddda36a10e987Raph Levien/*
21a73f732f91e97c9c66b808c245ddda36a10e987Raph Levien * Copyright (C) 2014 The Android Open Source Project
31a73f732f91e97c9c66b808c245ddda36a10e987Raph Levien *
41a73f732f91e97c9c66b808c245ddda36a10e987Raph Levien * Licensed under the Apache License, Version 2.0 (the "License");
51a73f732f91e97c9c66b808c245ddda36a10e987Raph Levien * you may not use this file except in compliance with the License.
61a73f732f91e97c9c66b808c245ddda36a10e987Raph Levien * You may obtain a copy of the License at
71a73f732f91e97c9c66b808c245ddda36a10e987Raph Levien *
81a73f732f91e97c9c66b808c245ddda36a10e987Raph Levien *      http://www.apache.org/licenses/LICENSE-2.0
91a73f732f91e97c9c66b808c245ddda36a10e987Raph Levien *
101a73f732f91e97c9c66b808c245ddda36a10e987Raph Levien * Unless required by applicable law or agreed to in writing, software
111a73f732f91e97c9c66b808c245ddda36a10e987Raph Levien * distributed under the License is distributed on an "AS IS" BASIS,
121a73f732f91e97c9c66b808c245ddda36a10e987Raph Levien * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
131a73f732f91e97c9c66b808c245ddda36a10e987Raph Levien * See the License for the specific language governing permissions and
141a73f732f91e97c9c66b808c245ddda36a10e987Raph Levien * limitations under the License.
151a73f732f91e97c9c66b808c245ddda36a10e987Raph Levien */
1652eb4e01a49fe2e94555c000de38bbcbbb13401bMark Salyzyn
17dccca44ffda4836b56a21da95a046c9708ffd49csergeyv#include "MinikinUtils.h"
181a73f732f91e97c9c66b808c245ddda36a10e987Raph Levien
1952eb4e01a49fe2e94555c000de38bbcbbb13401bMark Salyzyn#include <string>
2052eb4e01a49fe2e94555c000de38bbcbbb13401bMark Salyzyn
2152eb4e01a49fe2e94555c000de38bbcbbb13401bMark Salyzyn#include <log/log.h>
2252eb4e01a49fe2e94555c000de38bbcbbb13401bMark Salyzyn
23783f961d2fa6f916009844dafeaa08ffaf96a4d3Seigo Nonaka#include <minikin/MeasuredText.h>
24afbd0f1fef46ef0ddf633dfde0de724db3da1405Sergei Vasilinetc#include "Paint.h"
25dccca44ffda4836b56a21da95a046c9708ffd49csergeyv#include "SkPathMeasure.h"
26bad99183916ba2bac6659efc8a28273e344ba511sergeyv#include "Typeface.h"
271a73f732f91e97c9c66b808c245ddda36a10e987Raph Levien
281a73f732f91e97c9c66b808c245ddda36a10e987Raph Leviennamespace android {
291a73f732f91e97c9c66b808c245ddda36a10e987Raph Levien
3020866c140438a9aca3e1ad09fe646308678e9383Seigo Nonakaminikin::MinikinPaint MinikinUtils::prepareMinikinPaint(const Paint* paint,
3120866c140438a9aca3e1ad09fe646308678e9383Seigo Nonaka                                                        const Typeface* typeface) {
32bad99183916ba2bac6659efc8a28273e344ba511sergeyv    const Typeface* resolvedFace = Typeface::resolveDefault(typeface);
331c4ab704d14c047775b3e42f87ea4081fa204e37Seigo Nonaka
34976f707fbf15296ea98ece91c506ae4e64dc7e66Seigo Nonaka    minikin::MinikinPaint minikinPaint(resolvedFace->fFontCollection);
351c4ab704d14c047775b3e42f87ea4081fa204e37Seigo Nonaka    /* Prepare minikin Paint */
361c4ab704d14c047775b3e42f87ea4081fa204e37Seigo Nonaka    minikinPaint.size =
371c4ab704d14c047775b3e42f87ea4081fa204e37Seigo Nonaka            paint->isLinearText() ? paint->getTextSize() : static_cast<int>(paint->getTextSize());
381c4ab704d14c047775b3e42f87ea4081fa204e37Seigo Nonaka    minikinPaint.scaleX = paint->getTextScaleX();
391c4ab704d14c047775b3e42f87ea4081fa204e37Seigo Nonaka    minikinPaint.skewX = paint->getTextSkewX();
401c4ab704d14c047775b3e42f87ea4081fa204e37Seigo Nonaka    minikinPaint.letterSpacing = paint->getLetterSpacing();
411c4ab704d14c047775b3e42f87ea4081fa204e37Seigo Nonaka    minikinPaint.wordSpacing = paint->getWordSpacing();
421c4ab704d14c047775b3e42f87ea4081fa204e37Seigo Nonaka    minikinPaint.paintFlags = MinikinFontSkia::packPaintFlags(paint);
431c4ab704d14c047775b3e42f87ea4081fa204e37Seigo Nonaka    minikinPaint.localeListId = paint->getMinikinLocaleListId();
44c52075ee2bcfde4cf9b091e404517a74ff7cec60Seigo Nonaka    minikinPaint.familyVariant = paint->getFamilyVariant();
45c52075ee2bcfde4cf9b091e404517a74ff7cec60Seigo Nonaka    minikinPaint.fontStyle = resolvedFace->fStyle;
461c4ab704d14c047775b3e42f87ea4081fa204e37Seigo Nonaka    minikinPaint.fontFeatureSettings = paint->getFontFeatureSettings();
471c4ab704d14c047775b3e42f87ea4081fa204e37Seigo Nonaka    return minikinPaint;
48c94f742f7e07a3b86c8f603836c19638472b3e83Raph Levien}
495ec789608bda858a0c6d669bb44a35a5a99abcdbBehdad Esfahbod
507c93e868825225a270c993ac058687adde682626Seigo Nonakaminikin::Layout MinikinUtils::doLayout(const Paint* paint, minikin::Bidi bidiFlags,
511bcacfdcab0eaa0cee92bd7f5a1b5e271dd68e52John Reck                                       const Typeface* typeface, const uint16_t* buf, size_t start,
52783f961d2fa6f916009844dafeaa08ffaf96a4d3Seigo Nonaka                                       size_t count, size_t bufSize, minikin::MeasuredText* mt,
53783f961d2fa6f916009844dafeaa08ffaf96a4d3Seigo Nonaka                                       int mtOffset) {
541c4ab704d14c047775b3e42f87ea4081fa204e37Seigo Nonaka    minikin::MinikinPaint minikinPaint = prepareMinikinPaint(paint, typeface);
5551218e80f70601193e43d90aaf1599a7f6d11062Seigo Nonaka    minikin::Layout layout;
56783f961d2fa6f916009844dafeaa08ffaf96a4d3Seigo Nonaka
57da252ac5c17426f28b8e18a2b8942c6880e4055bSeigo Nonaka    const minikin::U16StringPiece textBuf(buf, bufSize);
58da252ac5c17426f28b8e18a2b8942c6880e4055bSeigo Nonaka    const minikin::Range range(start, start + count);
59da252ac5c17426f28b8e18a2b8942c6880e4055bSeigo Nonaka    const minikin::HyphenEdit hyphenEdit = static_cast<minikin::HyphenEdit>(paint->getHyphenEdit());
60da252ac5c17426f28b8e18a2b8942c6880e4055bSeigo Nonaka    const minikin::StartHyphenEdit startHyphen = minikin::startHyphenEdit(hyphenEdit);
61da252ac5c17426f28b8e18a2b8942c6880e4055bSeigo Nonaka    const minikin::EndHyphenEdit endHyphen = minikin::endHyphenEdit(hyphenEdit);
62da252ac5c17426f28b8e18a2b8942c6880e4055bSeigo Nonaka
63783f961d2fa6f916009844dafeaa08ffaf96a4d3Seigo Nonaka    if (mt == nullptr) {
64da252ac5c17426f28b8e18a2b8942c6880e4055bSeigo Nonaka        layout.doLayout(textBuf,range, bidiFlags, minikinPaint, startHyphen, endHyphen);
65783f961d2fa6f916009844dafeaa08ffaf96a4d3Seigo Nonaka        return layout;
66783f961d2fa6f916009844dafeaa08ffaf96a4d3Seigo Nonaka    }
67783f961d2fa6f916009844dafeaa08ffaf96a4d3Seigo Nonaka
68da252ac5c17426f28b8e18a2b8942c6880e4055bSeigo Nonaka    if (mt->buildLayout(textBuf, range, minikinPaint, bidiFlags, mtOffset, startHyphen, endHyphen,
69da252ac5c17426f28b8e18a2b8942c6880e4055bSeigo Nonaka                        &layout)) {
70783f961d2fa6f916009844dafeaa08ffaf96a4d3Seigo Nonaka        return layout;
71783f961d2fa6f916009844dafeaa08ffaf96a4d3Seigo Nonaka    }
72783f961d2fa6f916009844dafeaa08ffaf96a4d3Seigo Nonaka
73da252ac5c17426f28b8e18a2b8942c6880e4055bSeigo Nonaka    layout.doLayout(textBuf, range, bidiFlags, minikinPaint, startHyphen, endHyphen);
74c7064146f959caec058980ced144942c8044a169Seigo Nonaka    return layout;
751a73f732f91e97c9c66b808c245ddda36a10e987Raph Levien}
761a73f732f91e97c9c66b808c245ddda36a10e987Raph Levien
777c93e868825225a270c993ac058687adde682626Seigo Nonakafloat MinikinUtils::measureText(const Paint* paint, minikin::Bidi bidiFlags,
781bcacfdcab0eaa0cee92bd7f5a1b5e271dd68e52John Reck                                const Typeface* typeface, const uint16_t* buf, size_t start,
791bcacfdcab0eaa0cee92bd7f5a1b5e271dd68e52John Reck                                size_t count, size_t bufSize, float* advances) {
801c4ab704d14c047775b3e42f87ea4081fa204e37Seigo Nonaka    minikin::MinikinPaint minikinPaint = prepareMinikinPaint(paint, typeface);
81da252ac5c17426f28b8e18a2b8942c6880e4055bSeigo Nonaka    const minikin::U16StringPiece textBuf(buf, bufSize);
82da252ac5c17426f28b8e18a2b8942c6880e4055bSeigo Nonaka    const minikin::Range range(start, start + count);
83da252ac5c17426f28b8e18a2b8942c6880e4055bSeigo Nonaka    const minikin::HyphenEdit hyphenEdit = static_cast<minikin::HyphenEdit>(paint->getHyphenEdit());
84da252ac5c17426f28b8e18a2b8942c6880e4055bSeigo Nonaka    const minikin::StartHyphenEdit startHyphen = minikin::startHyphenEdit(hyphenEdit);
85da252ac5c17426f28b8e18a2b8942c6880e4055bSeigo Nonaka    const minikin::EndHyphenEdit endHyphen = minikin::endHyphenEdit(hyphenEdit);
86da252ac5c17426f28b8e18a2b8942c6880e4055bSeigo Nonaka
87da252ac5c17426f28b8e18a2b8942c6880e4055bSeigo Nonaka    return minikin::Layout::measureText(textBuf, range, bidiFlags, minikinPaint, startHyphen,
88da252ac5c17426f28b8e18a2b8942c6880e4055bSeigo Nonaka                                        endHyphen, advances, nullptr /* extent */);
89a3024bd7026deb777556dd75dd34a719ea1c2b39Keisuke Kuroyanagi}
90a3024bd7026deb777556dd75dd34a719ea1c2b39Keisuke Kuroyanagi
91318ca04079bd6242cb6186d9005b9caeee22e845Seigo Nonakabool MinikinUtils::hasVariationSelector(const Typeface* typeface, uint32_t codepoint, uint32_t vs) {
92bad99183916ba2bac6659efc8a28273e344ba511sergeyv    const Typeface* resolvedFace = Typeface::resolveDefault(typeface);
93bb1a96647a82df5a134bf631fc9db342e7ef61deSeigo Nonaka    return resolvedFace->fFontCollection->hasVariationSelector(codepoint, vs);
94bb1a96647a82df5a134bf631fc9db342e7ef61deSeigo Nonaka}
95bb1a96647a82df5a134bf631fc9db342e7ef61deSeigo Nonaka
96ae1aa85d0c7305bb621f1f8003bd674285aa3b63Seigo Nonakafloat MinikinUtils::xOffsetForTextAlign(Paint* paint, const minikin::Layout& layout) {
97f2114d5646194100242206b267ddd6e7194b7da9Raph Levien    switch (paint->getTextAlign()) {
986ba30b85ddfbe37c338ee8dde3dd33322eb38d47Behdad Esfahbod        case Paint::kCenter_Align:
99f2114d5646194100242206b267ddd6e7194b7da9Raph Levien            return layout.getAdvance() * -0.5f;
100f2114d5646194100242206b267ddd6e7194b7da9Raph Levien            break;
1016ba30b85ddfbe37c338ee8dde3dd33322eb38d47Behdad Esfahbod        case Paint::kRight_Align:
102f2114d5646194100242206b267ddd6e7194b7da9Raph Levien            return -layout.getAdvance();
103f2114d5646194100242206b267ddd6e7194b7da9Raph Levien            break;
104f2114d5646194100242206b267ddd6e7194b7da9Raph Levien        default:
105f2114d5646194100242206b267ddd6e7194b7da9Raph Levien            break;
106f2114d5646194100242206b267ddd6e7194b7da9Raph Levien    }
107f2114d5646194100242206b267ddd6e7194b7da9Raph Levien    return 0;
108f2114d5646194100242206b267ddd6e7194b7da9Raph Levien}
109f2114d5646194100242206b267ddd6e7194b7da9Raph Levien
110ae1aa85d0c7305bb621f1f8003bd674285aa3b63Seigo Nonakafloat MinikinUtils::hOffsetForTextAlign(Paint* paint, const minikin::Layout& layout,
1111bcacfdcab0eaa0cee92bd7f5a1b5e271dd68e52John Reck                                        const SkPath& path) {
1129d2b5e1930bfc4b1da1c865843c247c708ea1565Raph Levien    float align = 0;
1139d2b5e1930bfc4b1da1c865843c247c708ea1565Raph Levien    switch (paint->getTextAlign()) {
1146ba30b85ddfbe37c338ee8dde3dd33322eb38d47Behdad Esfahbod        case Paint::kCenter_Align:
1159d2b5e1930bfc4b1da1c865843c247c708ea1565Raph Levien            align = -0.5f;
1169d2b5e1930bfc4b1da1c865843c247c708ea1565Raph Levien            break;
1176ba30b85ddfbe37c338ee8dde3dd33322eb38d47Behdad Esfahbod        case Paint::kRight_Align:
1189d2b5e1930bfc4b1da1c865843c247c708ea1565Raph Levien            align = -1;
1199d2b5e1930bfc4b1da1c865843c247c708ea1565Raph Levien            break;
1209d2b5e1930bfc4b1da1c865843c247c708ea1565Raph Levien        default:
1219d2b5e1930bfc4b1da1c865843c247c708ea1565Raph Levien            return 0;
1229d2b5e1930bfc4b1da1c865843c247c708ea1565Raph Levien    }
1239d2b5e1930bfc4b1da1c865843c247c708ea1565Raph Levien    SkPathMeasure measure(path, false);
1249d2b5e1930bfc4b1da1c865843c247c708ea1565Raph Levien    return align * (layout.getAdvance() - measure.getLength());
1259d2b5e1930bfc4b1da1c865843c247c708ea1565Raph Levien}
12620866c140438a9aca3e1ad09fe646308678e9383Seigo Nonaka}  // namespace android
127