Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d313c665 authored by Fabrice Di Meglio's avatar Fabrice Di Meglio
Browse files

Add TextLayout Cache

- use GenerationCache for caching
- move GenerationCache.h from libs/hwui/utils to include/utils
- add #define for cache activation / deactivation

Change-Id: Ifaf519f0b5e33b087a453e4aa6430162d8438f20
parent 5fb008e3
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -112,6 +112,7 @@ LOCAL_SRC_FILES:= \
	android/graphics/Shader.cpp \
	android/graphics/SurfaceTexture.cpp \
	android/graphics/TextLayout.cpp \
	android/graphics/TextLayoutCache.cpp \
	android/graphics/Typeface.cpp \
	android/graphics/Utils.cpp \
	android/graphics/Xfermode.cpp \
+49 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2011 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.
 */

#ifndef ANDROID_RTL_PROPERTIES_H
#define ANDROID_RTL_PROPERTIES_H

#include <cutils/properties.h>
#include <stdlib.h>

namespace android {

/**
 * Debug level for app developers.
 */
#define RTL_PROPERTY_DEBUG "rtl.debug_level"

/**
 * Debug levels. Debug levels are used as flags.
 */
enum RtlDebugLevel {
    kRtlDebugDisabled = 0,
    kRtlDebugMemory = 1,
    kRtlDebugCaches = 2,
    kRtlDebugAllocations = 3
};

static RtlDebugLevel readRtlDebugLevel() {
    char property[PROPERTY_VALUE_MAX];
    if (property_get(RTL_PROPERTY_DEBUG, property, NULL) > 0) {
        return (RtlDebugLevel) atoi(property);
    }
    return kRtlDebugDisabled;
}

} // namespace android
#endif // ANDROID_RTL_PROPERTIES_H
+20 −81
Original line number Diff line number Diff line
@@ -15,6 +15,7 @@
 */

#include "TextLayout.h"
#include "TextLayoutCache.h"

#include <android_runtime/AndroidRuntime.h>

@@ -23,10 +24,12 @@
#include "unicode/ushape.h"
#include <utils/Log.h>

// Log debug messages from RTL related allocations
#define DEBUG_RTL_ALLOCATIONS 0

