/*
 * Copyright (C) 2020 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.
 */

package android.graphics.text;

import android.annotation.NonNull;
import android.graphics.Paint;
import android.text.TextDirectionHeuristic;
import android.text.TextPaint;
import android.text.TextUtils;

import com.android.internal.util.Preconditions;

/**
 * Provides conversion from a text into glyph array.
 *
 * Text shaping is a preprocess for drawing text into canvas with glyphs. The glyph is a most
 * primitive unit of the text drawing, consist of glyph identifier in the font file and its position
 * and style. You can draw the shape result to Canvas by calling Canvas#drawGlyphs.
 *
 * For most of the use cases, {@link android.text.TextShaper} will provide text shaping
 * functionalities needed. {@link TextRunShaper} is a lower level API that is used by
 * {@link android.text.TextShaper}.
 *
 * @see TextRunShaper#shapeTextRun(CharSequence, int, int, int, int, float, float, boolean, Paint)
 * @see TextRunShaper#shapeTextRun(char[], int, int, int, int, float, float, boolean, Paint)
 * @see android.text.TextShaper#shapeText(CharSequence, int, int, TextDirectionHeuristic, TextPaint,
 * TextShaper.GlyphsConsumer)
 */
public class TextRunShaper {
    private TextRunShaper() {}  // Do not instantiate

    /**
     * Shape non-styled text.
     *
     * This function shapes the text of the given range under the context of given context range.
     * Some script, e.g. Arabic or Devanagari, changes letter shape based on its location or
     * surrounding characters.
     *
     * @param text a text buffer to be shaped
     * @param start a start index of shaping target in the buffer.
     * @param count a length of shaping target in the buffer.
     * @param contextStart a start index of context used for shaping in the buffer.
     * @param contextCount a length of context used for shaping in the buffer.
     * @param xOffset an additional amount of x offset of the result glyphs.
     * @param yOffset an additional amount of y offset of the result glyphs.
     * @param isRtl true if this text is shaped for RTL direction, false otherwise.
     * @param paint a paint used for shaping text.
     * @return a shape result.
     */
    @NonNull
    public static PositionedGlyphs shapeTextRun(
            @NonNull char[] text, int start, int count, int contextStart, int contextCount,
            float xOffset, float yOffset, boolean isRtl, @NonNull Paint paint) {
        Preconditions.checkNotNull(text);
        Preconditions.checkNotNull(paint);
        return new PositionedGlyphs(
                nativeShapeTextRun(text, start, count, contextStart, contextCount, isRtl,
                        paint.getNativeInstance()),
                xOffset, yOffset);
    }

    /**
     * Shape non-styled text.
     *
     * This function shapes the text of the given range under the context of given context range.
     * Some script, e.g. Arabic or Devanagari, changes letter shape based on its location or
     * surrounding characters.
     *
     * @param text a text buffer to be shaped. Any styled spans stored in this text are ignored.
     * @param start a start index of shaping target in the buffer.
     * @param count a length of shaping target in the buffer.
     * @param contextStart a start index of context used for shaping in the buffer.
     * @param contextCount a length of context used for shaping in the buffer.
     * @param xOffset an additional amount of x offset of the result glyphs.
     * @param yOffset an additional amount of y offset of the result glyphs.
     * @param isRtl true if this text is shaped for RTL direction, false otherwise.
     * @param paint a paint used for shaping text.
     * @return a shape result
     */
    @NonNull
    public static PositionedGlyphs shapeTextRun(
            @NonNull CharSequence text, int start, int count, int contextStart, int contextCount,
            float xOffset, float yOffset, boolean isRtl, @NonNull Paint paint) {
        Preconditions.checkNotNull(text);
        Preconditions.checkNotNull(paint);
        if (text instanceof String) {
            return new PositionedGlyphs(
                    nativeShapeTextRun(
                            (String) text, start, count, contextStart, contextCount, isRtl,
                            paint.getNativeInstance()),
                    xOffset, yOffset);
        } else {
            char[] buf = new char[contextCount];
            TextUtils.getChars(text, contextStart, contextStart + contextCount, buf, 0);
            return new PositionedGlyphs(
                    nativeShapeTextRun(
                            buf, start - contextStart, count,
                            0, contextCount, isRtl, paint.getNativeInstance()),
                    xOffset, yOffset);
        }
    }

    private static native long nativeShapeTextRun(
            char[] text, int start, int count, int contextStart, int contextCount,
            boolean isRtl, long nativePaint);

    private static native long nativeShapeTextRun(
            String text, int start, int count, int contextStart, int contextCount,
            boolean isRtl, long nativePaint);

}
