1 /* 2 * Copyright (C) 2018 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.graphics.text; 18 19 import com.android.layoutlib.bridge.impl.DelegateManager; 20 import com.android.tools.layoutlib.annotations.LayoutlibDelegate; 21 22 import android.annotation.NonNull; 23 import android.graphics.BidiRenderer; 24 import android.graphics.Paint; 25 import android.graphics.Paint_Delegate; 26 import android.graphics.RectF; 27 import android.graphics.text.LineBreaker_Delegate.Builder; 28 import android.graphics.text.LineBreaker_Delegate.Run; 29 30 import java.util.ArrayList; 31 import java.util.Arrays; 32 33 /** 34 * Delegate that provides implementation for native methods in 35 * {@link android.graphics.text.MeasuredText} 36 * <p/> 37 * Through the layoutlib_create tool, selected methods of StaticLayout have been replaced 38 * by calls to methods of the same name in this delegate class. 39 * 40 */ 41 public class MeasuredText_Builder_Delegate { 42 // ---- Builder delegate manager ---- 43 protected static final DelegateManager<MeasuredText_Builder_Delegate> 44 sBuilderManager = 45 new DelegateManager<>(MeasuredText_Builder_Delegate.class); 46 47 protected final ArrayList<Run> mRuns = new ArrayList<>(); 48 49 @LayoutlibDelegate nInitBuilder()50 /*package*/ static long nInitBuilder() { 51 return sBuilderManager.addNewDelegate(new MeasuredText_Builder_Delegate()); 52 } 53 54 /** 55 * Apply style to make native measured text. 56 * 57 * @param nativeBuilderPtr The native NativeMeasuredParagraph builder pointer. 58 * @param paintPtr The native paint pointer to be applied. 59 * @param start The start offset in the copied buffer. 60 * @param end The end offset in the copied buffer. 61 * @param isRtl True if the text is RTL. 62 */ 63 @LayoutlibDelegate nAddStyleRun(long nativeBuilderPtr, long paintPtr, int start, int end, boolean isRtl)64 /*package*/ static void nAddStyleRun(long nativeBuilderPtr, long paintPtr, int start, 65 int end, boolean isRtl) { 66 MeasuredText_Builder_Delegate builder = sBuilderManager.getDelegate(nativeBuilderPtr); 67 if (builder == null) { 68 return; 69 } 70 builder.mRuns.add(new StyleRun(paintPtr, start, end, isRtl)); 71 } 72 73 /** 74 * Apply ReplacementRun to make native measured text. 75 * 76 * @param nativeBuilderPtr The native NativeMeasuredParagraph builder pointer. 77 * @param paintPtr The native paint pointer to be applied. 78 * @param start The start offset in the copied buffer. 79 * @param end The end offset in the copied buffer. 80 * @param width The width of the replacement. 81 */ 82 @LayoutlibDelegate nAddReplacementRun(long nativeBuilderPtr, long paintPtr, int start, int end, float width)83 /*package*/ static void nAddReplacementRun(long nativeBuilderPtr, long paintPtr, int start, 84 int end, float width) { 85 MeasuredText_Builder_Delegate builder = sBuilderManager.getDelegate(nativeBuilderPtr); 86 if (builder == null) { 87 return; 88 } 89 builder.mRuns.add(new ReplacementRun(start, end, width)); 90 } 91 92 @LayoutlibDelegate nBuildMeasuredText(long nativeBuilderPtr, long hintMtPtr, @NonNull char[] text, boolean computeHyphenation, boolean computeLayout)93 /*package*/ static long nBuildMeasuredText(long nativeBuilderPtr, long hintMtPtr, 94 @NonNull char[] text, boolean computeHyphenation, boolean computeLayout) { 95 MeasuredText_Delegate delegate = new MeasuredText_Delegate(); 96 delegate.mNativeBuilderPtr = nativeBuilderPtr; 97 return MeasuredText_Delegate.sManager.addNewDelegate(delegate); 98 } 99 100 @LayoutlibDelegate nFreeBuilder(long nativeBuilderPtr)101 /*package*/ static void nFreeBuilder(long nativeBuilderPtr) { 102 sBuilderManager.removeJavaReferenceFor(nativeBuilderPtr); 103 } 104 measureText(long nativePaint, char[] text, int index, int count, float[] widths, int bidiFlags)105 private static float measureText(long nativePaint, char[] text, int index, int count, 106 float[] widths, int bidiFlags) { 107 Paint_Delegate paint = Paint_Delegate.getDelegate(nativePaint); 108 RectF bounds = 109 new BidiRenderer(null, paint, text).renderText(index, index + count, bidiFlags, 110 widths, 0, false); 111 return bounds.right - bounds.left; 112 } 113 114 private static class StyleRun extends Run { 115 private final long mNativePaint; 116 private final boolean mIsRtl; 117 StyleRun(long nativePaint, int start, int end, boolean isRtl)118 private StyleRun(long nativePaint, int start, int end, boolean isRtl) { 119 super(start, end); 120 mNativePaint = nativePaint; 121 mIsRtl = isRtl; 122 } 123 124 @Override addTo(Builder builder)125 void addTo(Builder builder) { 126 int bidiFlags = mIsRtl ? Paint.BIDI_FORCE_RTL : Paint.BIDI_FORCE_LTR; 127 measureText(mNativePaint, builder.mText, mStart, mEnd - mStart, builder.mWidths, 128 bidiFlags); 129 } 130 } 131 132 private static class ReplacementRun extends Run { 133 private final float mWidth; 134 ReplacementRun(int start, int end, float width)135 private ReplacementRun(int start, int end, float width) { 136 super(start, end); 137 mWidth = width; 138 } 139 140 @Override addTo(Builder builder)141 void addTo(Builder builder) { 142 builder.mWidths[mStart] = mWidth; 143 Arrays.fill(builder.mWidths, mStart + 1, mEnd, 0.0f); 144 } 145 } 146 } 147