namespace android {

#if USE_TEXT_LAYOUT_CACHE
TextLayoutCache TextLayout::mCache;
#endif

// Returns true if we might need layout.  If bidiFlags force LTR, assume no layout, if
// bidiFlags indicate there probably is RTL, assume we do, otherwise scan the text
// looking for a character >= the first RTL character in unicode and assume we do if
@@ -64,10 +67,6 @@ int TextLayout::shapeRtlText(const jchar* context, jsize start, jsize count, jsi
    SkAutoSTMalloc<CHAR_BUFFER_SIZE, jchar> tempBuffer(contextCount);
    jchar* buffer = tempBuffer.get();

#if DEBUG_RTL_ALLOCATIONS
    LOGD("TextLayout::shapeRtlText - allocated buffer with size: %d", contextCount);
#endif

    // Use fixed length since we need to keep start and count valid
    u_shapeArabic(context, contextCount, buffer, contextCount,
                   U_SHAPE_LENGTH_FIXED_SPACES_NEAR |
@@ -166,11 +165,6 @@ bool TextLayout::prepareText(SkPaint *paint, const jchar* text, jsize len, jint
        if (!buffer) {
            return false;
        }

#if DEBUG_RTL_ALLOCATIONS
    LOGD("TextLayout::prepareText - allocated buffer with size: %d", len);
#endif

        UErrorCode status = U_ZERO_ERROR;
        len = layoutLine(text, len, bidiFlags, dir, buffer, status); // might change len, dir
        if (!U_SUCCESS(status)) {
@@ -178,7 +172,6 @@ bool TextLayout::prepareText(SkPaint *paint, const jchar* text, jsize len, jint
            free(buffer);
            return false; // can't render
        }

        workText = buffer; // use the shaped text
    }

@@ -265,71 +258,21 @@ void TextLayout::drawTextRun(SkPaint* paint, const jchar* chars,
void TextLayout::getTextRunAdvances(SkPaint* paint, const jchar* chars, jint start,
                                    jint count, jint contextCount, jint dirFlags,
                                    jfloat* resultAdvances, jfloat& resultTotalAdvance) {
    resultTotalAdvance = 0;

    SkAutoSTMalloc<CHAR_BUFFER_SIZE, jchar> tempBuffer(contextCount);
    jchar* buffer = tempBuffer.get();

#if DEBUG_RTL_ALLOCATIONS
    LOGD("TextLayout::getTextRunAdvances - allocated buffer with size: %d", contextCount);
#if USE_TEXT_LAYOUT_CACHE
    // Return advances from the cache. Compute them if needed
    mCache.getRunAdvances(paint, chars, start, count, contextCount,
            dirFlags, resultAdvances, &resultTotalAdvance);
#else
    // Compute advances and return them
    RunAdvanceDescription::computeAdvances(paint, chars, start, count, contextCount, dirFlags,
            resultAdvances, &resultTotalAdvance);
#endif

    SkScalar* scalarArray = (SkScalar*)resultAdvances;

    // this is where we'd call harfbuzz
    // for now we just use ushape.c

    int widths;
    const jchar* text;
    if (dirFlags & 0x1) { // rtl, call arabic shaping in case
        UErrorCode status = U_ZERO_ERROR;
        // Use fixed length since we need to keep start and count valid
        u_shapeArabic(chars, contextCount, buffer, contextCount,
                      U_SHAPE_LENGTH_FIXED_SPACES_NEAR |
                      U_SHAPE_TEXT_DIRECTION_LOGICAL | U_SHAPE_LETTERS_SHAPE |
                      U_SHAPE_X_LAMALEF_SUB_ALTERNATE, &status);
        // we shouldn't fail unless there's an out of memory condition,
        // in which case we're hosed anyway
        for (int i = start, e = i + count; i < e; ++i) {
          if (buffer[i] == UNICODE_NOT_A_CHAR) {
            buffer[i] = UNICODE_ZWSP; // zero-width-space for skia
          }
        }
        text = buffer + start;
        widths = paint->getTextWidths(text, count << 1, scalarArray);
    } else {
        text = chars + start;
        widths = paint->getTextWidths(text, count << 1, scalarArray);
    }

    if (widths < count) {
        // Skia operates on code points, not code units, so surrogate pairs return only
        // one value. Expand the result so we have one value per UTF-16 code unit.

        // Note, skia's getTextWidth gets confused if it encounters a surrogate pair,
        // leaving the remaining widths zero.  Not nice.
        for (int i = 0, p = 0; i < widths; ++i) {
            resultTotalAdvance += resultAdvances[p++] = SkScalarToFloat(scalarArray[i]);
            if (p < count &&
                    text[p] >= UNICODE_FIRST_LOW_SURROGATE &&
                    text[p] < UNICODE_FIRST_PRIVATE_USE &&
                    text[p-1] >= UNICODE_FIRST_HIGH_SURROGATE &&
                    text[p-1] < UNICODE_FIRST_LOW_SURROGATE) {
                resultAdvances[p++] = 0;
            }
        }
    } else {
        for (int i = 0; i < count; i++) {
            resultTotalAdvance += resultAdvances[i] = SkScalarToFloat(scalarArray[i]);
        }
    }
}


// Draws a paragraph of text on a single line, running bidi and shaping
void TextLayout::drawText(SkPaint* paint, const jchar* text, jsize len,
                          int bidiFlags, jfloat x, jfloat y, SkCanvas* canvas) {

    handleText(paint, text, len, bidiFlags, x, y, canvas, NULL);
}

@@ -353,10 +296,6 @@ void TextLayout::drawTextOnPath(SkPaint* paint, const jchar* text, int count,

    SkAutoSTMalloc<CHAR_BUFFER_SIZE, jchar> buffer(count);

#if DEBUG_RTL_ALLOCATIONS
    LOGD("TextLayout::drawTextOnPath - allocated buffer with size: %d", count);
#endif

    int dir = kDirection_LTR;
    UErrorCode status = U_ZERO_ERROR;
    count = layoutLine(text, count, bidiFlags, dir, buffer.get(), status);
+20 −8
Original line number Diff line number Diff line
@@ -20,6 +20,8 @@
#include "SkPaint.h"
#include "unicode/utypes.h"

#include "TextLayoutCache.h"

namespace android {

#define UNICODE_NOT_A_CHAR              0xffff
@@ -34,6 +36,11 @@ namespace android {
 */
#define CHAR_BUFFER_SIZE 80

/**
 * Turn on for using the Cache
 */
#define USE_TEXT_LAYOUT_CACHE 1

class TextLayout {
public:

@@ -78,6 +85,7 @@ public:
                               
    static bool prepareText(SkPaint* paint, const jchar* text, jsize len, jint bidiFlags,
        const jchar** outText, int32_t* outBytes, jchar** outBuffer);

    static bool prepareRtlTextRun(const jchar* context, jsize start, jsize& count,
        jsize contextCount, jchar* shaped);
        
@@ -90,6 +98,10 @@ private:
                           UErrorCode &status);
    static void handleText(SkPaint* paint, const jchar* text, jsize len,
                           int bidiFlags, jfloat x, jfloat y, SkCanvas* canvas, SkPath* path);

#if USE_TEXT_LAYOUT_CACHE
    static TextLayoutCache mCache;
#endif
};

}
Loading