Loading core/java/android/text/Layout.java +13 −23 Original line number Diff line number Diff line Loading @@ -1806,6 +1806,7 @@ public abstract class Layout { } } /** * Fills in the specified Path with a representation of a cursor * at the specified offset. This will often be a vertical line Loading @@ -1821,7 +1822,6 @@ public abstract class Layout { boolean clamped = shouldClampCursor(line); float h1 = getPrimaryHorizontal(point, clamped) - 0.5f; float h2 = isLevelBoundary(point) ? getSecondaryHorizontal(point, clamped) - 0.5f : h1; int caps = TextKeyListener.getMetaState(editingBuffer, TextKeyListener.META_SHIFT_ON) | TextKeyListener.getMetaState(editingBuffer, TextKeyListener.META_SELECTING); Loading @@ -1839,34 +1839,24 @@ public abstract class Layout { if (h1 < 0.5f) h1 = 0.5f; if (h2 < 0.5f) h2 = 0.5f; if (Float.compare(h1, h2) == 0) { dest.moveTo(h1, top); dest.lineTo(h1, bottom); } else { dest.moveTo(h1, top); dest.lineTo(h1, (top + bottom) >> 1); dest.moveTo(h2, (top + bottom) >> 1); dest.lineTo(h2, bottom); } if (caps == 2) { dest.moveTo(h2, bottom); dest.lineTo(h2 - dist, bottom + dist); dest.lineTo(h2, bottom); dest.lineTo(h2 + dist, bottom + dist); dest.moveTo(h1, bottom); dest.lineTo(h1 - dist, bottom + dist); dest.lineTo(h1, bottom); dest.lineTo(h1 + dist, bottom + dist); } else if (caps == 1) { dest.moveTo(h2, bottom); dest.lineTo(h2 - dist, bottom + dist); dest.moveTo(h1, bottom); dest.lineTo(h1 - dist, bottom + dist); dest.moveTo(h2 - dist, bottom + dist - 0.5f); dest.lineTo(h2 + dist, bottom + dist - 0.5f); dest.moveTo(h1 - dist, bottom + dist - 0.5f); dest.lineTo(h1 + dist, bottom + dist - 0.5f); dest.moveTo(h2 + dist, bottom + dist); dest.lineTo(h2, bottom); dest.moveTo(h1 + dist, bottom + dist); dest.lineTo(h1, bottom); } if (fn == 2) { Loading core/tests/coretests/assets/fonts/1em_bidi_font.ttf 0 → 100644 +2.03 KiB File added.No diff preview for this file type. View file core/tests/coretests/src/android/text/LayoutBidiCursorPathTest.java 0 → 100644 +166 −0 Original line number Diff line number Diff line /* * Copyright (C) 2018 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.text; import static org.junit.Assert.assertArrayEquals; import android.content.Context; import android.graphics.Path; import android.graphics.Typeface; import android.platform.test.annotations.Presubmit; import android.support.test.InstrumentationRegistry; import android.support.test.filters.SmallTest; import android.support.test.runner.AndroidJUnit4; import android.text.method.MetaKeyKeyListener; import android.view.KeyEvent; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @Presubmit @SmallTest @RunWith(AndroidJUnit4.class) public class LayoutBidiCursorPathTest { private static final float BIDI_TEXT_SIZE = 12f; private static final String LTR_TEXT = "hello"; private static final String RTL_TEXT = "مرحبا"; private SpannableStringBuilder mBidiText; private TextPaint mTextPaint; @Before public void setup() { mBidiText = new SpannableStringBuilder(LTR_TEXT + RTL_TEXT); final Context context = InstrumentationRegistry.getTargetContext(); mTextPaint = new TextPaint(); mTextPaint.setTypeface( Typeface.createFromAsset(context.getAssets(), "fonts/1em_bidi_font.ttf")); mTextPaint.setTextSize(BIDI_TEXT_SIZE); } @Test public void testGetCursorPathSegments() { // Setup layout and Act. final Path actualPath = new Path(); setupLayoutAndGetCursorPath(actualPath); // Expected path. final float h1 = BIDI_TEXT_SIZE * LTR_TEXT.length() - 0.5f; final int top = 0; // sTypoLineGap is set to 1/5 of the Height in font metrics of the font file used here. final int bottom = Math.round(BIDI_TEXT_SIZE + BIDI_TEXT_SIZE / 5f); final Path expectedPath = new Path(); expectedPath.moveTo(h1, top); expectedPath.lineTo(h1, bottom); // Assert. assertArrayEquals(expectedPath.approximate(0f), actualPath.approximate(0f), 0f); } @Test public void testGetCursorPath_whenShiftIsPressed() { // When shift is pressed a triangle is drawn at the bottom quarter of the cursor. // Set up key. final MetaKeyKeyListener metaKeyKeyListener = new MetaKeyKeyListener() {}; metaKeyKeyListener .onKeyDown(null /*view*/, mBidiText, KeyEvent.KEYCODE_SHIFT_RIGHT, null /*keyEvent*/); // Setup layout and Act. final Path actualPath = new Path(); setupLayoutAndGetCursorPath(actualPath); // Expected path. final float h1 = BIDI_TEXT_SIZE * LTR_TEXT.length() - 0.5f; final int top = 0; // sTypoLineGap is set to 1/5 of the Height in font metrics of the font file used here. int bottom = Math.round(BIDI_TEXT_SIZE + BIDI_TEXT_SIZE / 5f); // Draw a triangle at the bottom quarter of the cursor, thus cut the cursor to its 3/4 // length. final int dist = (bottom - top) / 4; bottom -= dist; final Path expectedPath = new Path(); expectedPath.moveTo(h1, top); expectedPath.lineTo(h1, bottom); expectedPath.moveTo(h1, bottom); expectedPath.lineTo(h1 - dist, bottom + dist); expectedPath.moveTo(h1 - dist, bottom + dist - 0.5f); expectedPath.lineTo(h1 + dist, bottom + dist - 0.5f); expectedPath.moveTo(h1 + dist, bottom + dist); expectedPath.lineTo(h1, bottom); // Assert. assertArrayEquals(expectedPath.approximate(0f), actualPath.approximate(0f), 0f); } @Test public void testGetCursorPath_whenAltIsPressed() { // When alt is pressed a triangle is drawn at the top quarter of the cursor. // Set up key. final MetaKeyKeyListener metaKeyKeyListener = new MetaKeyKeyListener() {}; metaKeyKeyListener .onKeyDown(null /*view*/, mBidiText, KeyEvent.KEYCODE_ALT_RIGHT, null /*keyEvent*/); // Setup layout and Act. final Path actualPath = new Path(); setupLayoutAndGetCursorPath(actualPath); // Expected path. final float h1 = BIDI_TEXT_SIZE * LTR_TEXT.length() - 0.5f; int top = 0; // sTypoLineGap is set to 1/5 of the Height in font metrics of the font file used here. final int bottom = Math.round(BIDI_TEXT_SIZE + BIDI_TEXT_SIZE / 5f); // Draw a triangle at the top quarter of the cursor, thus cut the cursor to its 3/4 length. final int dist = (bottom - top) / 4; top += dist; final Path expectedPath = new Path(); expectedPath.moveTo(h1, top); expectedPath.lineTo(h1, bottom); expectedPath.moveTo(h1, top); expectedPath.lineTo(h1 - dist, top - dist); expectedPath.moveTo(h1 - dist, top - dist + 0.5f); expectedPath.lineTo(h1 + dist, top - dist + 0.5f); expectedPath.moveTo(h1 + dist, top - dist); expectedPath.lineTo(h1, top); // Assert. assertArrayEquals(expectedPath.approximate(0f), actualPath.approximate(0f), 0f); } private void setupLayoutAndGetCursorPath(Path path) { final Layout layout = StaticLayout.Builder.obtain( mBidiText, 0, mBidiText.length(), mTextPaint, Integer.MAX_VALUE) .setIncludePad(false) .build(); layout.getCursorPath(LTR_TEXT.length(), path, mBidiText); } } Loading
core/java/android/text/Layout.java +13 −23 Original line number Diff line number Diff line Loading @@ -1806,6 +1806,7 @@ public abstract class Layout { } } /** * Fills in the specified Path with a representation of a cursor * at the specified offset. This will often be a vertical line Loading @@ -1821,7 +1822,6 @@ public abstract class Layout { boolean clamped = shouldClampCursor(line); float h1 = getPrimaryHorizontal(point, clamped) - 0.5f; float h2 = isLevelBoundary(point) ? getSecondaryHorizontal(point, clamped) - 0.5f : h1; int caps = TextKeyListener.getMetaState(editingBuffer, TextKeyListener.META_SHIFT_ON) | TextKeyListener.getMetaState(editingBuffer, TextKeyListener.META_SELECTING); Loading @@ -1839,34 +1839,24 @@ public abstract class Layout { if (h1 < 0.5f) h1 = 0.5f; if (h2 < 0.5f) h2 = 0.5f; if (Float.compare(h1, h2) == 0) { dest.moveTo(h1, top); dest.lineTo(h1, bottom); } else { dest.moveTo(h1, top); dest.lineTo(h1, (top + bottom) >> 1); dest.moveTo(h2, (top + bottom) >> 1); dest.lineTo(h2, bottom); } if (caps == 2) { dest.moveTo(h2, bottom); dest.lineTo(h2 - dist, bottom + dist); dest.lineTo(h2, bottom); dest.lineTo(h2 + dist, bottom + dist); dest.moveTo(h1, bottom); dest.lineTo(h1 - dist, bottom + dist); dest.lineTo(h1, bottom); dest.lineTo(h1 + dist, bottom + dist); } else if (caps == 1) { dest.moveTo(h2, bottom); dest.lineTo(h2 - dist, bottom + dist); dest.moveTo(h1, bottom); dest.lineTo(h1 - dist, bottom + dist); dest.moveTo(h2 - dist, bottom + dist - 0.5f); dest.lineTo(h2 + dist, bottom + dist - 0.5f); dest.moveTo(h1 - dist, bottom + dist - 0.5f); dest.lineTo(h1 + dist, bottom + dist - 0.5f); dest.moveTo(h2 + dist, bottom + dist); dest.lineTo(h2, bottom); dest.moveTo(h1 + dist, bottom + dist); dest.lineTo(h1, bottom); } if (fn == 2) { Loading
core/tests/coretests/assets/fonts/1em_bidi_font.ttf 0 → 100644 +2.03 KiB File added.No diff preview for this file type. View file
core/tests/coretests/src/android/text/LayoutBidiCursorPathTest.java 0 → 100644 +166 −0 Original line number Diff line number Diff line /* * Copyright (C) 2018 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.text; import static org.junit.Assert.assertArrayEquals; import android.content.Context; import android.graphics.Path; import android.graphics.Typeface; import android.platform.test.annotations.Presubmit; import android.support.test.InstrumentationRegistry; import android.support.test.filters.SmallTest; import android.support.test.runner.AndroidJUnit4; import android.text.method.MetaKeyKeyListener; import android.view.KeyEvent; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @Presubmit @SmallTest @RunWith(AndroidJUnit4.class) public class LayoutBidiCursorPathTest { private static final float BIDI_TEXT_SIZE = 12f; private static final String LTR_TEXT = "hello"; private static final String RTL_TEXT = "مرحبا"; private SpannableStringBuilder mBidiText; private TextPaint mTextPaint; @Before public void setup() { mBidiText = new SpannableStringBuilder(LTR_TEXT + RTL_TEXT); final Context context = InstrumentationRegistry.getTargetContext(); mTextPaint = new TextPaint(); mTextPaint.setTypeface( Typeface.createFromAsset(context.getAssets(), "fonts/1em_bidi_font.ttf")); mTextPaint.setTextSize(BIDI_TEXT_SIZE); } @Test public void testGetCursorPathSegments() { // Setup layout and Act. final Path actualPath = new Path(); setupLayoutAndGetCursorPath(actualPath); // Expected path. final float h1 = BIDI_TEXT_SIZE * LTR_TEXT.length() - 0.5f; final int top = 0; // sTypoLineGap is set to 1/5 of the Height in font metrics of the font file used here. final int bottom = Math.round(BIDI_TEXT_SIZE + BIDI_TEXT_SIZE / 5f); final Path expectedPath = new Path(); expectedPath.moveTo(h1, top); expectedPath.lineTo(h1, bottom); // Assert. assertArrayEquals(expectedPath.approximate(0f), actualPath.approximate(0f), 0f); } @Test public void testGetCursorPath_whenShiftIsPressed() { // When shift is pressed a triangle is drawn at the bottom quarter of the cursor. // Set up key. final MetaKeyKeyListener metaKeyKeyListener = new MetaKeyKeyListener() {}; metaKeyKeyListener .onKeyDown(null /*view*/, mBidiText, KeyEvent.KEYCODE_SHIFT_RIGHT, null /*keyEvent*/); // Setup layout and Act. final Path actualPath = new Path(); setupLayoutAndGetCursorPath(actualPath); // Expected path. final float h1 = BIDI_TEXT_SIZE * LTR_TEXT.length() - 0.5f; final int top = 0; // sTypoLineGap is set to 1/5 of the Height in font metrics of the font file used here. int bottom = Math.round(BIDI_TEXT_SIZE + BIDI_TEXT_SIZE / 5f); // Draw a triangle at the bottom quarter of the cursor, thus cut the cursor to its 3/4 // length. final int dist = (bottom - top) / 4; bottom -= dist; final Path expectedPath = new Path(); expectedPath.moveTo(h1, top); expectedPath.lineTo(h1, bottom); expectedPath.moveTo(h1, bottom); expectedPath.lineTo(h1 - dist, bottom + dist); expectedPath.moveTo(h1 - dist, bottom + dist - 0.5f); expectedPath.lineTo(h1 + dist, bottom + dist - 0.5f); expectedPath.moveTo(h1 + dist, bottom + dist); expectedPath.lineTo(h1, bottom); // Assert. assertArrayEquals(expectedPath.approximate(0f), actualPath.approximate(0f), 0f); } @Test public void testGetCursorPath_whenAltIsPressed() { // When alt is pressed a triangle is drawn at the top quarter of the cursor. // Set up key. final MetaKeyKeyListener metaKeyKeyListener = new MetaKeyKeyListener() {}; metaKeyKeyListener .onKeyDown(null /*view*/, mBidiText, KeyEvent.KEYCODE_ALT_RIGHT, null /*keyEvent*/); // Setup layout and Act. final Path actualPath = new Path(); setupLayoutAndGetCursorPath(actualPath); // Expected path. final float h1 = BIDI_TEXT_SIZE * LTR_TEXT.length() - 0.5f; int top = 0; // sTypoLineGap is set to 1/5 of the Height in font metrics of the font file used here. final int bottom = Math.round(BIDI_TEXT_SIZE + BIDI_TEXT_SIZE / 5f); // Draw a triangle at the top quarter of the cursor, thus cut the cursor to its 3/4 length. final int dist = (bottom - top) / 4; top += dist; final Path expectedPath = new Path(); expectedPath.moveTo(h1, top); expectedPath.lineTo(h1, bottom); expectedPath.moveTo(h1, top); expectedPath.lineTo(h1 - dist, top - dist); expectedPath.moveTo(h1 - dist, top - dist + 0.5f); expectedPath.lineTo(h1 + dist, top - dist + 0.5f); expectedPath.moveTo(h1 + dist, top - dist); expectedPath.lineTo(h1, top); // Assert. assertArrayEquals(expectedPath.approximate(0f), actualPath.approximate(0f), 0f); } private void setupLayoutAndGetCursorPath(Path path) { final Layout layout = StaticLayout.Builder.obtain( mBidiText, 0, mBidiText.length(), mTextPaint, Integer.MAX_VALUE) .setIncludePad(false) .build(); layout.getCursorPath(LTR_TEXT.length(), path, mBidiText); } }