1f7cb1f75fdaedf996cab7c4690b080adc7bc5b97Doug Felt/*
2f7cb1f75fdaedf996cab7c4690b080adc7bc5b97Doug Felt * Copyright (C) 2010 The Android Open Source Project
3f7cb1f75fdaedf996cab7c4690b080adc7bc5b97Doug Felt *
4f7cb1f75fdaedf996cab7c4690b080adc7bc5b97Doug Felt * Licensed under the Apache License, Version 2.0 (the "License");
5f7cb1f75fdaedf996cab7c4690b080adc7bc5b97Doug Felt * you may not use this file except in compliance with the License.
6f7cb1f75fdaedf996cab7c4690b080adc7bc5b97Doug Felt * You may obtain a copy of the License at
7f7cb1f75fdaedf996cab7c4690b080adc7bc5b97Doug Felt *
8f7cb1f75fdaedf996cab7c4690b080adc7bc5b97Doug Felt *      http://www.apache.org/licenses/LICENSE-2.0
9f7cb1f75fdaedf996cab7c4690b080adc7bc5b97Doug Felt *
10f7cb1f75fdaedf996cab7c4690b080adc7bc5b97Doug Felt * Unless required by applicable law or agreed to in writing, software
11f7cb1f75fdaedf996cab7c4690b080adc7bc5b97Doug Felt * distributed under the License is distributed on an "AS IS" BASIS,
12f7cb1f75fdaedf996cab7c4690b080adc7bc5b97Doug Felt * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13f7cb1f75fdaedf996cab7c4690b080adc7bc5b97Doug Felt * See the License for the specific language governing permissions and
14f7cb1f75fdaedf996cab7c4690b080adc7bc5b97Doug Felt * limitations under the License.
15f7cb1f75fdaedf996cab7c4690b080adc7bc5b97Doug Felt */
16f7cb1f75fdaedf996cab7c4690b080adc7bc5b97Doug Felt
17b02d0ca5553300063e4332192632312600caf4b9Fabrice Di Meglio#define LOG_TAG "TextLayout"
18b02d0ca5553300063e4332192632312600caf4b9Fabrice Di Meglio
19f7cb1f75fdaedf996cab7c4690b080adc7bc5b97Doug Felt#include "TextLayout.h"
20d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio#include "TextLayoutCache.h"
21f7cb1f75fdaedf996cab7c4690b080adc7bc5b97Doug Felt
22f7cb1f75fdaedf996cab7c4690b080adc7bc5b97Doug Felt#include <android_runtime/AndroidRuntime.h>
23f7cb1f75fdaedf996cab7c4690b080adc7bc5b97Doug Felt
24f7cb1f75fdaedf996cab7c4690b080adc7bc5b97Doug Felt#include "SkTemplates.h"
25f7cb1f75fdaedf996cab7c4690b080adc7bc5b97Doug Felt#include "unicode/ubidi.h"
26f7cb1f75fdaedf996cab7c4690b080adc7bc5b97Doug Felt#include "unicode/ushape.h"
27f7cb1f75fdaedf996cab7c4690b080adc7bc5b97Doug Felt#include <utils/Log.h>
28f7cb1f75fdaedf996cab7c4690b080adc7bc5b97Doug Felt
29f7cb1f75fdaedf996cab7c4690b080adc7bc5b97Doug Feltnamespace android {
30d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio
31f7cb1f75fdaedf996cab7c4690b080adc7bc5b97Doug Felt// Returns true if we might need layout.  If bidiFlags force LTR, assume no layout, if
32f7cb1f75fdaedf996cab7c4690b080adc7bc5b97Doug Felt// bidiFlags indicate there probably is RTL, assume we do, otherwise scan the text
33f7cb1f75fdaedf996cab7c4690b080adc7bc5b97Doug Felt// looking for a character >= the first RTL character in unicode and assume we do if
34f7cb1f75fdaedf996cab7c4690b080adc7bc5b97Doug Felt// we find one.
35f7cb1f75fdaedf996cab7c4690b080adc7bc5b97Doug Feltbool TextLayout::needsLayout(const jchar* text, jint len, jint bidiFlags) {
36f7cb1f75fdaedf996cab7c4690b080adc7bc5b97Doug Felt    if (bidiFlags == kBidi_Force_LTR) {
37f7cb1f75fdaedf996cab7c4690b080adc7bc5b97Doug Felt        return false;
38f7cb1f75fdaedf996cab7c4690b080adc7bc5b97Doug Felt    }
39f7cb1f75fdaedf996cab7c4690b080adc7bc5b97Doug Felt    if ((bidiFlags == kBidi_RTL) || (bidiFlags == kBidi_Default_RTL) ||
40f7cb1f75fdaedf996cab7c4690b080adc7bc5b97Doug Felt            bidiFlags == kBidi_Force_RTL) {
41f7cb1f75fdaedf996cab7c4690b080adc7bc5b97Doug Felt        return true;
42f7cb1f75fdaedf996cab7c4690b080adc7bc5b97Doug Felt    }
43f7cb1f75fdaedf996cab7c4690b080adc7bc5b97Doug Felt    for (int i = 0; i < len; ++i) {
44dd347df9f85e04d8b08a5249b8db731300699cc4Fabrice Di Meglio        if (text[i] >= UNICODE_FIRST_RTL_CHAR) {
45f7cb1f75fdaedf996cab7c4690b080adc7bc5b97Doug Felt            return true;
46f7cb1f75fdaedf996cab7c4690b080adc7bc5b97Doug Felt        }
47f7cb1f75fdaedf996cab7c4690b080adc7bc5b97Doug Felt    }
48f7cb1f75fdaedf996cab7c4690b080adc7bc5b97Doug Felt    return false;
49f7cb1f75fdaedf996cab7c4690b080adc7bc5b97Doug Felt}
50f7cb1f75fdaedf996cab7c4690b080adc7bc5b97Doug Felt
51e8e62a4a032a80409114a37908b5f18ab0080848Romain Guy// Draws or gets the path of a paragraph of text on a single line, running bidi and shaping.
52e8e62a4a032a80409114a37908b5f18ab0080848Romain Guy// This will draw if canvas is not null, otherwise path must be non-null and it will create
53e8e62a4a032a80409114a37908b5f18ab0080848Romain Guy// a path representing the text that would have been drawn.
54e8e62a4a032a80409114a37908b5f18ab0080848Romain Guyvoid TextLayout::handleText(SkPaint *paint, const jchar* text, jsize len,
55c511bee87cda99a252d1a62487f47c8f05aee78cFabrice Di Meglio                            jint bidiFlags, jfloat x, jfloat y, SkPath *path) {
56a731b082b2c43204e6e9f927ab82fb732934a83bFabrice Di Meglio    sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(paint,
57a731b082b2c43204e6e9f927ab82fb732934a83bFabrice Di Meglio            text, 0, len, len, bidiFlags);
58b02d0ca5553300063e4332192632312600caf4b9Fabrice Di Meglio    if (value == NULL) {
59b02d0ca5553300063e4332192632312600caf4b9Fabrice Di Meglio        return ;
60e8e62a4a032a80409114a37908b5f18ab0080848Romain Guy    }
61b02d0ca5553300063e4332192632312600caf4b9Fabrice Di Meglio    SkScalar x_ = SkFloatToScalar(x);
62b02d0ca5553300063e4332192632312600caf4b9Fabrice Di Meglio    SkScalar y_ = SkFloatToScalar(y);
63c511bee87cda99a252d1a62487f47c8f05aee78cFabrice Di Meglio    // Beware: this needs Glyph encoding (already done on the Paint constructor)
64c511bee87cda99a252d1a62487f47c8f05aee78cFabrice Di Meglio    paint->getTextPath(value->getGlyphs(), value->getGlyphsCount() * 2, x_, y_, path);
6561c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy}
6661c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy
67d313c665e618af3194f504064bcd284fe5368682Fabrice Di Megliovoid TextLayout::getTextRunAdvances(SkPaint* paint, const jchar* chars, jint start,
68f7cb1f75fdaedf996cab7c4690b080adc7bc5b97Doug Felt                                    jint count, jint contextCount, jint dirFlags,
6979df5323e7ed541b854cea5684a89e8be8c2dfc9Fabrice Di Meglio                                    jfloat* resultAdvances, jfloat* resultTotalAdvance) {
70a731b082b2c43204e6e9f927ab82fb732934a83bFabrice Di Meglio    sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(paint,
71a731b082b2c43204e6e9f927ab82fb732934a83bFabrice Di Meglio            chars, start, count, contextCount, dirFlags);
72b02d0ca5553300063e4332192632312600caf4b9Fabrice Di Meglio    if (value == NULL) {
73b02d0ca5553300063e4332192632312600caf4b9Fabrice Di Meglio        return ;
74b02d0ca5553300063e4332192632312600caf4b9Fabrice Di Meglio    }
75b02d0ca5553300063e4332192632312600caf4b9Fabrice Di Meglio    if (resultAdvances) {
76b02d0ca5553300063e4332192632312600caf4b9Fabrice Di Meglio        memcpy(resultAdvances, value->getAdvances(), value->getAdvancesCount() * sizeof(jfloat));
77b02d0ca5553300063e4332192632312600caf4b9Fabrice Di Meglio    }
78b02d0ca5553300063e4332192632312600caf4b9Fabrice Di Meglio    if (resultTotalAdvance) {
79b02d0ca5553300063e4332192632312600caf4b9Fabrice Di Meglio        *resultTotalAdvance = value->getTotalAdvance();
80fcf2be1846935e7983ea2fe87fdd4d7af27764b6Fabrice Di Meglio    }
81f7cb1f75fdaedf996cab7c4690b080adc7bc5b97Doug Felt}
82f7cb1f75fdaedf996cab7c4690b080adc7bc5b97Doug Felt
83eee49c699c035ffba188417489f40d34f587d65cFabrice Di Megliovoid TextLayout::getTextRunAdvancesICU(SkPaint* paint, const jchar* chars, jint start,
84eee49c699c035ffba188417489f40d34f587d65cFabrice Di Meglio                                    jint count, jint contextCount, jint dirFlags,
85eee49c699c035ffba188417489f40d34f587d65cFabrice Di Meglio                                    jfloat* resultAdvances, jfloat& resultTotalAdvance) {
86eee49c699c035ffba188417489f40d34f587d65cFabrice Di Meglio    // Compute advances and return them
8754dc642cc1e188b9eeecadb648b9e8c610f4b857Fabrice Di Meglio    computeAdvancesWithICU(paint, chars, start, count, contextCount, dirFlags,
88eee49c699c035ffba188417489f40d34f587d65cFabrice Di Meglio            resultAdvances, &resultTotalAdvance);
89eee49c699c035ffba188417489f40d34f587d65cFabrice Di Meglio}
90f7cb1f75fdaedf996cab7c4690b080adc7bc5b97Doug Felt
91f7cb1f75fdaedf996cab7c4690b080adc7bc5b97Doug Feltvoid TextLayout::getTextPath(SkPaint *paint, const jchar *text, jsize len,
92f7cb1f75fdaedf996cab7c4690b080adc7bc5b97Doug Felt                             jint bidiFlags, jfloat x, jfloat y, SkPath *path) {
93c511bee87cda99a252d1a62487f47c8f05aee78cFabrice Di Meglio    handleText(paint, text, len, bidiFlags, x, y, path);
94f7cb1f75fdaedf996cab7c4690b080adc7bc5b97Doug Felt}
95f7cb1f75fdaedf996cab7c4690b080adc7bc5b97Doug Felt
96f7cb1f75fdaedf996cab7c4690b080adc7bc5b97Doug Felt
97f7cb1f75fdaedf996cab7c4690b080adc7bc5b97Doug Feltvoid TextLayout::drawTextOnPath(SkPaint* paint, const jchar* text, int count,
98f7cb1f75fdaedf996cab7c4690b080adc7bc5b97Doug Felt                                int bidiFlags, jfloat hOffset, jfloat vOffset,
99f7cb1f75fdaedf996cab7c4690b080adc7bc5b97Doug Felt                                SkPath* path, SkCanvas* canvas) {
100f7cb1f75fdaedf996cab7c4690b080adc7bc5b97Doug Felt
101f7cb1f75fdaedf996cab7c4690b080adc7bc5b97Doug Felt    SkScalar h_ = SkFloatToScalar(hOffset);
102f7cb1f75fdaedf996cab7c4690b080adc7bc5b97Doug Felt    SkScalar v_ = SkFloatToScalar(vOffset);
103f7cb1f75fdaedf996cab7c4690b080adc7bc5b97Doug Felt
104a731b082b2c43204e6e9f927ab82fb732934a83bFabrice Di Meglio    sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(paint,
105a731b082b2c43204e6e9f927ab82fb732934a83bFabrice Di Meglio            text, 0, count, count, bidiFlags);
106b02d0ca5553300063e4332192632312600caf4b9Fabrice Di Meglio    if (value == NULL) {
107a731b082b2c43204e6e9f927ab82fb732934a83bFabrice Di Meglio        return;
108f7cb1f75fdaedf996cab7c4690b080adc7bc5b97Doug Felt    }
109a731b082b2c43204e6e9f927ab82fb732934a83bFabrice Di Meglio
110c511bee87cda99a252d1a62487f47c8f05aee78cFabrice Di Meglio    // Beware: this needs Glyph encoding (already done on the Paint constructor)
111b02d0ca5553300063e4332192632312600caf4b9Fabrice Di Meglio    canvas->drawTextOnPathHV(value->getGlyphs(), value->getGlyphsCount() * 2, *path, h_, v_, *paint);
112f7cb1f75fdaedf996cab7c4690b080adc7bc5b97Doug Felt}
113f7cb1f75fdaedf996cab7c4690b080adc7bc5b97Doug Felt
11454dc642cc1e188b9eeecadb648b9e8c610f4b857Fabrice Di Megliovoid TextLayout::computeAdvancesWithICU(SkPaint* paint, const UChar* chars,
11554dc642cc1e188b9eeecadb648b9e8c610f4b857Fabrice Di Meglio        size_t start, size_t count, size_t contextCount, int dirFlags,
11654dc642cc1e188b9eeecadb648b9e8c610f4b857Fabrice Di Meglio        jfloat* outAdvances, jfloat* outTotalAdvance) {
11754dc642cc1e188b9eeecadb648b9e8c610f4b857Fabrice Di Meglio    SkAutoSTMalloc<CHAR_BUFFER_SIZE, jchar> tempBuffer(contextCount);
11854dc642cc1e188b9eeecadb648b9e8c610f4b857Fabrice Di Meglio    jchar* buffer = tempBuffer.get();
11954dc642cc1e188b9eeecadb648b9e8c610f4b857Fabrice Di Meglio    SkScalar* scalarArray = (SkScalar*)outAdvances;
12054dc642cc1e188b9eeecadb648b9e8c610f4b857Fabrice Di Meglio
12154dc642cc1e188b9eeecadb648b9e8c610f4b857Fabrice Di Meglio    // this is where we'd call harfbuzz
12254dc642cc1e188b9eeecadb648b9e8c610f4b857Fabrice Di Meglio    // for now we just use ushape.c
12354dc642cc1e188b9eeecadb648b9e8c610f4b857Fabrice Di Meglio    size_t widths;
12454dc642cc1e188b9eeecadb648b9e8c610f4b857Fabrice Di Meglio    const jchar* text;
12554dc642cc1e188b9eeecadb648b9e8c610f4b857Fabrice Di Meglio    if (dirFlags & 0x1) { // rtl, call arabic shaping in case
12654dc642cc1e188b9eeecadb648b9e8c610f4b857Fabrice Di Meglio        UErrorCode status = U_ZERO_ERROR;
12754dc642cc1e188b9eeecadb648b9e8c610f4b857Fabrice Di Meglio        // Use fixed length since we need to keep start and count valid
12854dc642cc1e188b9eeecadb648b9e8c610f4b857Fabrice Di Meglio        u_shapeArabic(chars, contextCount, buffer, contextCount,
12954dc642cc1e188b9eeecadb648b9e8c610f4b857Fabrice Di Meglio                U_SHAPE_LENGTH_FIXED_SPACES_NEAR |
13054dc642cc1e188b9eeecadb648b9e8c610f4b857Fabrice Di Meglio                U_SHAPE_TEXT_DIRECTION_LOGICAL | U_SHAPE_LETTERS_SHAPE |
13154dc642cc1e188b9eeecadb648b9e8c610f4b857Fabrice Di Meglio                U_SHAPE_X_LAMALEF_SUB_ALTERNATE, &status);
13254dc642cc1e188b9eeecadb648b9e8c610f4b857Fabrice Di Meglio        // we shouldn't fail unless there's an out of memory condition,
13354dc642cc1e188b9eeecadb648b9e8c610f4b857Fabrice Di Meglio        // in which case we're hosed anyway
13454dc642cc1e188b9eeecadb648b9e8c610f4b857Fabrice Di Meglio        for (int i = start, e = i + count; i < e; ++i) {
13554dc642cc1e188b9eeecadb648b9e8c610f4b857Fabrice Di Meglio            if (buffer[i] == UNICODE_NOT_A_CHAR) {
13654dc642cc1e188b9eeecadb648b9e8c610f4b857Fabrice Di Meglio                buffer[i] = UNICODE_ZWSP; // zero-width-space for skia
13754dc642cc1e188b9eeecadb648b9e8c610f4b857Fabrice Di Meglio            }
13854dc642cc1e188b9eeecadb648b9e8c610f4b857Fabrice Di Meglio        }
13954dc642cc1e188b9eeecadb648b9e8c610f4b857Fabrice Di Meglio        text = buffer + start;
14054dc642cc1e188b9eeecadb648b9e8c610f4b857Fabrice Di Meglio        widths = paint->getTextWidths(text, count << 1, scalarArray);
14154dc642cc1e188b9eeecadb648b9e8c610f4b857Fabrice Di Meglio    } else {
14254dc642cc1e188b9eeecadb648b9e8c610f4b857Fabrice Di Meglio        text = chars + start;
14354dc642cc1e188b9eeecadb648b9e8c610f4b857Fabrice Di Meglio        widths = paint->getTextWidths(text, count << 1, scalarArray);
14454dc642cc1e188b9eeecadb648b9e8c610f4b857Fabrice Di Meglio    }
14554dc642cc1e188b9eeecadb648b9e8c610f4b857Fabrice Di Meglio
14654dc642cc1e188b9eeecadb648b9e8c610f4b857Fabrice Di Meglio    jfloat totalAdvance = 0;
14754dc642cc1e188b9eeecadb648b9e8c610f4b857Fabrice Di Meglio    if (widths < count) {
14854dc642cc1e188b9eeecadb648b9e8c610f4b857Fabrice Di Meglio#if DEBUG_ADVANCES
1495baa3a62a97544669fba6d65a11c07f252e654ddSteve Block    ALOGD("ICU -- count=%d", widths);
15054dc642cc1e188b9eeecadb648b9e8c610f4b857Fabrice Di Meglio#endif
15154dc642cc1e188b9eeecadb648b9e8c610f4b857Fabrice Di Meglio        // Skia operates on code points, not code units, so surrogate pairs return only
15254dc642cc1e188b9eeecadb648b9e8c610f4b857Fabrice Di Meglio        // one value. Expand the result so we have one value per UTF-16 code unit.
15354dc642cc1e188b9eeecadb648b9e8c610f4b857Fabrice Di Meglio
15454dc642cc1e188b9eeecadb648b9e8c610f4b857Fabrice Di Meglio        // Note, skia's getTextWidth gets confused if it encounters a surrogate pair,
15554dc642cc1e188b9eeecadb648b9e8c610f4b857Fabrice Di Meglio        // leaving the remaining widths zero.  Not nice.
15654dc642cc1e188b9eeecadb648b9e8c610f4b857Fabrice Di Meglio        for (size_t i = 0, p = 0; i < widths; ++i) {
15754dc642cc1e188b9eeecadb648b9e8c610f4b857Fabrice Di Meglio            totalAdvance += outAdvances[p++] = SkScalarToFloat(scalarArray[i]);
15854dc642cc1e188b9eeecadb648b9e8c610f4b857Fabrice Di Meglio            if (p < count &&
15954dc642cc1e188b9eeecadb648b9e8c610f4b857Fabrice Di Meglio                    text[p] >= UNICODE_FIRST_LOW_SURROGATE &&
16054dc642cc1e188b9eeecadb648b9e8c610f4b857Fabrice Di Meglio                    text[p] < UNICODE_FIRST_PRIVATE_USE &&
16154dc642cc1e188b9eeecadb648b9e8c610f4b857Fabrice Di Meglio                    text[p-1] >= UNICODE_FIRST_HIGH_SURROGATE &&
16254dc642cc1e188b9eeecadb648b9e8c610f4b857Fabrice Di Meglio                    text[p-1] < UNICODE_FIRST_LOW_SURROGATE) {
16354dc642cc1e188b9eeecadb648b9e8c610f4b857Fabrice Di Meglio                outAdvances[p++] = 0;
16454dc642cc1e188b9eeecadb648b9e8c610f4b857Fabrice Di Meglio            }
16554dc642cc1e188b9eeecadb648b9e8c610f4b857Fabrice Di Meglio#if DEBUG_ADVANCES
1665baa3a62a97544669fba6d65a11c07f252e654ddSteve Block            ALOGD("icu-adv = %f - total = %f", outAdvances[i], totalAdvance);
16754dc642cc1e188b9eeecadb648b9e8c610f4b857Fabrice Di Meglio#endif
16854dc642cc1e188b9eeecadb648b9e8c610f4b857Fabrice Di Meglio        }
16954dc642cc1e188b9eeecadb648b9e8c610f4b857Fabrice Di Meglio    } else {
17054dc642cc1e188b9eeecadb648b9e8c610f4b857Fabrice Di Meglio#if DEBUG_ADVANCES
1715baa3a62a97544669fba6d65a11c07f252e654ddSteve Block    ALOGD("ICU -- count=%d", count);
17254dc642cc1e188b9eeecadb648b9e8c610f4b857Fabrice Di Meglio#endif
17354dc642cc1e188b9eeecadb648b9e8c610f4b857Fabrice Di Meglio        for (size_t i = 0; i < count; i++) {
17454dc642cc1e188b9eeecadb648b9e8c610f4b857Fabrice Di Meglio            totalAdvance += outAdvances[i] = SkScalarToFloat(scalarArray[i]);
17554dc642cc1e188b9eeecadb648b9e8c610f4b857Fabrice Di Meglio#if DEBUG_ADVANCES
1765baa3a62a97544669fba6d65a11c07f252e654ddSteve Block            ALOGD("icu-adv = %f - total = %f", outAdvances[i], totalAdvance);
17754dc642cc1e188b9eeecadb648b9e8c610f4b857Fabrice Di Meglio#endif
17854dc642cc1e188b9eeecadb648b9e8c610f4b857Fabrice Di Meglio        }
17954dc642cc1e188b9eeecadb648b9e8c610f4b857Fabrice Di Meglio    }
18054dc642cc1e188b9eeecadb648b9e8c610f4b857Fabrice Di Meglio    *outTotalAdvance = totalAdvance;
18154dc642cc1e188b9eeecadb648b9e8c610f4b857Fabrice Di Meglio}
18254dc642cc1e188b9eeecadb648b9e8c610f4b857Fabrice Di Meglio
183f7cb1f75fdaedf996cab7c4690b080adc7bc5b97Doug Felt}
184