diff options
59 files changed, 979 insertions, 435 deletions
diff --git a/java/res/anim/key_preview_dismiss_holo.xml b/java/res/anim/key_preview_dismiss_holo.xml new file mode 100644 index 000000000..0bf725435 --- /dev/null +++ b/java/res/anim/key_preview_dismiss_holo.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** +** Copyright 2014, 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. +*/ +--> + +<set xmlns:android="http://schemas.android.com/apk/res/android"> + <objectAnimator + android:propertyName="scaleX" + android:duration="53" + android:valueFrom="1.00" + android:valueTo="0.94" /> + <objectAnimator + android:propertyName="scaleY" + android:duration="53" + android:valueFrom="1.00" + android:valueTo="0.94" /> +</set> diff --git a/java/res/anim/key_preview_dismiss_lxx.xml b/java/res/anim/key_preview_dismiss_lxx.xml new file mode 100644 index 000000000..326e534ec --- /dev/null +++ b/java/res/anim/key_preview_dismiss_lxx.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** +** Copyright 2014, 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. +*/ +--> + +<set xmlns:android="http://schemas.android.com/apk/res/android"> + <objectAnimator + android:propertyName="scaleX" + android:duration="53" + android:valueFrom="1.00" + android:valueTo="1.00" /> + <objectAnimator + android:propertyName="scaleY" + android:duration="53" + android:valueFrom="1.00" + android:valueTo="0.94" /> +</set> diff --git a/java/res/anim/key_preview_show_up_holo.xml b/java/res/anim/key_preview_show_up_holo.xml new file mode 100644 index 000000000..ad2e413a1 --- /dev/null +++ b/java/res/anim/key_preview_show_up_holo.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** +** Copyright 2014, 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. +*/ +--> + +<set xmlns:android="http://schemas.android.com/apk/res/android"> + <objectAnimator + android:propertyName="scaleX" + android:duration="17" + android:valueFrom="0.98" + android:valueTo="1.00" /> + <objectAnimator + android:propertyName="scaleY" + android:duration="17" + android:valueFrom="0.98" + android:valueTo="1.00" /> +</set> diff --git a/java/res/anim/key_preview_show_up_lxx.xml b/java/res/anim/key_preview_show_up_lxx.xml new file mode 100644 index 000000000..f5003499c --- /dev/null +++ b/java/res/anim/key_preview_show_up_lxx.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** +** Copyright 2014, 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. +*/ +--> + +<set xmlns:android="http://schemas.android.com/apk/res/android"> + <objectAnimator + android:propertyName="scaleX" + android:duration="17" + android:valueFrom="1.00" + android:valueTo="1.00" /> + <objectAnimator + android:propertyName="scaleY" + android:duration="17" + android:valueFrom="0.98" + android:valueTo="1.00" /> +</set> diff --git a/java/res/drawable/btn_keyboard_key_popup_lxx_light.xml b/java/res/drawable/btn_keyboard_key_popup_lxx_light.xml new file mode 100644 index 000000000..d6cd2b831 --- /dev/null +++ b/java/res/drawable/btn_keyboard_key_popup_lxx_light.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2014 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. +--> + +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:state_pressed="true" + android:drawable="@drawable/btn_keyboard_key_popup_selected_lxx_light" /> + <item android:drawable="@android:color/transparent" /> +</selector> diff --git a/java/res/values-ne-rNP/strings.xml b/java/res/values-ne-rNP/strings.xml index c7c95aeb2..1764e7699 100644 --- a/java/res/values-ne-rNP/strings.xml +++ b/java/res/values-ne-rNP/strings.xml @@ -80,7 +80,7 @@ <string name="help_and_feedback" msgid="5328219371839879161">"मद्दत र प्रतिक्रिया"</string> <string name="select_language" msgid="3693815588777926848">"इनपुट भाषाहरू"</string> <string name="hint_add_to_dictionary" msgid="573678656946085380">"बचत गर्न पुनः छुनुहोस्"</string> - <string name="hint_add_to_dictionary_without_word" msgid="3040385779511255101">"बचत गर्न यहाँ छुनुहोस्"</string> + <string name="hint_add_to_dictionary_without_word" msgid="3040385779511255101">"सुरक्षित गर्न यहाँ छुनुहोस्"</string> <string name="has_dictionary" msgid="6071847973466625007">"उपलब्ध शब्दकोश"</string> <string name="keyboard_layout" msgid="8451164783510487501">"किबोर्ड थिम"</string> <string name="subtype_en_GB" msgid="88170601942311355">"अंग्रेजी (युके)"</string> diff --git a/java/res/values-ta-rIN/strings-talkback-descriptions.xml b/java/res/values-ta-rIN/strings-talkback-descriptions.xml index 911e1a596..0ef07207a 100644 --- a/java/res/values-ta-rIN/strings-talkback-descriptions.xml +++ b/java/res/values-ta-rIN/strings-talkback-descriptions.xml @@ -58,7 +58,7 @@ <string name="keyboard_mode_date" msgid="6597407244976713364">"தேதி"</string> <string name="keyboard_mode_date_time" msgid="3642804408726668808">"தேதி மற்றும் நேரம்"</string> <string name="keyboard_mode_email" msgid="1239682082047693644">"மின்னஞ்சல்"</string> - <string name="keyboard_mode_im" msgid="3812086215529493501">"செய்தியிடல்"</string> + <string name="keyboard_mode_im" msgid="3812086215529493501">"மெசேஜ்"</string> <string name="keyboard_mode_number" msgid="5395042245837996809">"எண்"</string> <string name="keyboard_mode_phone" msgid="2486230278064523665">"ஃபோன்"</string> <string name="keyboard_mode_text" msgid="9138789594969187494">"உரை"</string> diff --git a/java/res/values/attrs.xml b/java/res/values/attrs.xml index e89912a9d..c756f8c34 100644 --- a/java/res/values/attrs.xml +++ b/java/res/values/attrs.xml @@ -113,6 +113,10 @@ <!-- TODO: consolidate key preview linger timeout with the key preview animation parameters. --> <!-- Delay after key releasing and key press feedback dismissing in millisecond --> <attr name="keyPreviewLingerTimeout" format="integer" /> + <!-- Key preview show up animator --> + <attr name="keyPreviewShowUpAnimator" format="reference" /> + <!-- Key preview dismiss animator --> + <attr name="keyPreviewDismissAnimator" format="reference" /> <!-- Layout resource for more keys keyboard --> <attr name="moreKeysKeyboardLayout" format="reference" /> <attr name="backgroundDimAlpha" format="integer" /> diff --git a/java/res/values/donottranslate-text-decorator.xml b/java/res/values/donottranslate-text-decorator.xml index 9c39a4689..a20034930 100644 --- a/java/res/values/donottranslate-text-decorator.xml +++ b/java/res/values/donottranslate-text-decorator.xml @@ -31,7 +31,7 @@ <!-- If true, the commit/add-to-text indicator will be suppressed when the word isn't going to trigger auto-correction. --> - <bool name="text_decorator_only_for_auto_correction">false</bool> + <bool name="text_decorator_only_for_auto_correction">true</bool> <!-- If true, the commit/add-to-text indicator will be suppressed when the word is already in the dictionary. --> @@ -61,18 +61,24 @@ <!-- Coordinates of the closed path to be used to render the commit indicator. The format is: X[0], Y[0], X[1], Y[1], ..., X[N-1], Y[N-1] --> <integer-array name="text_decorator_commit_indicator_path"> - <item>180</item> + <item>240</item> + <item>80</item> + <item>212</item> + <item>108</item> + <item>323</item> + <item>220</item> + <item>80</item> + <item>220</item> + <item>80</item> + <item>260</item> <item>323</item> - <item>97</item> + <item>260</item> + <item>212</item> + <item>372</item> + <item>240</item> + <item>400</item> + <item>400</item> <item>240</item> - <item>68</item> - <item>268</item> - <item>180</item> - <item>380</item> - <item>420</item> - <item>140</item> - <item>392</item> - <item>112</item> </integer-array> <!-- Background color to be used to highlight the target text when the add-to-dictionary diff --git a/java/res/values/strings.xml b/java/res/values/strings.xml index 2a6495a57..414820be9 100644 --- a/java/res/values/strings.xml +++ b/java/res/values/strings.xml @@ -336,14 +336,20 @@ mobile devices. [CHAR LIMIT=25] --> <string name="prefs_keypress_vibration_duration_settings">Keypress vibration duration</string> <!-- Title of the settings for keypress sound volume [CHAR LIMIT=35] --> <string name="prefs_keypress_sound_volume_settings">Keypress sound volume</string> + <!-- Title of the settings for customize key popup animation parameters [CHAR LIMIT=35] --> + <string name="prefs_customize_key_preview_animation">Customize key preview animation</string> <!-- Title of the settings for key popup show up animation duration (in milliseconds) [CHAR LIMIT=35] --> <string name="prefs_key_popup_show_up_duration_settings" translatable="false">Key popup show up duration</string> <!-- Title of the settings for key popup dismiss animation duration (in milliseconds) [CHAR LIMIT=35] --> <string name="prefs_key_popup_dismiss_duration_settings" translatable="false">Key popup dismiss duration</string> - <!-- Title of the settings for key popup show up animation start scale (in percentile) [CHAR LIMIT=35] --> - <string name="prefs_key_popup_show_up_start_scale_settings" translatable="false">Key popup show up start scale</string> - <!-- Title of the settings for key popup dismiss animation end scale (in percentile) [CHAR LIMIT=35] --> - <string name="prefs_key_popup_dismiss_end_scale_settings" translatable="false">Key popup dismiss end scale</string> + <!-- Title of the settings for key popup show up animation start X-scale (in percentile) [CHAR LIMIT=35] --> + <string name="prefs_key_popup_show_up_start_x_scale_settings" translatable="false">Key popup show up start X scale</string> + <!-- Title of the settings for key popup show up animation start Y-scale (in percentile) [CHAR LIMIT=35] --> + <string name="prefs_key_popup_show_up_start_y_scale_settings" translatable="false">Key popup show up start Y scale</string> + <!-- Title of the settings for key popup dismiss animation end X-scale (in percentile) [CHAR LIMIT=35] --> + <string name="prefs_key_popup_dismiss_end_x_scale_settings" translatable="false">Key popup dismiss end X scale</string> + <!-- Title of the settings for key popup dismiss animation end Y-scale (in percentile) [CHAR LIMIT=35] --> + <string name="prefs_key_popup_dismiss_end_y_scale_settings" translatable="false">Key popup dismiss end Y scale</string> <!-- Title of the settings for reading an external dictionary file --> <string name="prefs_read_external_dictionary">Read external dictionary file</string> <!-- Message to show when there are no files to install as an external dictionary [CHAR LIMIT=100] --> diff --git a/java/res/values/themes-ics.xml b/java/res/values/themes-ics.xml index 6fddcb905..051489e11 100644 --- a/java/res/values/themes-ics.xml +++ b/java/res/values/themes-ics.xml @@ -59,6 +59,8 @@ > <item name="keyPreviewBackground">@drawable/keyboard_key_feedback_ics</item> <item name="keyPreviewOffset">@dimen/config_key_preview_offset_holo</item> + <item name="keyPreviewShowUpAnimator">@anim/key_preview_show_up_holo</item> + <item name="keyPreviewDismissAnimator">@anim/key_preview_dismiss_holo</item> <item name="gestureFloatingPreviewTextColor">@color/highlight_color_ics</item> <item name="gestureFloatingPreviewColor">@color/gesture_floating_preview_color_holo</item> <item name="gestureTrailColor">@color/highlight_color_ics</item> diff --git a/java/res/values/themes-klp.xml b/java/res/values/themes-klp.xml index c9b83316c..a853ed9dd 100644 --- a/java/res/values/themes-klp.xml +++ b/java/res/values/themes-klp.xml @@ -59,6 +59,8 @@ > <item name="keyPreviewBackground">@drawable/keyboard_key_feedback_klp</item> <item name="keyPreviewOffset">@dimen/config_key_preview_offset_holo</item> + <item name="keyPreviewShowUpAnimator">@anim/key_preview_show_up_holo</item> + <item name="keyPreviewDismissAnimator">@anim/key_preview_dismiss_holo</item> <item name="gestureFloatingPreviewTextColor">@color/highlight_color_klp</item> <item name="gestureFloatingPreviewColor">@color/gesture_floating_preview_color_holo</item> <item name="gestureTrailColor">@color/highlight_color_klp</item> diff --git a/java/res/values/themes-lxx-dark.xml b/java/res/values/themes-lxx-dark.xml index 6afbd9b15..2aaee1360 100644 --- a/java/res/values/themes-lxx-dark.xml +++ b/java/res/values/themes-lxx-dark.xml @@ -59,6 +59,8 @@ > <item name="keyPreviewBackground">@drawable/keyboard_key_feedback_lxx_dark</item> <item name="keyPreviewOffset">@dimen/config_key_preview_offset_holo</item> + <item name="keyPreviewShowUpAnimator">@anim/key_preview_show_up_lxx</item> + <item name="keyPreviewDismissAnimator">@anim/key_preview_dismiss_lxx</item> <item name="gestureFloatingPreviewTextColor">@color/auto_correct_color_lxx_dark</item> <item name="gestureFloatingPreviewColor">@color/gesture_floating_preview_color_lxx_dark</item> <item name="gestureTrailColor">@color/gesture_trail_color_lxx_dark</item> diff --git a/java/res/values/themes-lxx-light.xml b/java/res/values/themes-lxx-light.xml index b3ced80a1..e7a6f5894 100644 --- a/java/res/values/themes-lxx-light.xml +++ b/java/res/values/themes-lxx-light.xml @@ -59,6 +59,8 @@ > <item name="keyPreviewBackground">@drawable/keyboard_key_feedback_lxx_light</item> <item name="keyPreviewOffset">@dimen/config_key_preview_offset_holo</item> + <item name="keyPreviewShowUpAnimator">@anim/key_preview_show_up_lxx</item> + <item name="keyPreviewDismissAnimator">@anim/key_preview_dismiss_lxx</item> <item name="gestureFloatingPreviewTextColor">@color/auto_correct_color_lxx_light</item> <item name="gestureFloatingPreviewColor">@color/gesture_floating_preview_color_lxx_light</item> <item name="gestureTrailColor">@color/gesture_trail_color_lxx_light</item> @@ -98,8 +100,7 @@ parent="KeyboardView.LXX_Light" > <item name="android:background">@drawable/keyboard_popup_panel_background_lxx_light</item> - <!-- Reuse KLP key background --> - <item name="keyBackground">@drawable/btn_keyboard_key_popup_klp</item> + <item name="keyBackground">@drawable/btn_keyboard_key_popup_lxx_light</item> <item name="keyTypeface">normal</item> <item name="verticalCorrection">@dimen/config_more_keys_keyboard_vertical_correction_holo</item> </style> diff --git a/java/res/xml/prefs_screen_debug.xml b/java/res/xml/prefs_screen_debug.xml index 965369a90..e0f3501fd 100644 --- a/java/res/xml/prefs_screen_debug.xml +++ b/java/res/xml/prefs_screen_debug.xml @@ -52,19 +52,38 @@ latin:minValue="@integer/config_min_longpress_timeout" latin:maxValue="@integer/config_max_longpress_timeout" latin:stepValue="@integer/config_longpress_timeout_step" /> + <CheckBoxPreference + android:key="pref_has_custom_key_preview_animation_params" + android:title="@string/prefs_customize_key_preview_animation" + android:defaultValue="false" + android:persistent="true" /> + <com.android.inputmethod.latin.settings.SeekBarDialogPreference + android:dependency="pref_customize_key_preview_animation" + android:key="pref_key_preview_show_up_start_x_scale" + android:title="@string/prefs_key_popup_show_up_start_x_scale_settings" + latin:maxValue="100" /> <!-- percent --> + <com.android.inputmethod.latin.settings.SeekBarDialogPreference + android:dependency="pref_customize_key_preview_animation" + android:key="pref_key_preview_show_up_start_y_scale" + android:title="@string/prefs_key_popup_show_up_start_y_scale_settings" + latin:maxValue="100" /> <!-- percent --> <com.android.inputmethod.latin.settings.SeekBarDialogPreference - android:key="pref_key_preview_show_up_start_scale" - android:title="@string/prefs_key_popup_show_up_start_scale_settings" + android:dependency="pref_customize_key_preview_animation" + android:key="pref_key_preview_dismiss_end_x_scale" + android:title="@string/prefs_key_popup_dismiss_end_x_scale_settings" latin:maxValue="100" /> <!-- percent --> <com.android.inputmethod.latin.settings.SeekBarDialogPreference - android:key="pref_key_preview_dismiss_end_scale" - android:title="@string/prefs_key_popup_dismiss_end_scale_settings" + android:dependency="pref_customize_key_preview_animation" + android:key="pref_key_preview_dismiss_end_y_scale" + android:title="@string/prefs_key_popup_dismiss_end_y_scale_settings" latin:maxValue="100" /> <!-- percent --> <com.android.inputmethod.latin.settings.SeekBarDialogPreference + android:dependency="pref_customize_key_preview_animation" android:key="pref_key_preview_show_up_duration" android:title="@string/prefs_key_popup_show_up_duration_settings" latin:maxValue="100" /> <!-- milliseconds --> <com.android.inputmethod.latin.settings.SeekBarDialogPreference + android:dependency="pref_customize_key_preview_animation" android:key="pref_key_preview_dismiss_duration" android:title="@string/prefs_key_popup_dismiss_duration_settings" latin:maxValue="100" /> <!-- milliseconds --> diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java index 389d58a30..91d703330 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java +++ b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java @@ -154,9 +154,12 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions { mCurrentSettingsValues.mKeyPreviewPopupOn, mCurrentSettingsValues.mKeyPreviewPopupDismissDelay); keyboardView.setKeyPreviewAnimationParams( - mCurrentSettingsValues.mKeyPreviewShowUpStartScale, + mCurrentSettingsValues.mHasCustomKeyPreviewAnimationParams, + mCurrentSettingsValues.mKeyPreviewShowUpStartXScale, + mCurrentSettingsValues.mKeyPreviewShowUpStartYScale, mCurrentSettingsValues.mKeyPreviewShowUpDuration, - mCurrentSettingsValues.mKeyPreviewDismissEndScale, + mCurrentSettingsValues.mKeyPreviewDismissEndXScale, + mCurrentSettingsValues.mKeyPreviewDismissEndYScale, mCurrentSettingsValues.mKeyPreviewDismissDuration); keyboardView.updateShortcutKey(mSubtypeSwitcher.isShortcutImeReady()); final boolean subtypeChanged = (oldKeyboard == null) diff --git a/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java b/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java index 847d90711..d2f3e9714 100644 --- a/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java +++ b/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java @@ -85,6 +85,8 @@ import java.util.WeakHashMap; * @attr ref R.styleable#MainKeyboardView_keyPreviewOffset * @attr ref R.styleable#MainKeyboardView_keyPreviewHeight * @attr ref R.styleable#MainKeyboardView_keyPreviewLingerTimeout + * @attr ref R.styleable#MainKeyboardView_keyPreviewShowUpAnimator + * @attr ref R.styleable#MainKeyboardView_keyPreviewDismissAnimator * @attr ref R.styleable#MainKeyboardView_moreKeysKeyboardLayout * @attr ref R.styleable#MainKeyboardView_backgroundDimAlpha * @attr ref R.styleable#MainKeyboardView_showMoreKeysKeyboardAtTouchPoint @@ -390,20 +392,34 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack } /** - * Enables or disables the key feedback popup. This is a popup that shows a magnified + * Enables or disables the key preview popup. This is a popup that shows a magnified * version of the depressed key. By default the preview is enabled. * @param previewEnabled whether or not to enable the key feedback preview * @param delay the delay after which the preview is dismissed - * @see #isKeyPreviewPopupEnabled() */ public void setKeyPreviewPopupEnabled(final boolean previewEnabled, final int delay) { mKeyPreviewDrawParams.setPopupEnabled(previewEnabled, delay); } - public void setKeyPreviewAnimationParams(final float showUpStartScale, final int showUpDuration, - final float dismissEndScale, final int dismissDuration) { - mKeyPreviewDrawParams.setAnimationParams( - showUpStartScale, showUpDuration, dismissEndScale, dismissDuration); + /** + * Enables or disables the key preview popup animations and set animations' parameters. + * + * @param hasCustomAnimationParams false to use the default key preview popup animations + * specified by keyPreviewShowUpAnimator and keyPreviewDismissAnimator attributes. + * true to override the default animations with the specified parameters. + * @param showUpStartXScale from this x-scale the show up animation will start. + * @param showUpStartYScale from this y-scale the show up animation will start. + * @param showUpDuration the duration of the show up animation in milliseconds. + * @param dismissEndXScale to this x-scale the dismiss animation will end. + * @param dismissEndYScale to this y-scale the dismiss animation will end. + * @param dismissDuration the duration of the dismiss animation in milliseconds. + */ + public void setKeyPreviewAnimationParams(final boolean hasCustomAnimationParams, + final float showUpStartXScale, final float showUpStartYScale, final int showUpDuration, + final float dismissEndXScale, final float dismissEndYScale, final int dismissDuration) { + mKeyPreviewDrawParams.setAnimationParams(hasCustomAnimationParams, + showUpStartXScale, showUpStartYScale, showUpDuration, + dismissEndXScale, dismissEndYScale, dismissDuration); } private void locatePreviewPlacerView() { diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyPreviewChoreographer.java b/java/src/com/android/inputmethod/keyboard/internal/KeyPreviewChoreographer.java index cd29c8d17..5005b7d7d 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/KeyPreviewChoreographer.java +++ b/java/src/com/android/inputmethod/keyboard/internal/KeyPreviewChoreographer.java @@ -18,13 +18,9 @@ package com.android.inputmethod.keyboard.internal; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; -import android.animation.AnimatorSet; -import android.animation.ObjectAnimator; import android.content.Context; import android.view.View; import android.view.ViewGroup; -import android.view.animation.AccelerateInterpolator; -import android.view.animation.DecelerateInterpolator; import com.android.inputmethod.keyboard.Key; import com.android.inputmethod.latin.utils.CoordinateUtils; @@ -89,9 +85,9 @@ public final class KeyPreviewChoreographer { } final Object tag = keyPreviewView.getTag(); if (withAnimation) { - if (tag instanceof KeyPreviewAnimations) { - final KeyPreviewAnimations animation = (KeyPreviewAnimations)tag; - animation.startDismiss(); + if (tag instanceof KeyPreviewAnimators) { + final KeyPreviewAnimators animators = (KeyPreviewAnimators)tag; + animators.startDismiss(); return; } } @@ -161,87 +157,60 @@ public final class KeyPreviewChoreographer { } // Show preview with animation. - final Animator showUpAnimation = createShowUpAniation(key, keyPreviewView); - final Animator dismissAnimation = createDismissAnimation(key, keyPreviewView); - final KeyPreviewAnimations animation = new KeyPreviewAnimations( - showUpAnimation, dismissAnimation); - keyPreviewView.setTag(animation); - animation.startShowUp(); + final Animator showUpAnimator = createShowUpAnimator(key, keyPreviewView); + final Animator dismissAnimator = createDismissAnimator(key, keyPreviewView); + final KeyPreviewAnimators animators = new KeyPreviewAnimators( + showUpAnimator, dismissAnimator); + keyPreviewView.setTag(animators); + animators.startShowUp(); } - private static final float KEY_PREVIEW_SHOW_UP_END_SCALE = 1.0f; - private static final AccelerateInterpolator ACCELERATE_INTERPOLATOR = - new AccelerateInterpolator(); - private static final DecelerateInterpolator DECELERATE_INTERPOLATOR = - new DecelerateInterpolator(); - - private Animator createShowUpAniation(final Key key, final KeyPreviewView keyPreviewView) { - // TODO: Optimization for no scale animation and no duration. - final ObjectAnimator scaleXAnimation = ObjectAnimator.ofFloat( - keyPreviewView, View.SCALE_X, mParams.getShowUpStartScale(), - KEY_PREVIEW_SHOW_UP_END_SCALE); - final ObjectAnimator scaleYAnimation = ObjectAnimator.ofFloat( - keyPreviewView, View.SCALE_Y, mParams.getShowUpStartScale(), - KEY_PREVIEW_SHOW_UP_END_SCALE); - final AnimatorSet showUpAnimation = new AnimatorSet(); - showUpAnimation.play(scaleXAnimation).with(scaleYAnimation); - showUpAnimation.setDuration(mParams.getShowUpDuration()); - showUpAnimation.setInterpolator(DECELERATE_INTERPOLATOR); - showUpAnimation.addListener(new AnimatorListenerAdapter() { + public Animator createShowUpAnimator(final Key key, final KeyPreviewView keyPreviewView) { + final Animator animator = mParams.createShowUpAnimator(keyPreviewView); + animator.addListener(new AnimatorListenerAdapter() { @Override - public void onAnimationStart(final Animator animation) { + public void onAnimationStart(final Animator animator) { showKeyPreview(key, keyPreviewView, false /* withAnimation */); } }); - return showUpAnimation; + return animator; } - private Animator createDismissAnimation(final Key key, final KeyPreviewView keyPreviewView) { - // TODO: Optimization for no scale animation and no duration. - final ObjectAnimator scaleXAnimation = ObjectAnimator.ofFloat( - keyPreviewView, View.SCALE_X, mParams.getDismissEndScale()); - final ObjectAnimator scaleYAnimation = ObjectAnimator.ofFloat( - keyPreviewView, View.SCALE_Y, mParams.getDismissEndScale()); - final AnimatorSet dismissAnimation = new AnimatorSet(); - dismissAnimation.play(scaleXAnimation).with(scaleYAnimation); - final int dismissDuration = Math.min( - mParams.getDismissDuration(), mParams.getLingerTimeout()); - dismissAnimation.setDuration(dismissDuration); - dismissAnimation.setInterpolator(ACCELERATE_INTERPOLATOR); - dismissAnimation.addListener(new AnimatorListenerAdapter() { + private Animator createDismissAnimator(final Key key, final KeyPreviewView keyPreviewView) { + final Animator animator = mParams.createDismissAnimator(keyPreviewView); + animator.addListener(new AnimatorListenerAdapter() { @Override - public void onAnimationEnd(final Animator animation) { + public void onAnimationEnd(final Animator animator) { dismissKeyPreview(key, false /* withAnimation */); } }); - return dismissAnimation; + return animator; } - private static class KeyPreviewAnimations extends AnimatorListenerAdapter { - private final Animator mShowUpAnimation; - private final Animator mDismissAnimation; + private static class KeyPreviewAnimators extends AnimatorListenerAdapter { + private final Animator mShowUpAnimator; + private final Animator mDismissAnimator; - public KeyPreviewAnimations(final Animator showUpAnimation, - final Animator dismissAnimation) { - mShowUpAnimation = showUpAnimation; - mDismissAnimation = dismissAnimation; + public KeyPreviewAnimators(final Animator showUpAnimator, final Animator dismissAnimator) { + mShowUpAnimator = showUpAnimator; + mDismissAnimator = dismissAnimator; } public void startShowUp() { - mShowUpAnimation.start(); + mShowUpAnimator.start(); } public void startDismiss() { - if (mShowUpAnimation.isRunning()) { - mShowUpAnimation.addListener(this); + if (mShowUpAnimator.isRunning()) { + mShowUpAnimator.addListener(this); return; } - mDismissAnimation.start(); + mDismissAnimator.start(); } @Override - public void onAnimationEnd(final Animator animation) { - mDismissAnimation.start(); + public void onAnimationEnd(final Animator animator) { + mDismissAnimator.start(); } } } diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyPreviewDrawParams.java b/java/src/com/android/inputmethod/keyboard/internal/KeyPreviewDrawParams.java index 68c9831fa..5ed39f986 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/KeyPreviewDrawParams.java +++ b/java/src/com/android/inputmethod/keyboard/internal/KeyPreviewDrawParams.java @@ -16,8 +16,14 @@ package com.android.inputmethod.keyboard.internal; +import android.animation.Animator; +import android.animation.AnimatorInflater; +import android.animation.AnimatorSet; +import android.animation.ObjectAnimator; import android.content.res.TypedArray; import android.view.View; +import android.view.animation.AccelerateInterpolator; +import android.view.animation.DecelerateInterpolator; import com.android.inputmethod.latin.R; @@ -26,10 +32,15 @@ public final class KeyPreviewDrawParams { public final int mPreviewOffset; public final int mPreviewHeight; public final int mPreviewBackgroundResId; + private final int mShowUpAnimatorResId; + private final int mDismissAnimatorResId; + private boolean mHasCustomAnimationParams; private int mShowUpDuration; private int mDismissDuration; - private float mShowUpStartScale; - private float mDismissEndScale; + private float mShowUpStartXScale; + private float mShowUpStartYScale; + private float mDismissEndXScale; + private float mDismissEndYScale; private int mLingerTimeout; private boolean mShowPopup = true; @@ -67,6 +78,10 @@ public final class KeyPreviewDrawParams { R.styleable.MainKeyboardView_keyPreviewBackground, 0); mLingerTimeout = mainKeyboardViewAttr.getInt( R.styleable.MainKeyboardView_keyPreviewLingerTimeout, 0); + mShowUpAnimatorResId = mainKeyboardViewAttr.getResourceId( + R.styleable.MainKeyboardView_keyPreviewShowUpAnimator, 0); + mDismissAnimatorResId = mainKeyboardViewAttr.getResourceId( + R.styleable.MainKeyboardView_keyPreviewDismissAnimator, 0); } public void setVisibleOffset(final int previewVisibleOffset) { @@ -112,27 +127,62 @@ public final class KeyPreviewDrawParams { return mLingerTimeout; } - public void setAnimationParams(final float showUpStartScale, final int showUpDuration, - final float dismissEndScale, final int dismissDuration) { - mShowUpStartScale = showUpStartScale; + public void setAnimationParams(final boolean hasCustomAnimationParams, + final float showUpStartXScale, final float showUpStartYScale, final int showUpDuration, + final float dismissEndXScale, final float dismissEndYScale, final int dismissDuration) { + mHasCustomAnimationParams = hasCustomAnimationParams; + mShowUpStartXScale = showUpStartXScale; + mShowUpStartYScale = showUpStartYScale; mShowUpDuration = showUpDuration; - mDismissEndScale = dismissEndScale; + mDismissEndXScale = dismissEndXScale; + mDismissEndYScale = dismissEndYScale; mDismissDuration = dismissDuration; } - public float getShowUpStartScale() { - return mShowUpStartScale; + private static final float KEY_PREVIEW_SHOW_UP_END_SCALE = 1.0f; + private static final AccelerateInterpolator ACCELERATE_INTERPOLATOR = + new AccelerateInterpolator(); + private static final DecelerateInterpolator DECELERATE_INTERPOLATOR = + new DecelerateInterpolator(); + + public Animator createShowUpAnimator(final View target) { + if (mHasCustomAnimationParams) { + final ObjectAnimator scaleXAnimator = ObjectAnimator.ofFloat( + target, View.SCALE_X, mShowUpStartXScale, + KEY_PREVIEW_SHOW_UP_END_SCALE); + final ObjectAnimator scaleYAnimator = ObjectAnimator.ofFloat( + target, View.SCALE_Y, mShowUpStartYScale, + KEY_PREVIEW_SHOW_UP_END_SCALE); + final AnimatorSet showUpAnimator = new AnimatorSet(); + showUpAnimator.play(scaleXAnimator).with(scaleYAnimator); + showUpAnimator.setDuration(mShowUpDuration); + showUpAnimator.setInterpolator(DECELERATE_INTERPOLATOR); + return showUpAnimator; + } + final Animator animator = AnimatorInflater.loadAnimator( + target.getContext(), mShowUpAnimatorResId); + animator.setTarget(target); + animator.setInterpolator(DECELERATE_INTERPOLATOR); + return animator; } - public int getShowUpDuration() { - return mShowUpDuration; - } - - public float getDismissEndScale() { - return mDismissEndScale; - } - - public int getDismissDuration() { - return mDismissDuration; + public Animator createDismissAnimator(final View target) { + if (mHasCustomAnimationParams) { + final ObjectAnimator scaleXAnimator = ObjectAnimator.ofFloat( + target, View.SCALE_X, mDismissEndXScale); + final ObjectAnimator scaleYAnimator = ObjectAnimator.ofFloat( + target, View.SCALE_Y, mDismissEndYScale); + final AnimatorSet dismissAnimator = new AnimatorSet(); + dismissAnimator.play(scaleXAnimator).with(scaleYAnimator); + final int dismissDuration = Math.min(mDismissDuration, mLingerTimeout); + dismissAnimator.setDuration(dismissDuration); + dismissAnimator.setInterpolator(ACCELERATE_INTERPOLATOR); + return dismissAnimator; + } + final Animator animator = AnimatorInflater.loadAnimator( + target.getContext(), mDismissAnimatorResId); + animator.setTarget(target); + animator.setInterpolator(ACCELERATE_INTERPOLATOR); + return animator; } } diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionary.java b/java/src/com/android/inputmethod/latin/BinaryDictionary.java index 693e1cdcc..2e108756e 100644 --- a/java/src/com/android/inputmethod/latin/BinaryDictionary.java +++ b/java/src/com/android/inputmethod/latin/BinaryDictionary.java @@ -83,7 +83,6 @@ public final class BinaryDictionary extends Dictionary { public static final String DIR_NAME_SUFFIX_FOR_RECORD_MIGRATION = ".migrating"; private long mNativeDict; - private final Locale mLocale; private final long mDictSize; private final String mDictFilePath; private final boolean mUseFullEditDistance; @@ -117,8 +116,7 @@ public final class BinaryDictionary extends Dictionary { public BinaryDictionary(final String filename, final long offset, final long length, final boolean useFullEditDistance, final Locale locale, final String dictType, final boolean isUpdatable) { - super(dictType); - mLocale = locale; + super(dictType, locale); mDictSize = length; mDictFilePath = filename; mIsUpdatable = isUpdatable; @@ -138,8 +136,7 @@ public final class BinaryDictionary extends Dictionary { public BinaryDictionary(final String filename, final boolean useFullEditDistance, final Locale locale, final String dictType, final long formatVersion, final Map<String, String> attributeMap) { - super(dictType); - mLocale = locale; + super(dictType, locale); mDictSize = 0; mDictFilePath = filename; // On memory dictionary is always updatable. diff --git a/java/src/com/android/inputmethod/latin/Dictionary.java b/java/src/com/android/inputmethod/latin/Dictionary.java index 560ced9c4..2f79c7662 100644 --- a/java/src/com/android/inputmethod/latin/Dictionary.java +++ b/java/src/com/android/inputmethod/latin/Dictionary.java @@ -16,12 +16,12 @@ package com.android.inputmethod.latin; -import com.android.inputmethod.annotations.UsedForTesting; import com.android.inputmethod.keyboard.ProximityInfo; import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo; import com.android.inputmethod.latin.settings.SettingsValuesForSuggestion; import java.util.ArrayList; +import java.util.Locale; /** * Abstract base class for a dictionary that can do a fuzzy search for words based on a set of key @@ -62,9 +62,12 @@ public abstract class Dictionary { // Contextual dictionary. public static final String TYPE_CONTEXTUAL = "contextual"; public final String mDictType; + // The locale for this dictionary. May be null if unknown (phony dictionary for example). + public final Locale mLocale; - public Dictionary(final String dictType) { + public Dictionary(final String dictType, final Locale locale) { mDictType = dictType; + mLocale = locale; } /** @@ -162,7 +165,7 @@ public abstract class Dictionary { private static class PhonyDictionary extends Dictionary { // This class is not publicly instantiable. private PhonyDictionary(final String type) { - super(type); + super(type, null); } @Override diff --git a/java/src/com/android/inputmethod/latin/DictionaryCollection.java b/java/src/com/android/inputmethod/latin/DictionaryCollection.java index 2b4c54d48..ca5e93714 100644 --- a/java/src/com/android/inputmethod/latin/DictionaryCollection.java +++ b/java/src/com/android/inputmethod/latin/DictionaryCollection.java @@ -25,6 +25,7 @@ import com.android.inputmethod.latin.settings.SettingsValuesForSuggestion; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; +import java.util.Locale; import java.util.concurrent.CopyOnWriteArrayList; /** @@ -34,13 +35,14 @@ public final class DictionaryCollection extends Dictionary { private final String TAG = DictionaryCollection.class.getSimpleName(); protected final CopyOnWriteArrayList<Dictionary> mDictionaries; - public DictionaryCollection(final String dictType) { - super(dictType); + public DictionaryCollection(final String dictType, final Locale locale) { + super(dictType, locale); mDictionaries = new CopyOnWriteArrayList<>(); } - public DictionaryCollection(final String dictType, final Dictionary... dictionaries) { - super(dictType); + public DictionaryCollection(final String dictType, final Locale locale, + final Dictionary... dictionaries) { + super(dictType, locale); if (null == dictionaries) { mDictionaries = new CopyOnWriteArrayList<>(); } else { @@ -49,8 +51,9 @@ public final class DictionaryCollection extends Dictionary { } } - public DictionaryCollection(final String dictType, final Collection<Dictionary> dictionaries) { - super(dictType); + public DictionaryCollection(final String dictType, final Locale locale, + final Collection<Dictionary> dictionaries) { + super(dictType, locale); mDictionaries = new CopyOnWriteArrayList<>(dictionaries); mDictionaries.removeAll(Collections.singleton(null)); } diff --git a/java/src/com/android/inputmethod/latin/DictionaryFacilitator.java b/java/src/com/android/inputmethod/latin/DictionaryFacilitator.java index fe395a807..480bd1f85 100644 --- a/java/src/com/android/inputmethod/latin/DictionaryFacilitator.java +++ b/java/src/com/android/inputmethod/latin/DictionaryFacilitator.java @@ -503,7 +503,7 @@ public class DictionaryFacilitator { final SettingsValuesForSuggestion settingsValuesForSuggestion, final int sessionId) { final Dictionaries dictionaries = mDictionaries; final SuggestionResults suggestionResults = - new SuggestionResults(dictionaries.mLocale, SuggestedWords.MAX_SUGGESTIONS); + new SuggestionResults(SuggestedWords.MAX_SUGGESTIONS); final float[] languageWeight = new float[] { Dictionary.NOT_A_LANGUAGE_WEIGHT }; for (final String dictType : DICT_TYPES_ORDERED_TO_GET_SUGGESTIONS) { final Dictionary dictionary = dictionaries.getDict(dictType); diff --git a/java/src/com/android/inputmethod/latin/DictionaryFactory.java b/java/src/com/android/inputmethod/latin/DictionaryFactory.java index 59de4f82a..3459b426d 100644 --- a/java/src/com/android/inputmethod/latin/DictionaryFactory.java +++ b/java/src/com/android/inputmethod/latin/DictionaryFactory.java @@ -50,7 +50,7 @@ public final class DictionaryFactory { final Locale locale, final boolean useFullEditDistance) { if (null == locale) { Log.e(TAG, "No locale defined for dictionary"); - return new DictionaryCollection(Dictionary.TYPE_MAIN, + return new DictionaryCollection(Dictionary.TYPE_MAIN, locale, createReadOnlyBinaryDictionary(context, locale)); } @@ -75,7 +75,7 @@ public final class DictionaryFactory { // If the list is empty, that means we should not use any dictionary (for example, the user // explicitly disabled the main dictionary), so the following is okay. dictList is never // null, but if for some reason it is, DictionaryCollection handles it gracefully. - return new DictionaryCollection(Dictionary.TYPE_MAIN, dictList); + return new DictionaryCollection(Dictionary.TYPE_MAIN, locale, dictList); } /** @@ -188,7 +188,7 @@ public final class DictionaryFactory { public static Dictionary createDictionaryForTest(final AssetFileAddress[] dictionaryList, final boolean useFullEditDistance, Locale locale) { final DictionaryCollection dictionaryCollection = - new DictionaryCollection(Dictionary.TYPE_MAIN); + new DictionaryCollection(Dictionary.TYPE_MAIN, locale); for (final AssetFileAddress address : dictionaryList) { final ReadOnlyBinaryDictionary readOnlyBinaryDictionary = new ReadOnlyBinaryDictionary( address.mFilename, address.mOffset, address.mLength, useFullEditDistance, diff --git a/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java b/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java index de384037f..a1dd67f27 100644 --- a/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java +++ b/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java @@ -86,9 +86,6 @@ abstract public class ExpandableBinaryDictionary extends Dictionary { */ private final String mDictName; - /** Dictionary locale */ - private final Locale mLocale; - /** Dictionary file */ private final File mDictFile; @@ -137,10 +134,9 @@ abstract public class ExpandableBinaryDictionary extends Dictionary { */ public ExpandableBinaryDictionary(final Context context, final String dictName, final Locale locale, final String dictType, final File dictFile) { - super(dictType); + super(dictType, locale); mDictName = dictName; mContext = context; - mLocale = locale; mDictFile = getDictFile(context, dictName, dictFile); mBinaryDictionary = null; mIsReloading = new AtomicBoolean(); diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index 59150aeca..c55acd462 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -1179,10 +1179,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen return mInputLogic.getCurrentRecapitalizeState(); } - public Locale getCurrentSubtypeLocale() { - return mSubtypeSwitcher.getCurrentSubtypeLocale(); - } - /** * @param codePoints code points to get coordinates for. * @return x,y coordinates for this keyboard, as a flattened array. @@ -1496,7 +1492,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen } final String wordToShow; if (CapsModeUtils.isAutoCapsMode(mInputLogic.mLastComposedWord.mCapitalizedMode)) { - wordToShow = word.toLowerCase(getCurrentSubtypeLocale()); + wordToShow = word.toLowerCase(mSubtypeSwitcher.getCurrentSubtypeLocale()); } else { wordToShow = word; } diff --git a/java/src/com/android/inputmethod/latin/ReadOnlyBinaryDictionary.java b/java/src/com/android/inputmethod/latin/ReadOnlyBinaryDictionary.java index 5d4fc5861..ecf25c28b 100644 --- a/java/src/com/android/inputmethod/latin/ReadOnlyBinaryDictionary.java +++ b/java/src/com/android/inputmethod/latin/ReadOnlyBinaryDictionary.java @@ -40,7 +40,7 @@ public final class ReadOnlyBinaryDictionary extends Dictionary { public ReadOnlyBinaryDictionary(final String filename, final long offset, final long length, final boolean useFullEditDistance, final Locale locale, final String dictType) { - super(dictType); + super(dictType, locale); mBinaryDictionary = new BinaryDictionary(filename, offset, length, useFullEditDistance, locale, dictType, false /* isUpdatable */); } diff --git a/java/src/com/android/inputmethod/latin/Suggest.java b/java/src/com/android/inputmethod/latin/Suggest.java index 6779351fd..9e4aa40a2 100644 --- a/java/src/com/android/inputmethod/latin/Suggest.java +++ b/java/src/com/android/inputmethod/latin/Suggest.java @@ -84,7 +84,7 @@ public final class Suggest { private static ArrayList<SuggestedWordInfo> getTransformedSuggestedWordInfoList( final WordComposer wordComposer, final SuggestionResults results, - final int trailingSingleQuotesCount) { + final int trailingSingleQuotesCount, final Locale defaultLocale) { final boolean shouldMakeSuggestionsAllUpperCase = wordComposer.isAllUpperCase() && !wordComposer.isResumed(); final boolean isOnlyFirstCharCapitalized = @@ -96,9 +96,11 @@ public final class Suggest { || 0 != trailingSingleQuotesCount) { for (int i = 0; i < suggestionsCount; ++i) { final SuggestedWordInfo wordInfo = suggestionsContainer.get(i); + final Locale wordLocale = wordInfo.mSourceDict.mLocale; final SuggestedWordInfo transformedWordInfo = getTransformedSuggestedWordInfo( - wordInfo, results.mLocale, shouldMakeSuggestionsAllUpperCase, - isOnlyFirstCharCapitalized, trailingSingleQuotesCount); + wordInfo, null == wordLocale ? defaultLocale : wordLocale, + shouldMakeSuggestionsAllUpperCase, isOnlyFirstCharCapitalized, + trailingSingleQuotesCount); suggestionsContainer.set(i, transformedWordInfo); } } @@ -134,7 +136,7 @@ public final class Suggest { SESSION_ID_TYPING); final ArrayList<SuggestedWordInfo> suggestionsContainer = getTransformedSuggestedWordInfoList(wordComposer, suggestionResults, - trailingSingleQuotesCount); + trailingSingleQuotesCount, mDictionaryFacilitator.getLocale()); final boolean didRemoveTypedWord = SuggestedWordInfo.removeDups(wordComposer.getTypedWord(), suggestionsContainer); @@ -208,6 +210,7 @@ public final class Suggest { final SuggestionResults suggestionResults = mDictionaryFacilitator.getSuggestionResults( wordComposer, prevWordsInfo, proximityInfo, settingsValuesForSuggestion, SESSION_ID_GESTURE); + final Locale defaultLocale = mDictionaryFacilitator.getLocale(); final ArrayList<SuggestedWordInfo> suggestionsContainer = new ArrayList<>(suggestionResults); final int suggestionsCount = suggestionsContainer.size(); @@ -216,9 +219,10 @@ public final class Suggest { if (isFirstCharCapitalized || isAllUpperCase) { for (int i = 0; i < suggestionsCount; ++i) { final SuggestedWordInfo wordInfo = suggestionsContainer.get(i); + final Locale wordlocale = wordInfo.mSourceDict.mLocale; final SuggestedWordInfo transformedWordInfo = getTransformedSuggestedWordInfo( - wordInfo, suggestionResults.mLocale, isAllUpperCase, isFirstCharCapitalized, - 0 /* trailingSingleQuotesCount */); + wordInfo, null == wordlocale ? defaultLocale : wordlocale, isAllUpperCase, + isFirstCharCapitalized, 0 /* trailingSingleQuotesCount */); suggestionsContainer.set(i, transformedWordInfo); } } diff --git a/java/src/com/android/inputmethod/latin/settings/DebugSettings.java b/java/src/com/android/inputmethod/latin/settings/DebugSettings.java index 63d848e2d..48f4c758c 100644 --- a/java/src/com/android/inputmethod/latin/settings/DebugSettings.java +++ b/java/src/com/android/inputmethod/latin/settings/DebugSettings.java @@ -23,10 +23,16 @@ public final class DebugSettings { "force_physical_keyboard_special_key"; public static final String PREF_SHOW_UI_TO_ACCEPT_TYPED_WORD = "pref_show_ui_to_accept_typed_word"; - public static final String PREF_KEY_PREVIEW_SHOW_UP_START_SCALE = - "pref_key_preview_show_up_start_scale"; - public static final String PREF_KEY_PREVIEW_DISMISS_END_SCALE = - "pref_key_preview_dismiss_end_scale"; + public static final String PREF_HAS_CUSTOM_KEY_PREVIEW_ANIMATION_PARAMS = + "pref_has_custom_key_preview_animation_params"; + public static final String PREF_KEY_PREVIEW_SHOW_UP_START_X_SCALE = + "pref_key_preview_show_up_start_x_scale"; + public static final String PREF_KEY_PREVIEW_SHOW_UP_START_Y_SCALE = + "pref_key_preview_show_up_start_y_scale"; + public static final String PREF_KEY_PREVIEW_DISMISS_END_X_SCALE = + "pref_key_preview_dismiss_end_x_scale"; + public static final String PREF_KEY_PREVIEW_DISMISS_END_Y_SCALE = + "pref_key_preview_dismiss_end_y_scale"; public static final String PREF_KEY_PREVIEW_SHOW_UP_DURATION = "pref_key_preview_show_up_duration"; public static final String PREF_KEY_PREVIEW_DISMISS_DURATION = diff --git a/java/src/com/android/inputmethod/latin/settings/DebugSettingsFragment.java b/java/src/com/android/inputmethod/latin/settings/DebugSettingsFragment.java index dc2f88aa8..5640e2039 100644 --- a/java/src/com/android/inputmethod/latin/settings/DebugSettingsFragment.java +++ b/java/src/com/android/inputmethod/latin/settings/DebugSettingsFragment.java @@ -78,12 +78,18 @@ public final class DebugSettingsFragment extends SubScreenFragment res.getInteger(R.integer.config_key_preview_show_up_duration)); setupKeyPreviewAnimationDuration(DebugSettings.PREF_KEY_PREVIEW_DISMISS_DURATION, res.getInteger(R.integer.config_key_preview_dismiss_duration)); - setupKeyPreviewAnimationScale(DebugSettings.PREF_KEY_PREVIEW_SHOW_UP_START_SCALE, - ResourceUtils.getFloatFromFraction( - res, R.fraction.config_key_preview_show_up_start_scale)); - setupKeyPreviewAnimationScale(DebugSettings.PREF_KEY_PREVIEW_DISMISS_END_SCALE, - ResourceUtils.getFloatFromFraction( - res, R.fraction.config_key_preview_dismiss_end_scale)); + final float defaultKeyPreviewShowUpStartScale = ResourceUtils.getFloatFromFraction( + res, R.fraction.config_key_preview_show_up_start_scale); + final float defaultKeyPreviewDismissEndScale = ResourceUtils.getFloatFromFraction( + res, R.fraction.config_key_preview_dismiss_end_scale); + setupKeyPreviewAnimationScale(DebugSettings.PREF_KEY_PREVIEW_SHOW_UP_START_X_SCALE, + defaultKeyPreviewShowUpStartScale); + setupKeyPreviewAnimationScale(DebugSettings.PREF_KEY_PREVIEW_SHOW_UP_START_Y_SCALE, + defaultKeyPreviewShowUpStartScale); + setupKeyPreviewAnimationScale(DebugSettings.PREF_KEY_PREVIEW_DISMISS_END_X_SCALE, + defaultKeyPreviewDismissEndScale); + setupKeyPreviewAnimationScale(DebugSettings.PREF_KEY_PREVIEW_DISMISS_END_Y_SCALE, + defaultKeyPreviewDismissEndScale); mServiceNeedsRestart = false; mDebugMode = (TwoStatePreference) findPreference(DebugSettings.PREF_DEBUG_MODE); diff --git a/java/src/com/android/inputmethod/latin/settings/SettingsValues.java b/java/src/com/android/inputmethod/latin/settings/SettingsValues.java index e91862de4..11291959c 100644 --- a/java/src/com/android/inputmethod/latin/settings/SettingsValues.java +++ b/java/src/com/android/inputmethod/latin/settings/SettingsValues.java @@ -104,10 +104,13 @@ public class SettingsValues { // Debug settings public final boolean mIsInternal; + public final boolean mHasCustomKeyPreviewAnimationParams; public final int mKeyPreviewShowUpDuration; public final int mKeyPreviewDismissDuration; - public final float mKeyPreviewShowUpStartScale; - public final float mKeyPreviewDismissEndScale; + public final float mKeyPreviewShowUpStartXScale; + public final float mKeyPreviewShowUpStartYScale; + public final float mKeyPreviewDismissEndXScale; + public final float mKeyPreviewDismissEndYScale; public SettingsValues(final Context context, final SharedPreferences prefs, final Resources res, final InputAttributes inputAttributes) { @@ -179,20 +182,30 @@ public class SettingsValues { mTextHighlightColorForAddToDictionaryIndicator = res.getColor( R.color.text_decorator_add_to_dictionary_indicator_text_highlight_color); mIsInternal = Settings.isInternal(prefs); + mHasCustomKeyPreviewAnimationParams = prefs.getBoolean( + DebugSettings.PREF_HAS_CUSTOM_KEY_PREVIEW_ANIMATION_PARAMS, false); mKeyPreviewShowUpDuration = Settings.readKeyPreviewAnimationDuration( prefs, DebugSettings.PREF_KEY_PREVIEW_SHOW_UP_DURATION, res.getInteger(R.integer.config_key_preview_show_up_duration)); mKeyPreviewDismissDuration = Settings.readKeyPreviewAnimationDuration( prefs, DebugSettings.PREF_KEY_PREVIEW_DISMISS_DURATION, res.getInteger(R.integer.config_key_preview_dismiss_duration)); - mKeyPreviewShowUpStartScale = Settings.readKeyPreviewAnimationScale( - prefs, DebugSettings.PREF_KEY_PREVIEW_SHOW_UP_START_SCALE, - ResourceUtils.getFloatFromFraction( - res, R.fraction.config_key_preview_show_up_start_scale)); - mKeyPreviewDismissEndScale = Settings.readKeyPreviewAnimationScale( - prefs, DebugSettings.PREF_KEY_PREVIEW_DISMISS_END_SCALE, - ResourceUtils.getFloatFromFraction( - res, R.fraction.config_key_preview_dismiss_end_scale)); + final float defaultKeyPreviewShowUpStartScale = ResourceUtils.getFloatFromFraction( + res, R.fraction.config_key_preview_show_up_start_scale); + final float defaultKeyPreviewDismissEndScale = ResourceUtils.getFloatFromFraction( + res, R.fraction.config_key_preview_dismiss_end_scale); + mKeyPreviewShowUpStartXScale = Settings.readKeyPreviewAnimationScale( + prefs, DebugSettings.PREF_KEY_PREVIEW_SHOW_UP_START_X_SCALE, + defaultKeyPreviewShowUpStartScale); + mKeyPreviewShowUpStartYScale = Settings.readKeyPreviewAnimationScale( + prefs, DebugSettings.PREF_KEY_PREVIEW_SHOW_UP_START_Y_SCALE, + defaultKeyPreviewShowUpStartScale); + mKeyPreviewDismissEndXScale = Settings.readKeyPreviewAnimationScale( + prefs, DebugSettings.PREF_KEY_PREVIEW_DISMISS_END_X_SCALE, + defaultKeyPreviewDismissEndScale); + mKeyPreviewDismissEndYScale = Settings.readKeyPreviewAnimationScale( + prefs, DebugSettings.PREF_KEY_PREVIEW_DISMISS_END_Y_SCALE, + defaultKeyPreviewDismissEndScale); mDisplayOrientation = res.getConfiguration().orientation; mAppWorkarounds = new AsyncResultHolder<>(); final PackageInfo packageInfo = TargetPackageInfoGetterTask.getCachedPackageInfo( @@ -429,10 +442,14 @@ public class SettingsValues { sb.append("" + mKeyPreviewShowUpDuration); sb.append("\n mKeyPreviewDismissDuration = "); sb.append("" + mKeyPreviewDismissDuration); - sb.append("\n mKeyPreviewShowUpStartScale = "); - sb.append("" + mKeyPreviewShowUpStartScale); - sb.append("\n mKeyPreviewDismissEndScale = "); - sb.append("" + mKeyPreviewDismissEndScale); + sb.append("\n mKeyPreviewShowUpStartScaleX = "); + sb.append("" + mKeyPreviewShowUpStartXScale); + sb.append("\n mKeyPreviewShowUpStartScaleY = "); + sb.append("" + mKeyPreviewShowUpStartYScale); + sb.append("\n mKeyPreviewDismissEndScaleX = "); + sb.append("" + mKeyPreviewDismissEndXScale); + sb.append("\n mKeyPreviewDismissEndScaleY = "); + sb.append("" + mKeyPreviewDismissEndYScale); return sb.toString(); } } diff --git a/java/src/com/android/inputmethod/latin/utils/SuggestionResults.java b/java/src/com/android/inputmethod/latin/utils/SuggestionResults.java index 7170bd789..eaa5743d4 100644 --- a/java/src/com/android/inputmethod/latin/utils/SuggestionResults.java +++ b/java/src/com/android/inputmethod/latin/utils/SuggestionResults.java @@ -30,18 +30,16 @@ import java.util.TreeSet; * than its limit */ public final class SuggestionResults extends TreeSet<SuggestedWordInfo> { - public final Locale mLocale; public final ArrayList<SuggestedWordInfo> mRawSuggestions; private final int mCapacity; - public SuggestionResults(final Locale locale, final int capacity) { - this(locale, sSuggestedWordInfoComparator, capacity); + public SuggestionResults(final int capacity) { + this(sSuggestedWordInfoComparator, capacity); } - public SuggestionResults(final Locale locale, final Comparator<SuggestedWordInfo> comparator, + public SuggestionResults(final Comparator<SuggestedWordInfo> comparator, final int capacity) { super(comparator); - mLocale = locale; mCapacity = capacity; if (ProductionFlags.INCLUDE_RAW_SUGGESTIONS) { mRawSuggestions = new ArrayList<>(); diff --git a/native/jni/NativeFileList.mk b/native/jni/NativeFileList.mk index 082e1e2f9..4f77388fd 100644 --- a/native/jni/NativeFileList.mk +++ b/native/jni/NativeFileList.mk @@ -123,6 +123,7 @@ LATIN_IME_CORE_TEST_FILES := \ defines_test.cpp \ suggest/core/dicnode/dic_node_pool_test.cpp \ suggest/core/dictionary/bloom_filter_test.cpp \ + suggest/core/layout/geometry_utils_test.cpp \ suggest/core/layout/normal_distribution_2d_test.cpp \ suggest/policyimpl/dictionary/structure/v4/content/language_model_dict_content_test.cpp \ suggest/policyimpl/dictionary/structure/v4/content/probability_entry_test.cpp \ @@ -131,6 +132,8 @@ LATIN_IME_CORE_TEST_FILES := \ suggest/policyimpl/dictionary/utils/byte_array_utils_test.cpp \ suggest/policyimpl/dictionary/utils/sparse_table_test.cpp \ suggest/policyimpl/dictionary/utils/trie_map_test.cpp \ + suggest/policyimpl/utils/damerau_levenshtein_edit_distance_policy_test.cpp \ utils/autocorrection_threshold_utils_test.cpp \ + utils/char_utils_test.cpp \ utils/int_array_view_test.cpp \ utils/time_keeper_test.cpp diff --git a/native/jni/src/suggest/core/dicnode/dic_node.h b/native/jni/src/suggest/core/dicnode/dic_node.h index 214cdfca6..e44d5ae20 100644 --- a/native/jni/src/suggest/core/dicnode/dic_node.h +++ b/native/jni/src/suggest/core/dicnode/dic_node.h @@ -103,10 +103,10 @@ class DicNode { PROF_NODE_COPY(&dicNode->mProfiler, mProfiler); } - // Init for root with prevWordsPtNodePos which is used for n-gram - void initAsRoot(const int rootPtNodeArrayPos, const int *const prevWordsPtNodePos) { + // Init for root with prevWordIds which is used for n-gram + void initAsRoot(const int rootPtNodeArrayPos, const int *const prevWordIds) { mIsCachedForNextSuggestion = false; - mDicNodeProperties.init(rootPtNodeArrayPos, prevWordsPtNodePos); + mDicNodeProperties.init(rootPtNodeArrayPos, prevWordIds); mDicNodeState.init(); PROF_NODE_RESET(mProfiler); } @@ -114,12 +114,12 @@ class DicNode { // Init for root with previous word void initAsRootWithPreviousWord(const DicNode *const dicNode, const int rootPtNodeArrayPos) { mIsCachedForNextSuggestion = dicNode->mIsCachedForNextSuggestion; - int newPrevWordsPtNodePos[MAX_PREV_WORD_COUNT_FOR_N_GRAM]; - newPrevWordsPtNodePos[0] = dicNode->mDicNodeProperties.getPtNodePos(); - for (size_t i = 1; i < NELEMS(newPrevWordsPtNodePos); ++i) { - newPrevWordsPtNodePos[i] = dicNode->getPrevWordsTerminalPtNodePos()[i - 1]; + int newPrevWordIds[MAX_PREV_WORD_COUNT_FOR_N_GRAM]; + newPrevWordIds[0] = dicNode->mDicNodeProperties.getWordId(); + for (size_t i = 1; i < NELEMS(newPrevWordIds); ++i) { + newPrevWordIds[i] = dicNode->getPrevWordIds()[i - 1]; } - mDicNodeProperties.init(rootPtNodeArrayPos, newPrevWordsPtNodePos); + mDicNodeProperties.init(rootPtNodeArrayPos, newPrevWordIds); mDicNodeState.initAsRootWithPreviousWord(&dicNode->mDicNodeState, dicNode->mDicNodeProperties.getDepth()); PROF_NODE_COPY(&dicNode->mProfiler, mProfiler); @@ -145,7 +145,7 @@ class DicNode { dicNode->mDicNodeProperties.getLeavingDepth() + mergedNodeCodePointCount); mDicNodeProperties.init(ptNodePos, childrenPtNodeArrayPos, mergedNodeCodePoints[0], probability, wordId, hasChildren, isBlacklistedOrNotAWord, newDepth, - newLeavingDepth, dicNode->mDicNodeProperties.getPrevWordsTerminalPtNodePos()); + newLeavingDepth, dicNode->mDicNodeProperties.getPrevWordIds()); mDicNodeState.init(&dicNode->mDicNodeState, mergedNodeCodePointCount, mergedNodeCodePoints); PROF_NODE_COPY(&dicNode->mProfiler, mProfiler); @@ -204,13 +204,18 @@ class DicNode { } // Used to get n-gram probability in DicNodeUtils. + int getWordId() const { + return mDicNodeProperties.getWordId(); + } + + // TODO: Remove int getPtNodePos() const { return mDicNodeProperties.getPtNodePos(); } - // TODO: Use view class to return PtNodePos array. - const int *getPrevWordsTerminalPtNodePos() const { - return mDicNodeProperties.getPrevWordsTerminalPtNodePos(); + // TODO: Use view class to return word id array. + const int *getPrevWordIds() const { + return mDicNodeProperties.getPrevWordIds(); } // Used in DicNodeUtils diff --git a/native/jni/src/suggest/core/dicnode/dic_node_utils.cpp b/native/jni/src/suggest/core/dicnode/dic_node_utils.cpp index 69ea67418..87d245276 100644 --- a/native/jni/src/suggest/core/dicnode/dic_node_utils.cpp +++ b/native/jni/src/suggest/core/dicnode/dic_node_utils.cpp @@ -29,8 +29,8 @@ namespace latinime { /* static */ void DicNodeUtils::initAsRoot( const DictionaryStructureWithBufferPolicy *const dictionaryStructurePolicy, - const int *const prevWordsPtNodePos, DicNode *const newRootDicNode) { - newRootDicNode->initAsRoot(dictionaryStructurePolicy->getRootPosition(), prevWordsPtNodePos); + const int *const prevWordIds, DicNode *const newRootDicNode) { + newRootDicNode->initAsRoot(dictionaryStructurePolicy->getRootPosition(), prevWordIds); } /*static */ void DicNodeUtils::initAsRootWithPreviousWord( @@ -86,9 +86,9 @@ namespace latinime { const DicNode *const dicNode, MultiBigramMap *const multiBigramMap) { const int unigramProbability = dicNode->getProbability(); if (multiBigramMap) { - const int *const prevWordsPtNodePos = dicNode->getPrevWordsTerminalPtNodePos(); + const int *const prevWordIds = dicNode->getPrevWordIds(); return multiBigramMap->getBigramProbability(dictionaryStructurePolicy, - prevWordsPtNodePos, dicNode->getPtNodePos(), unigramProbability); + prevWordIds, dicNode->getWordId(), unigramProbability); } return dictionaryStructurePolicy->getProbability(unigramProbability, NOT_A_PROBABILITY); diff --git a/native/jni/src/suggest/core/dicnode/dic_node_utils.h b/native/jni/src/suggest/core/dicnode/dic_node_utils.h index 00e80c604..56ff6e3d0 100644 --- a/native/jni/src/suggest/core/dicnode/dic_node_utils.h +++ b/native/jni/src/suggest/core/dicnode/dic_node_utils.h @@ -30,7 +30,7 @@ class DicNodeUtils { public: static void initAsRoot( const DictionaryStructureWithBufferPolicy *const dictionaryStructurePolicy, - const int *const prevWordPtNodePos, DicNode *const newRootDicNode); + const int *const prevWordIds, DicNode *const newRootDicNode); static void initAsRootWithPreviousWord( const DictionaryStructureWithBufferPolicy *const dictionaryStructurePolicy, const DicNode *const prevWordLastDicNode, DicNode *const newRootDicNode); diff --git a/native/jni/src/suggest/core/dicnode/internal/dic_node_properties.h b/native/jni/src/suggest/core/dicnode/internal/dic_node_properties.h index fc242a92b..1d905b9fe 100644 --- a/native/jni/src/suggest/core/dicnode/internal/dic_node_properties.h +++ b/native/jni/src/suggest/core/dicnode/internal/dic_node_properties.h @@ -39,7 +39,7 @@ class DicNodeProperties { // Should be called only once per DicNode is initialized. void init(const int pos, const int childrenPos, const int nodeCodePoint, const int probability, const int wordId, const bool hasChildren, const bool isBlacklistedOrNotAWord, - const uint16_t depth, const uint16_t leavingDepth, const int *const prevWordsNodePos) { + const uint16_t depth, const uint16_t leavingDepth, const int *const prevWordIds) { mPtNodePos = pos; mChildrenPtNodeArrayPos = childrenPos; mDicNodeCodePoint = nodeCodePoint; @@ -49,11 +49,11 @@ class DicNodeProperties { mIsBlacklistedOrNotAWord = isBlacklistedOrNotAWord; mDepth = depth; mLeavingDepth = leavingDepth; - memmove(mPrevWordsTerminalPtNodePos, prevWordsNodePos, sizeof(mPrevWordsTerminalPtNodePos)); + memmove(mPrevWordIds, prevWordIds, sizeof(mPrevWordIds)); } // Init for root with prevWordsPtNodePos which is used for n-gram - void init(const int rootPtNodeArrayPos, const int *const prevWordsNodePos) { + void init(const int rootPtNodeArrayPos, const int *const prevWordIds) { mPtNodePos = NOT_A_DICT_POS; mChildrenPtNodeArrayPos = rootPtNodeArrayPos; mDicNodeCodePoint = NOT_A_CODE_POINT; @@ -63,7 +63,7 @@ class DicNodeProperties { mIsBlacklistedOrNotAWord = false; mDepth = 0; mLeavingDepth = 0; - memmove(mPrevWordsTerminalPtNodePos, prevWordsNodePos, sizeof(mPrevWordsTerminalPtNodePos)); + memmove(mPrevWordIds, prevWordIds, sizeof(mPrevWordIds)); } void initByCopy(const DicNodeProperties *const dicNodeProp) { @@ -76,8 +76,7 @@ class DicNodeProperties { mIsBlacklistedOrNotAWord = dicNodeProp->mIsBlacklistedOrNotAWord; mDepth = dicNodeProp->mDepth; mLeavingDepth = dicNodeProp->mLeavingDepth; - memmove(mPrevWordsTerminalPtNodePos, dicNodeProp->mPrevWordsTerminalPtNodePos, - sizeof(mPrevWordsTerminalPtNodePos)); + memmove(mPrevWordIds, dicNodeProp->mPrevWordIds, sizeof(mPrevWordIds)); } // Init as passing child @@ -91,8 +90,7 @@ class DicNodeProperties { mIsBlacklistedOrNotAWord = dicNodeProp->mIsBlacklistedOrNotAWord; mDepth = dicNodeProp->mDepth + 1; // Increment the depth of a passing child mLeavingDepth = dicNodeProp->mLeavingDepth; - memmove(mPrevWordsTerminalPtNodePos, dicNodeProp->mPrevWordsTerminalPtNodePos, - sizeof(mPrevWordsTerminalPtNodePos)); + memmove(mPrevWordIds, dicNodeProp->mPrevWordIds, sizeof(mPrevWordIds)); } int getPtNodePos() const { @@ -132,8 +130,12 @@ class DicNodeProperties { return mIsBlacklistedOrNotAWord; } - const int *getPrevWordsTerminalPtNodePos() const { - return mPrevWordsTerminalPtNodePos; + const int *getPrevWordIds() const { + return mPrevWordIds; + } + + int getWordId() const { + return mWordId; } private: @@ -149,7 +151,7 @@ class DicNodeProperties { bool mIsBlacklistedOrNotAWord; uint16_t mDepth; uint16_t mLeavingDepth; - int mPrevWordsTerminalPtNodePos[MAX_PREV_WORD_COUNT_FOR_N_GRAM]; + int mPrevWordIds[MAX_PREV_WORD_COUNT_FOR_N_GRAM]; }; } // namespace latinime #endif // LATINIME_DIC_NODE_PROPERTIES_H diff --git a/native/jni/src/suggest/core/dictionary/dictionary.cpp b/native/jni/src/suggest/core/dictionary/dictionary.cpp index c025bfcf5..956243161 100644 --- a/native/jni/src/suggest/core/dictionary/dictionary.cpp +++ b/native/jni/src/suggest/core/dictionary/dictionary.cpp @@ -93,11 +93,10 @@ void Dictionary::getPredictions(const PrevWordsInfo *const prevWordsInfo, TimeKeeper::setCurrentTime(); NgramListenerForPrediction listener(prevWordsInfo, outSuggestionResults, mDictionaryStructureWithBufferPolicy.get()); - int prevWordsPtNodePos[MAX_PREV_WORD_COUNT_FOR_N_GRAM]; - prevWordsInfo->getPrevWordsTerminalPtNodePos( - mDictionaryStructureWithBufferPolicy.get(), prevWordsPtNodePos, + int prevWordIds[MAX_PREV_WORD_COUNT_FOR_N_GRAM]; + prevWordsInfo->getPrevWordIds(mDictionaryStructureWithBufferPolicy.get(), prevWordIds, true /* tryLowerCaseSearch */); - mDictionaryStructureWithBufferPolicy->iterateNgramEntries(prevWordsPtNodePos, &listener); + mDictionaryStructureWithBufferPolicy->iterateNgramEntries(prevWordIds, &listener); } int Dictionary::getProbability(const int *word, int length) const { @@ -113,18 +112,17 @@ int Dictionary::getMaxProbabilityOfExactMatches(const int *word, int length) con int Dictionary::getNgramProbability(const PrevWordsInfo *const prevWordsInfo, const int *word, int length) const { TimeKeeper::setCurrentTime(); - int nextWordPos = mDictionaryStructureWithBufferPolicy->getTerminalPtNodePositionOfWord( + int wordId = mDictionaryStructureWithBufferPolicy->getWordId( CodePointArrayView(word, length), false /* forceLowerCaseSearch */); - if (NOT_A_DICT_POS == nextWordPos) return NOT_A_PROBABILITY; + if (wordId == NOT_A_WORD_ID) return NOT_A_PROBABILITY; if (!prevWordsInfo) { - return getDictionaryStructurePolicy()->getProbabilityOfPtNode( - nullptr /* prevWordsPtNodePos */, nextWordPos); + return getDictionaryStructurePolicy()->getProbabilityOfWord( + nullptr /* prevWordsPtNodePos */, wordId); } - int prevWordsPtNodePos[MAX_PREV_WORD_COUNT_FOR_N_GRAM]; - prevWordsInfo->getPrevWordsTerminalPtNodePos( - mDictionaryStructureWithBufferPolicy.get(), prevWordsPtNodePos, + int prevWordIds[MAX_PREV_WORD_COUNT_FOR_N_GRAM]; + prevWordsInfo->getPrevWordIds(mDictionaryStructureWithBufferPolicy.get(), prevWordIds, true /* tryLowerCaseSearch */); - return getDictionaryStructurePolicy()->getProbabilityOfPtNode(prevWordsPtNodePos, nextWordPos); + return getDictionaryStructurePolicy()->getProbabilityOfWord(prevWordIds, wordId); } bool Dictionary::addUnigramEntry(const int *const word, const int length, diff --git a/native/jni/src/suggest/core/dictionary/dictionary_utils.cpp b/native/jni/src/suggest/core/dictionary/dictionary_utils.cpp index b94966cbe..b372b6b4f 100644 --- a/native/jni/src/suggest/core/dictionary/dictionary_utils.cpp +++ b/native/jni/src/suggest/core/dictionary/dictionary_utils.cpp @@ -34,11 +34,11 @@ namespace latinime { // No prev words information. PrevWordsInfo emptyPrevWordsInfo; - int prevWordsPtNodePos[MAX_PREV_WORD_COUNT_FOR_N_GRAM]; - emptyPrevWordsInfo.getPrevWordsTerminalPtNodePos(dictionaryStructurePolicy, - prevWordsPtNodePos, false /* tryLowerCaseSearch */); + int prevWordIds[MAX_PREV_WORD_COUNT_FOR_N_GRAM]; + emptyPrevWordsInfo.getPrevWordIds(dictionaryStructurePolicy, prevWordIds, + false /* tryLowerCaseSearch */); current.emplace_back(); - DicNodeUtils::initAsRoot(dictionaryStructurePolicy, prevWordsPtNodePos, ¤t.front()); + DicNodeUtils::initAsRoot(dictionaryStructurePolicy, prevWordIds, ¤t.front()); for (int i = 0; i < codePointCount; ++i) { // The base-lower input is used to ignore case errors and accent errors. const int codePoint = CharUtils::toBaseLowerCase(codePoints[i]); diff --git a/native/jni/src/suggest/core/dictionary/multi_bigram_map.cpp b/native/jni/src/suggest/core/dictionary/multi_bigram_map.cpp index 91f33a8dd..979d61edb 100644 --- a/native/jni/src/suggest/core/dictionary/multi_bigram_map.cpp +++ b/native/jni/src/suggest/core/dictionary/multi_bigram_map.cpp @@ -35,39 +35,37 @@ const int MultiBigramMap::BigramMap::DEFAULT_HASH_MAP_SIZE_FOR_EACH_BIGRAM_MAP = // Also caches the bigrams if there is space remaining and they have not been cached already. int MultiBigramMap::getBigramProbability( const DictionaryStructureWithBufferPolicy *const structurePolicy, - const int *const prevWordsPtNodePos, const int nextWordPosition, + const int *const prevWordIds, const int nextWordId, const int unigramProbability) { - if (!prevWordsPtNodePos || prevWordsPtNodePos[0] == NOT_A_DICT_POS) { + if (!prevWordIds || prevWordIds[0] == NOT_A_WORD_ID) { return structurePolicy->getProbability(unigramProbability, NOT_A_PROBABILITY); } - std::unordered_map<int, BigramMap>::const_iterator mapPosition = - mBigramMaps.find(prevWordsPtNodePos[0]); + const auto mapPosition = mBigramMaps.find(prevWordIds[0]); if (mapPosition != mBigramMaps.end()) { - return mapPosition->second.getBigramProbability(structurePolicy, nextWordPosition, + return mapPosition->second.getBigramProbability(structurePolicy, nextWordId, unigramProbability); } if (mBigramMaps.size() < MAX_CACHED_PREV_WORDS_IN_BIGRAM_MAP) { - addBigramsForWordPosition(structurePolicy, prevWordsPtNodePos); - return mBigramMaps[prevWordsPtNodePos[0]].getBigramProbability(structurePolicy, - nextWordPosition, unigramProbability); + addBigramsForWord(structurePolicy, prevWordIds); + return mBigramMaps[prevWordIds[0]].getBigramProbability(structurePolicy, + nextWordId, unigramProbability); } - return readBigramProbabilityFromBinaryDictionary(structurePolicy, prevWordsPtNodePos, - nextWordPosition, unigramProbability); + return readBigramProbabilityFromBinaryDictionary(structurePolicy, prevWordIds, + nextWordId, unigramProbability); } void MultiBigramMap::BigramMap::init( const DictionaryStructureWithBufferPolicy *const structurePolicy, - const int *const prevWordsPtNodePos) { - structurePolicy->iterateNgramEntries(prevWordsPtNodePos, this /* listener */); + const int *const prevWordIds) { + structurePolicy->iterateNgramEntries(prevWordIds, this /* listener */); } int MultiBigramMap::BigramMap::getBigramProbability( const DictionaryStructureWithBufferPolicy *const structurePolicy, - const int nextWordPosition, const int unigramProbability) const { + const int nextWordId, const int unigramProbability) const { int bigramProbability = NOT_A_PROBABILITY; - if (mBloomFilter.isInFilter(nextWordPosition)) { - const std::unordered_map<int, int>::const_iterator bigramProbabilityIt = - mBigramMap.find(nextWordPosition); + if (mBloomFilter.isInFilter(nextWordId)) { + const auto bigramProbabilityIt = mBigramMap.find(nextWordId); if (bigramProbabilityIt != mBigramMap.end()) { bigramProbability = bigramProbabilityIt->second; } @@ -75,29 +73,27 @@ int MultiBigramMap::BigramMap::getBigramProbability( return structurePolicy->getProbability(unigramProbability, bigramProbability); } -void MultiBigramMap::BigramMap::onVisitEntry(const int ngramProbability, - const int targetPtNodePos) { - if (targetPtNodePos == NOT_A_DICT_POS) { +void MultiBigramMap::BigramMap::onVisitEntry(const int ngramProbability, const int targetWordId) { + if (targetWordId == NOT_A_WORD_ID) { return; } - mBigramMap[targetPtNodePos] = ngramProbability; - mBloomFilter.setInFilter(targetPtNodePos); + mBigramMap[targetWordId] = ngramProbability; + mBloomFilter.setInFilter(targetWordId); } -void MultiBigramMap::addBigramsForWordPosition( +void MultiBigramMap::addBigramsForWord( const DictionaryStructureWithBufferPolicy *const structurePolicy, - const int *const prevWordsPtNodePos) { - if (prevWordsPtNodePos) { - mBigramMaps[prevWordsPtNodePos[0]].init(structurePolicy, prevWordsPtNodePos); + const int *const prevWordIds) { + if (prevWordIds) { + mBigramMaps[prevWordIds[0]].init(structurePolicy, prevWordIds); } } int MultiBigramMap::readBigramProbabilityFromBinaryDictionary( const DictionaryStructureWithBufferPolicy *const structurePolicy, - const int *const prevWordsPtNodePos, const int nextWordPosition, + const int *const prevWordIds, const int nextWordId, const int unigramProbability) { - const int bigramProbability = structurePolicy->getProbabilityOfPtNode(prevWordsPtNodePos, - nextWordPosition); + const int bigramProbability = structurePolicy->getProbabilityOfWord(prevWordIds, nextWordId); if (bigramProbability != NOT_A_PROBABILITY) { return bigramProbability; } diff --git a/native/jni/src/suggest/core/dictionary/multi_bigram_map.h b/native/jni/src/suggest/core/dictionary/multi_bigram_map.h index ad36dde83..a8c4ded57 100644 --- a/native/jni/src/suggest/core/dictionary/multi_bigram_map.h +++ b/native/jni/src/suggest/core/dictionary/multi_bigram_map.h @@ -39,8 +39,7 @@ class MultiBigramMap { // Look up the bigram probability for the given word pair from the cached bigram maps. // Also caches the bigrams if there is space remaining and they have not been cached already. int getBigramProbability(const DictionaryStructureWithBufferPolicy *const structurePolicy, - const int *const prevWordsPtNodePos, const int nextWordPosition, - const int unigramProbability); + const int *const prevWordIds, const int nextWordId, const int unigramProbability); void clear() { mBigramMaps.clear(); @@ -58,11 +57,11 @@ class MultiBigramMap { virtual ~BigramMap() {} void init(const DictionaryStructureWithBufferPolicy *const structurePolicy, - const int *const prevWordsPtNodePos); + const int *const prevWordIds); int getBigramProbability( const DictionaryStructureWithBufferPolicy *const structurePolicy, - const int nextWordPosition, const int unigramProbability) const; - virtual void onVisitEntry(const int ngramProbability, const int targetPtNodePos); + const int nextWordId, const int unigramProbability) const; + virtual void onVisitEntry(const int ngramProbability, const int targetWordId); private: static const int DEFAULT_HASH_MAP_SIZE_FOR_EACH_BIGRAM_MAP; @@ -70,14 +69,12 @@ class MultiBigramMap { BloomFilter mBloomFilter; }; - void addBigramsForWordPosition( - const DictionaryStructureWithBufferPolicy *const structurePolicy, - const int *const prevWordsPtNodePos); + void addBigramsForWord(const DictionaryStructureWithBufferPolicy *const structurePolicy, + const int *const prevWordIds); int readBigramProbabilityFromBinaryDictionary( const DictionaryStructureWithBufferPolicy *const structurePolicy, - const int *const prevWordsPtNodePos, const int nextWordPosition, - const int unigramProbability); + const int *const prevWordIds, const int nextWordId, const int unigramProbability); static const size_t MAX_CACHED_PREV_WORDS_IN_BIGRAM_MAP; std::unordered_map<int, BigramMap> mBigramMaps; diff --git a/native/jni/src/suggest/core/dictionary/ngram_listener.h b/native/jni/src/suggest/core/dictionary/ngram_listener.h index 88b88bafb..e9b3c1aaf 100644 --- a/native/jni/src/suggest/core/dictionary/ngram_listener.h +++ b/native/jni/src/suggest/core/dictionary/ngram_listener.h @@ -26,7 +26,7 @@ namespace latinime { */ class NgramListener { public: - virtual void onVisitEntry(const int ngramProbability, const int targetPtNodePos) = 0; + virtual void onVisitEntry(const int ngramProbability, const int targetWordId) = 0; virtual ~NgramListener() {}; protected: diff --git a/native/jni/src/suggest/core/layout/geometry_utils.h b/native/jni/src/suggest/core/layout/geometry_utils.h index b667df68f..000fcd4a1 100644 --- a/native/jni/src/suggest/core/layout/geometry_utils.h +++ b/native/jni/src/suggest/core/layout/geometry_utils.h @@ -38,13 +38,15 @@ class GeometryUtils { } static AK_FORCE_INLINE float getAngleDiff(const float a1, const float a2) { - const float deltaA = fabsf(a1 - a2); - const float diff = ROUND_FLOAT_10000(deltaA); - if (diff > M_PI_F) { - const float normalizedDiff = 2.0f * M_PI_F - diff; - return ROUND_FLOAT_10000(normalizedDiff); + static const float M_2PI_F = M_PI * 2.0f; + float delta = fabsf(a1 - a2); + if (delta > M_2PI_F) { + delta -= (M_2PI_F * static_cast<int>(delta / M_2PI_F)); } - return diff; + if (delta > M_PI_F) { + delta = M_2PI_F - delta; + } + return ROUND_FLOAT_10000(delta); } static AK_FORCE_INLINE int getDistanceInt(const int x1, const int y1, const int x2, diff --git a/native/jni/src/suggest/core/policy/dictionary_structure_with_buffer_policy.h b/native/jni/src/suggest/core/policy/dictionary_structure_with_buffer_policy.h index 0faf00003..72ec13fe8 100644 --- a/native/jni/src/suggest/core/policy/dictionary_structure_with_buffer_policy.h +++ b/native/jni/src/suggest/core/policy/dictionary_structure_with_buffer_policy.h @@ -53,15 +53,14 @@ class DictionaryStructureWithBufferPolicy { const int ptNodePos, const int maxCodePointCount, int *const outCodePoints, int *const outUnigramProbability) const = 0; - virtual int getTerminalPtNodePositionOfWord(const CodePointArrayView wordCodePoints, + virtual int getWordId(const CodePointArrayView wordCodePoints, const bool forceLowerCaseSearch) const = 0; virtual int getProbability(const int unigramProbability, const int bigramProbability) const = 0; - virtual int getProbabilityOfPtNode(const int *const prevWordsPtNodePos, - const int ptNodePos) const = 0; + virtual int getProbabilityOfWord(const int *const prevWordIds, const int wordId) const = 0; - virtual void iterateNgramEntries(const int *const prevWordsPtNodePos, + virtual void iterateNgramEntries(const int *const prevWordIds, NgramListener *const listener) const = 0; virtual int getShortcutPositionOfPtNode(const int ptNodePos) const = 0; diff --git a/native/jni/src/suggest/core/session/dic_traverse_session.cpp b/native/jni/src/suggest/core/session/dic_traverse_session.cpp index f1e411f38..d4d4d1eed 100644 --- a/native/jni/src/suggest/core/session/dic_traverse_session.cpp +++ b/native/jni/src/suggest/core/session/dic_traverse_session.cpp @@ -35,8 +35,8 @@ void DicTraverseSession::init(const Dictionary *const dictionary, mMultiWordCostMultiplier = getDictionaryStructurePolicy()->getHeaderStructurePolicy() ->getMultiWordCostMultiplier(); mSuggestOptions = suggestOptions; - prevWordsInfo->getPrevWordsTerminalPtNodePos( - getDictionaryStructurePolicy(), mPrevWordsPtNodePos, true /* tryLowerCaseSearch */); + prevWordsInfo->getPrevWordIds(getDictionaryStructurePolicy(), mPrevWordsIds, + true /* tryLowerCaseSearch */); } void DicTraverseSession::setupForGetSuggestions(const ProximityInfo *pInfo, diff --git a/native/jni/src/suggest/core/session/dic_traverse_session.h b/native/jni/src/suggest/core/session/dic_traverse_session.h index 5a51a112d..0e676d897 100644 --- a/native/jni/src/suggest/core/session/dic_traverse_session.h +++ b/native/jni/src/suggest/core/session/dic_traverse_session.h @@ -55,8 +55,8 @@ class DicTraverseSession { mMultiWordCostMultiplier(1.0f) { // NOTE: mProximityInfoStates is an array of instances. // No need to initialize it explicitly here. - for (size_t i = 0; i < NELEMS(mPrevWordsPtNodePos); ++i) { - mPrevWordsPtNodePos[i] = NOT_A_DICT_POS; + for (size_t i = 0; i < NELEMS(mPrevWordsIds); ++i) { + mPrevWordsIds[i] = NOT_A_DICT_POS; } } @@ -79,7 +79,7 @@ class DicTraverseSession { //-------------------- const ProximityInfo *getProximityInfo() const { return mProximityInfo; } const SuggestOptions *getSuggestOptions() const { return mSuggestOptions; } - const int *getPrevWordsPtNodePos() const { return mPrevWordsPtNodePos; } + const int *getPrevWordIds() const { return mPrevWordsIds; } DicNodesCache *getDicTraverseCache() { return &mDicNodesCache; } MultiBigramMap *getMultiBigramMap() { return &mMultiBigramMap; } const ProximityInfoState *getProximityInfoState(int id) const { @@ -166,7 +166,7 @@ class DicTraverseSession { const int *const inputYs, const int *const times, const int *const pointerIds, const int inputSize, const float maxSpatialDistance, const int maxPointerCount); - int mPrevWordsPtNodePos[MAX_PREV_WORD_COUNT_FOR_N_GRAM]; + int mPrevWordsIds[MAX_PREV_WORD_COUNT_FOR_N_GRAM]; const ProximityInfo *mProximityInfo; const Dictionary *mDictionary; const SuggestOptions *mSuggestOptions; diff --git a/native/jni/src/suggest/core/session/prev_words_info.h b/native/jni/src/suggest/core/session/prev_words_info.h index 9b3a7d468..fc9a35968 100644 --- a/native/jni/src/suggest/core/session/prev_words_info.h +++ b/native/jni/src/suggest/core/session/prev_words_info.h @@ -18,14 +18,12 @@ #define LATINIME_PREV_WORDS_INFO_H #include "defines.h" -#include "suggest/core/dictionary/binary_dictionary_bigrams_iterator.h" #include "suggest/core/policy/dictionary_structure_with_buffer_policy.h" #include "utils/char_utils.h" #include "utils/int_array_view.h" namespace latinime { -// TODO: Support n-gram. class PrevWordsInfo { public: // No prev word information. @@ -81,11 +79,10 @@ class PrevWordsInfo { return false; } - void getPrevWordsTerminalPtNodePos( - const DictionaryStructureWithBufferPolicy *const dictStructurePolicy, - int *const outPrevWordsTerminalPtNodePos, const bool tryLowerCaseSearch) const { + void getPrevWordIds(const DictionaryStructureWithBufferPolicy *const dictStructurePolicy, + int *const outPrevWordIds, const bool tryLowerCaseSearch) const { for (size_t i = 0; i < NELEMS(mPrevWordCodePoints); ++i) { - outPrevWordsTerminalPtNodePos[i] = getTerminalPtNodePosOfWord(dictStructurePolicy, + outPrevWordIds[i] = getWordId(dictStructurePolicy, mPrevWordCodePoints[i], mPrevWordCodePointCount[i], mIsBeginningOfSentence[i], tryLowerCaseSearch); } @@ -110,12 +107,11 @@ class PrevWordsInfo { private: DISALLOW_COPY_AND_ASSIGN(PrevWordsInfo); - static int getTerminalPtNodePosOfWord( - const DictionaryStructureWithBufferPolicy *const dictStructurePolicy, + static int getWordId(const DictionaryStructureWithBufferPolicy *const dictStructurePolicy, const int *const wordCodePoints, const int wordCodePointCount, const bool isBeginningOfSentence, const bool tryLowerCaseSearch) { if (!dictStructurePolicy || !wordCodePoints || wordCodePointCount > MAX_WORD_LENGTH) { - return NOT_A_DICT_POS; + return NOT_A_WORD_ID; } int codePoints[MAX_WORD_LENGTH]; int codePointCount = wordCodePointCount; @@ -124,21 +120,19 @@ class PrevWordsInfo { codePointCount = CharUtils::attachBeginningOfSentenceMarker(codePoints, codePointCount, MAX_WORD_LENGTH); if (codePointCount <= 0) { - return NOT_A_DICT_POS; + return NOT_A_WORD_ID; } } const CodePointArrayView codePointArrayView(codePoints, codePointCount); - const int wordPtNodePos = dictStructurePolicy->getTerminalPtNodePositionOfWord( + const int wordId = dictStructurePolicy->getWordId( codePointArrayView, false /* forceLowerCaseSearch */); - if (wordPtNodePos != NOT_A_DICT_POS || !tryLowerCaseSearch) { - // Return the position when when the word was found or doesn't try lower case - // search. - return wordPtNodePos; + if (wordId != NOT_A_WORD_ID || !tryLowerCaseSearch) { + // Return the id when when the word was found or doesn't try lower case search. + return wordId; } // Check bigrams for lower-cased previous word if original was not found. Useful for // auto-capitalized words like "The [current_word]". - return dictStructurePolicy->getTerminalPtNodePositionOfWord( - codePointArrayView, true /* forceLowerCaseSearch */); + return dictStructurePolicy->getWordId(codePointArrayView, true /* forceLowerCaseSearch */); } void clear() { diff --git a/native/jni/src/suggest/core/suggest.cpp b/native/jni/src/suggest/core/suggest.cpp index 0cd305f5a..66c87f04c 100644 --- a/native/jni/src/suggest/core/suggest.cpp +++ b/native/jni/src/suggest/core/suggest.cpp @@ -92,7 +92,7 @@ void Suggest::initializeSearch(DicTraverseSession *traverseSession) const { // Create a new dic node here DicNode rootNode; DicNodeUtils::initAsRoot(traverseSession->getDictionaryStructurePolicy(), - traverseSession->getPrevWordsPtNodePos(), &rootNode); + traverseSession->getPrevWordIds(), &rootNode); traverseSession->getDicTraverseCache()->copyPushActive(&rootNode); } } diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/ver4_patricia_trie_policy.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/ver4_patricia_trie_policy.cpp index 9f6ae114d..5dff1fc97 100644 --- a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/ver4_patricia_trie_policy.cpp +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/ver4_patricia_trie_policy.cpp @@ -104,7 +104,7 @@ int Ver4PatriciaTriePolicy::getCodePointsAndProbabilityAndReturnCodePointCount( return codePointCount; } -int Ver4PatriciaTriePolicy::getTerminalPtNodePositionOfWord(const CodePointArrayView wordCodePoints, +int Ver4PatriciaTriePolicy::getWordId(const CodePointArrayView wordCodePoints, const bool forceLowerCaseSearch) const { DynamicPtReadingHelper readingHelper(&mNodeReader, &mPtNodeArrayReader); readingHelper.initWithPtNodeArrayPos(getRootPosition()); @@ -112,9 +112,9 @@ int Ver4PatriciaTriePolicy::getTerminalPtNodePositionOfWord(const CodePointArray wordCodePoints.size(), forceLowerCaseSearch); if (readingHelper.isError()) { mIsCorrupted = true; - AKLOGE("Dictionary reading error in createAndGetAllChildDicNodes()."); + AKLOGE("Dictionary reading error in getWordId()."); } - return ptNodePos; + return getWordIdFromTerminalPtNodePos(ptNodePos); } int Ver4PatriciaTriePolicy::getProbability(const int unigramProbability, @@ -133,17 +133,19 @@ int Ver4PatriciaTriePolicy::getProbability(const int unigramProbability, } } -int Ver4PatriciaTriePolicy::getProbabilityOfPtNode(const int *const prevWordsPtNodePos, - const int ptNodePos) const { - if (ptNodePos == NOT_A_DICT_POS) { +int Ver4PatriciaTriePolicy::getProbabilityOfWord(const int *const prevWordIds, + const int wordId) const { + if (wordId == NOT_A_WORD_ID) { return NOT_A_PROBABILITY; } + const int ptNodePos = getTerminalPtNodePosFromWordId(wordId); const PtNodeParams ptNodeParams(mNodeReader.fetchPtNodeParamsInBufferFromPtNodePos(ptNodePos)); if (ptNodeParams.isDeleted() || ptNodeParams.isBlacklisted() || ptNodeParams.isNotAWord()) { return NOT_A_PROBABILITY; } - if (prevWordsPtNodePos) { - const int bigramsPosition = getBigramsPositionOfPtNode(prevWordsPtNodePos[0]); + if (prevWordIds) { + const int bigramsPosition = getBigramsPositionOfPtNode( + getTerminalPtNodePosFromWordId(prevWordIds[0])); BinaryDictionaryBigramsIterator bigramsIt(&mBigramPolicy, bigramsPosition); while (bigramsIt.hasNext()) { bigramsIt.next(); @@ -157,16 +159,18 @@ int Ver4PatriciaTriePolicy::getProbabilityOfPtNode(const int *const prevWordsPtN return getProbability(ptNodeParams.getProbability(), NOT_A_PROBABILITY); } -void Ver4PatriciaTriePolicy::iterateNgramEntries(const int *const prevWordsPtNodePos, +void Ver4PatriciaTriePolicy::iterateNgramEntries(const int *const prevWordIds, NgramListener *const listener) const { - if (!prevWordsPtNodePos) { + if (!prevWordIds) { return; } - const int bigramsPosition = getBigramsPositionOfPtNode(prevWordsPtNodePos[0]); + const int bigramsPosition = getBigramsPositionOfPtNode( + getTerminalPtNodePosFromWordId(prevWordIds[0])); BinaryDictionaryBigramsIterator bigramsIt(&mBigramPolicy, bigramsPosition); while (bigramsIt.hasNext()) { bigramsIt.next(); - listener->onVisitEntry(bigramsIt.getProbability(), bigramsIt.getBigramPos()); + listener->onVisitEntry(bigramsIt.getProbability(), + getWordIdFromTerminalPtNodePos(bigramsIt.getBigramPos())); } } @@ -238,8 +242,8 @@ bool Ver4PatriciaTriePolicy::addUnigramEntry(const CodePointArrayView wordCodePo } if (unigramProperty->getShortcuts().size() > 0) { // Add shortcut target. - const int wordPos = getTerminalPtNodePositionOfWord(codePointArrayView, - false /* forceLowerCaseSearch */); + const int wordPos = getTerminalPtNodePosFromWordId( + getWordId(codePointArrayView, false /* forceLowerCaseSearch */)); if (wordPos == NOT_A_DICT_POS) { AKLOGE("Cannot find terminal PtNode position to add shortcut target."); return false; @@ -266,8 +270,8 @@ bool Ver4PatriciaTriePolicy::removeUnigramEntry(const CodePointArrayView wordCod AKLOGI("Warning: removeUnigramEntry() is called for non-updatable dictionary."); return false; } - const int ptNodePos = getTerminalPtNodePositionOfWord(wordCodePoints, - false /* forceLowerCaseSearch */); + const int ptNodePos = getTerminalPtNodePosFromWordId( + getWordId(wordCodePoints, false /* forceLowerCaseSearch */)); if (ptNodePos == NOT_A_DICT_POS) { return false; } @@ -295,11 +299,9 @@ bool Ver4PatriciaTriePolicy::addNgramEntry(const PrevWordsInfo *const prevWordsI "length: %zd", bigramProperty->getTargetCodePoints()->size()); return false; } - int prevWordsPtNodePos[MAX_PREV_WORD_COUNT_FOR_N_GRAM]; - prevWordsInfo->getPrevWordsTerminalPtNodePos(this, prevWordsPtNodePos, - false /* tryLowerCaseSearch */); - // TODO: Support N-gram. - if (prevWordsPtNodePos[0] == NOT_A_DICT_POS) { + int prevWordIds[MAX_PREV_WORD_COUNT_FOR_N_GRAM]; + prevWordsInfo->getPrevWordIds(this, prevWordIds, false /* tryLowerCaseSearch */); + if (prevWordIds[0] == NOT_A_WORD_ID) { if (prevWordsInfo->isNthPrevWordBeginningOfSentence(1 /* n */)) { const std::vector<UnigramProperty::ShortcutProperty> shortcuts; const UnigramProperty beginningOfSentenceUnigramProperty( @@ -311,22 +313,22 @@ bool Ver4PatriciaTriePolicy::addNgramEntry(const PrevWordsInfo *const prevWordsI AKLOGE("Cannot add unigram entry for the beginning-of-sentence."); return false; } - // Refresh Terminal PtNode positions. - prevWordsInfo->getPrevWordsTerminalPtNodePos(this, prevWordsPtNodePos, - false /* tryLowerCaseSearch */); + // Refresh word ids. + prevWordsInfo->getPrevWordIds(this, prevWordIds, false /* tryLowerCaseSearch */); } else { return false; } } - const int word1Pos = getTerminalPtNodePositionOfWord( + const int wordPos = getTerminalPtNodePosFromWordId(getWordId( CodePointArrayView(*bigramProperty->getTargetCodePoints()), - false /* forceLowerCaseSearch */); - if (word1Pos == NOT_A_DICT_POS) { + false /* forceLowerCaseSearch */)); + if (wordPos == NOT_A_DICT_POS) { return false; } bool addedNewBigram = false; - if (mUpdatingHelper.addNgramEntry(PtNodePosArrayView::fromObject(prevWordsPtNodePos), - word1Pos, bigramProperty, &addedNewBigram)) { + const int prevWordPtNodePos = getTerminalPtNodePosFromWordId(prevWordIds[0]); + if (mUpdatingHelper.addNgramEntry(PtNodePosArrayView::fromObject(&prevWordPtNodePos), + wordPos, bigramProperty, &addedNewBigram)) { if (addedNewBigram) { mBigramCount++; } @@ -355,20 +357,19 @@ bool Ver4PatriciaTriePolicy::removeNgramEntry(const PrevWordsInfo *const prevWor AKLOGE("word is too long to remove n-gram entry form the dictionary. length: %zd", wordCodePoints.size()); } - int prevWordsPtNodePos[MAX_PREV_WORD_COUNT_FOR_N_GRAM]; - prevWordsInfo->getPrevWordsTerminalPtNodePos(this, prevWordsPtNodePos, - false /* tryLowerCaseSerch */); - // TODO: Support N-gram. - if (prevWordsPtNodePos[0] == NOT_A_DICT_POS) { + int prevWordIds[MAX_PREV_WORD_COUNT_FOR_N_GRAM]; + prevWordsInfo->getPrevWordIds(this, prevWordIds, false /* tryLowerCaseSerch */); + if (prevWordIds[0] == NOT_A_WORD_ID) { return false; } - const int wordPos = getTerminalPtNodePositionOfWord(wordCodePoints, - false /* forceLowerCaseSearch */); + const int wordPos = getTerminalPtNodePosFromWordId(getWordId(wordCodePoints, + false /* forceLowerCaseSearch */)); if (wordPos == NOT_A_DICT_POS) { return false; } + const int prevWordPtNodePos = getTerminalPtNodePosFromWordId(prevWordIds[0]); if (mUpdatingHelper.removeNgramEntry( - PtNodePosArrayView::fromObject(prevWordsPtNodePos), wordPos)) { + PtNodePosArrayView::fromObject(&prevWordPtNodePos), wordPos)) { mBigramCount--; return true; } else { @@ -449,8 +450,8 @@ void Ver4PatriciaTriePolicy::getProperty(const char *const query, const int quer const WordProperty Ver4PatriciaTriePolicy::getWordProperty( const CodePointArrayView wordCodePoints) const { - const int ptNodePos = getTerminalPtNodePositionOfWord(wordCodePoints, - false /* forceLowerCaseSearch */); + const int ptNodePos = getTerminalPtNodePosFromWordId( + getWordId(wordCodePoints, false /* forceLowerCaseSearch */)); if (ptNodePos == NOT_A_DICT_POS) { AKLOGE("getWordProperty is called for invalid word."); return WordProperty(); @@ -553,6 +554,14 @@ int Ver4PatriciaTriePolicy::getNextWordAndNextToken(const int token, int *const return nextToken; } +int Ver4PatriciaTriePolicy::getWordIdFromTerminalPtNodePos(const int ptNodePos) const { + return ptNodePos == NOT_A_DICT_POS ? NOT_A_WORD_ID : ptNodePos; +} + +int Ver4PatriciaTriePolicy::getTerminalPtNodePosFromWordId(const int wordId) const { + return wordId == NOT_A_WORD_ID ? NOT_A_DICT_POS : wordId; +} + } // namespace v402 } // namespace backward } // namespace latinime diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/ver4_patricia_trie_policy.h b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/ver4_patricia_trie_policy.h index df119e3a1..508a46c5e 100644 --- a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/ver4_patricia_trie_policy.h +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/ver4_patricia_trie_policy.h @@ -28,6 +28,7 @@ #include <vector> #include "defines.h" +#include "suggest/core/dictionary/binary_dictionary_bigrams_iterator.h" #include "suggest/core/policy/dictionary_structure_with_buffer_policy.h" #include "suggest/policyimpl/dictionary/header/header_policy.h" #include "suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_updating_helper.h" @@ -87,15 +88,13 @@ class Ver4PatriciaTriePolicy : public DictionaryStructureWithBufferPolicy { const int terminalPtNodePos, const int maxCodePointCount, int *const outCodePoints, int *const outUnigramProbability) const; - int getTerminalPtNodePositionOfWord(const CodePointArrayView wordCodePoints, - const bool forceLowerCaseSearch) const; + int getWordId(const CodePointArrayView wordCodePoints, const bool forceLowerCaseSearch) const; int getProbability(const int unigramProbability, const int bigramProbability) const; - int getProbabilityOfPtNode(const int *const prevWordsPtNodePos, const int ptNodePos) const; + int getProbabilityOfWord(const int *const prevWordIds, const int wordId) const; - void iterateNgramEntries(const int *const prevWordsPtNodePos, - NgramListener *const listener) const; + void iterateNgramEntries(const int *const prevWordIds, NgramListener *const listener) const; int getShortcutPositionOfPtNode(const int ptNodePos) const; @@ -164,6 +163,8 @@ class Ver4PatriciaTriePolicy : public DictionaryStructureWithBufferPolicy { mutable bool mIsCorrupted; int getBigramsPositionOfPtNode(const int ptNodePos) const; + int getWordIdFromTerminalPtNodePos(const int ptNodePos) const; + int getTerminalPtNodePosFromWordId(const int wordId) const; }; } // namespace v402 } // namespace backward diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v2/patricia_trie_policy.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/v2/patricia_trie_policy.cpp index 4ac366e07..85971f1f2 100644 --- a/native/jni/src/suggest/policyimpl/dictionary/structure/v2/patricia_trie_policy.cpp +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v2/patricia_trie_policy.cpp @@ -267,8 +267,8 @@ int PatriciaTriePolicy::getCodePointsAndProbabilityAndReturnCodePointCount( } // This function gets the position of the terminal PtNode of the exact matching word in the -// dictionary. If no match is found, it returns NOT_A_DICT_POS. -int PatriciaTriePolicy::getTerminalPtNodePositionOfWord(const CodePointArrayView wordCodePoints, +// dictionary. If no match is found, it returns NOT_A_WORD_ID. +int PatriciaTriePolicy::getWordId(const CodePointArrayView wordCodePoints, const bool forceLowerCaseSearch) const { DynamicPtReadingHelper readingHelper(&mPtNodeReader, &mPtNodeArrayReader); readingHelper.initWithPtNodeArrayPos(getRootPosition()); @@ -276,9 +276,9 @@ int PatriciaTriePolicy::getTerminalPtNodePositionOfWord(const CodePointArrayView wordCodePoints.size(), forceLowerCaseSearch); if (readingHelper.isError()) { mIsCorrupted = true; - AKLOGE("Dictionary reading error in createAndGetAllChildDicNodes()."); + AKLOGE("Dictionary reading error in getWordId()."); } - return ptNodePos; + return getWordIdFromTerminalPtNodePos(ptNodePos); } int PatriciaTriePolicy::getProbability(const int unigramProbability, @@ -297,11 +297,11 @@ int PatriciaTriePolicy::getProbability(const int unigramProbability, } } -int PatriciaTriePolicy::getProbabilityOfPtNode(const int *const prevWordsPtNodePos, - const int ptNodePos) const { - if (ptNodePos == NOT_A_DICT_POS) { +int PatriciaTriePolicy::getProbabilityOfWord(const int *const prevWordIds, const int wordId) const { + if (wordId == NOT_A_WORD_ID) { return NOT_A_PROBABILITY; } + const int ptNodePos = getTerminalPtNodePosFromWordId(wordId); const PtNodeParams ptNodeParams = mPtNodeReader.fetchPtNodeParamsInBufferFromPtNodePos(ptNodePos); if (ptNodeParams.isNotAWord() || ptNodeParams.isBlacklisted()) { @@ -310,8 +310,9 @@ int PatriciaTriePolicy::getProbabilityOfPtNode(const int *const prevWordsPtNodeP // for shortcuts). return NOT_A_PROBABILITY; } - if (prevWordsPtNodePos) { - const int bigramsPosition = getBigramsPositionOfPtNode(prevWordsPtNodePos[0]); + if (prevWordIds) { + const int bigramsPosition = getBigramsPositionOfPtNode( + getTerminalPtNodePosFromWordId(prevWordIds[0])); BinaryDictionaryBigramsIterator bigramsIt(&mBigramListPolicy, bigramsPosition); while (bigramsIt.hasNext()) { bigramsIt.next(); @@ -325,16 +326,18 @@ int PatriciaTriePolicy::getProbabilityOfPtNode(const int *const prevWordsPtNodeP return getProbability(ptNodeParams.getProbability(), NOT_A_PROBABILITY); } -void PatriciaTriePolicy::iterateNgramEntries(const int *const prevWordsPtNodePos, +void PatriciaTriePolicy::iterateNgramEntries(const int *const prevWordIds, NgramListener *const listener) const { - if (!prevWordsPtNodePos) { + if (!prevWordIds) { return; } - const int bigramsPosition = getBigramsPositionOfPtNode(prevWordsPtNodePos[0]); + const int bigramsPosition = getBigramsPositionOfPtNode( + getTerminalPtNodePosFromWordId(prevWordIds[0])); BinaryDictionaryBigramsIterator bigramsIt(&mBigramListPolicy, bigramsPosition); while (bigramsIt.hasNext()) { bigramsIt.next(); - listener->onVisitEntry(bigramsIt.getProbability(), bigramsIt.getBigramPos()); + listener->onVisitEntry(bigramsIt.getProbability(), + getWordIdFromTerminalPtNodePos(bigramsIt.getBigramPos())); } } @@ -379,12 +382,12 @@ int PatriciaTriePolicy::createAndGetLeavingChildNode(const DicNode *const dicNod const WordProperty PatriciaTriePolicy::getWordProperty( const CodePointArrayView wordCodePoints) const { - const int ptNodePos = getTerminalPtNodePositionOfWord(wordCodePoints, - false /* forceLowerCaseSearch */); - if (ptNodePos == NOT_A_DICT_POS) { + const int wordId = getWordId(wordCodePoints, false /* forceLowerCaseSearch */); + if (wordId == NOT_A_WORD_ID) { AKLOGE("getWordProperty was called for invalid word."); return WordProperty(); } + const int ptNodePos = getTerminalPtNodePosFromWordId(wordId); const PtNodeParams ptNodeParams = mPtNodeReader.fetchPtNodeParamsInBufferFromPtNodePos(ptNodePos); std::vector<int> codePointVector(ptNodeParams.getCodePoints(), @@ -467,4 +470,11 @@ int PatriciaTriePolicy::getNextWordAndNextToken(const int token, int *const outC return nextToken; } +int PatriciaTriePolicy::getWordIdFromTerminalPtNodePos(const int ptNodePos) const { + return ptNodePos == NOT_A_DICT_POS ? NOT_A_WORD_ID : ptNodePos; +} + +int PatriciaTriePolicy::getTerminalPtNodePosFromWordId(const int wordId) const { + return wordId == NOT_A_WORD_ID ? NOT_A_DICT_POS : wordId; +} } // namespace latinime diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v2/patricia_trie_policy.h b/native/jni/src/suggest/policyimpl/dictionary/structure/v2/patricia_trie_policy.h index 4d9af2877..31fee7742 100644 --- a/native/jni/src/suggest/policyimpl/dictionary/structure/v2/patricia_trie_policy.h +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v2/patricia_trie_policy.h @@ -64,15 +64,13 @@ class PatriciaTriePolicy : public DictionaryStructureWithBufferPolicy { const int terminalNodePos, const int maxCodePointCount, int *const outCodePoints, int *const outUnigramProbability) const; - int getTerminalPtNodePositionOfWord(const CodePointArrayView wordCodePoints, - const bool forceLowerCaseSearch) const; + int getWordId(const CodePointArrayView wordCodePoints, const bool forceLowerCaseSearch) const; int getProbability(const int unigramProbability, const int bigramProbability) const; - int getProbabilityOfPtNode(const int *const prevWordsPtNodePos, const int ptNodePos) const; + int getProbabilityOfWord(const int *const prevWordIds, const int wordId) const; - void iterateNgramEntries(const int *const prevWordsPtNodePos, - NgramListener *const listener) const; + void iterateNgramEntries(const int *const prevWordIds, NgramListener *const listener) const; int getShortcutPositionOfPtNode(const int ptNodePos) const; @@ -163,6 +161,8 @@ class PatriciaTriePolicy : public DictionaryStructureWithBufferPolicy { int getBigramsPositionOfPtNode(const int ptNodePos) const; int createAndGetLeavingChildNode(const DicNode *const dicNode, const int ptNodePos, DicNodeVector *const childDicNodes) const; + int getWordIdFromTerminalPtNodePos(const int ptNodePos) const; + int getTerminalPtNodePosFromWordId(const int wordId) const; }; } // namespace latinime #endif // LATINIME_PATRICIA_TRIE_POLICY_H diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_policy.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_policy.cpp index 619cdb59b..7024682f6 100644 --- a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_policy.cpp +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_policy.cpp @@ -94,7 +94,7 @@ int Ver4PatriciaTriePolicy::getCodePointsAndProbabilityAndReturnCodePointCount( return codePointCount; } -int Ver4PatriciaTriePolicy::getTerminalPtNodePositionOfWord(const CodePointArrayView wordCodePoints, +int Ver4PatriciaTriePolicy::getWordId(const CodePointArrayView wordCodePoints, const bool forceLowerCaseSearch) const { DynamicPtReadingHelper readingHelper(&mNodeReader, &mPtNodeArrayReader); readingHelper.initWithPtNodeArrayPos(getRootPosition()); @@ -104,7 +104,11 @@ int Ver4PatriciaTriePolicy::getTerminalPtNodePositionOfWord(const CodePointArray mIsCorrupted = true; AKLOGE("Dictionary reading error in createAndGetAllChildDicNodes()."); } - return ptNodePos; + if (ptNodePos == NOT_A_DICT_POS) { + return NOT_A_WORD_ID; + } + const PtNodeParams ptNodeParams = mNodeReader.fetchPtNodeParamsInBufferFromPtNodePos(ptNodePos); + return ptNodeParams.getTerminalId(); } int Ver4PatriciaTriePolicy::getProbability(const int unigramProbability, @@ -123,24 +127,22 @@ int Ver4PatriciaTriePolicy::getProbability(const int unigramProbability, } } -int Ver4PatriciaTriePolicy::getProbabilityOfPtNode(const int *const prevWordsPtNodePos, - const int ptNodePos) const { - if (ptNodePos == NOT_A_DICT_POS) { +int Ver4PatriciaTriePolicy::getProbabilityOfWord(const int *const prevWordIds, + const int wordId) const { + if (wordId == NOT_A_WORD_ID) { return NOT_A_PROBABILITY; } + const int ptNodePos = + mBuffers->getTerminalPositionLookupTable()->getTerminalPtNodePosition(wordId); const PtNodeParams ptNodeParams = mNodeReader.fetchPtNodeParamsInBufferFromPtNodePos(ptNodePos); if (ptNodeParams.isDeleted() || ptNodeParams.isBlacklisted() || ptNodeParams.isNotAWord()) { return NOT_A_PROBABILITY; } - if (prevWordsPtNodePos) { + if (prevWordIds) { // TODO: Support n-gram. - const PtNodeParams prevWordPtNodeParams = - mNodeReader.fetchPtNodeParamsInBufferFromPtNodePos(prevWordsPtNodePos[0]); - const int prevWordTerminalId = prevWordPtNodeParams.getTerminalId(); const ProbabilityEntry probabilityEntry = mBuffers->getLanguageModelDictContent()->getNgramProbabilityEntry( - IntArrayView::fromObject(&prevWordTerminalId), - ptNodeParams.getTerminalId()); + IntArrayView::fromObject(prevWordIds), wordId); if (!probabilityEntry.isValid()) { return NOT_A_PROBABILITY; } @@ -154,26 +156,21 @@ int Ver4PatriciaTriePolicy::getProbabilityOfPtNode(const int *const prevWordsPtN return getProbability(ptNodeParams.getProbability(), NOT_A_PROBABILITY); } -void Ver4PatriciaTriePolicy::iterateNgramEntries(const int *const prevWordsPtNodePos, +void Ver4PatriciaTriePolicy::iterateNgramEntries(const int *const prevWordIds, NgramListener *const listener) const { - if (!prevWordsPtNodePos) { + if (!prevWordIds) { return; } // TODO: Support n-gram. - const PtNodeParams ptNodeParams = - mNodeReader.fetchPtNodeParamsInBufferFromPtNodePos(prevWordsPtNodePos[0]); - const int prevWordId = ptNodeParams.getTerminalId(); - const WordIdArrayView prevWordIds = WordIdArrayView::fromObject(&prevWordId); const auto languageModelDictContent = mBuffers->getLanguageModelDictContent(); - for (const auto entry : languageModelDictContent->getProbabilityEntries(prevWordIds)) { + for (const auto entry : languageModelDictContent->getProbabilityEntries( + WordIdArrayView::fromObject(prevWordIds))) { const ProbabilityEntry &probabilityEntry = entry.getProbabilityEntry(); const int probability = probabilityEntry.hasHistoricalInfo() ? ForgettingCurveUtils::decodeProbability( probabilityEntry.getHistoricalInfo(), mHeaderPolicy) : probabilityEntry.getProbability(); - const int ptNodePos = mBuffers->getTerminalPositionLookupTable()->getTerminalPtNodePosition( - entry.getWordId()); - listener->onVisitEntry(probability, ptNodePos); + listener->onVisitEntry(probability, entry.getWordId()); } } @@ -233,12 +230,13 @@ bool Ver4PatriciaTriePolicy::addUnigramEntry(const CodePointArrayView wordCodePo } if (unigramProperty->getShortcuts().size() > 0) { // Add shortcut target. - const int wordPos = getTerminalPtNodePositionOfWord(codePointArrayView, - false /* forceLowerCaseSearch */); - if (wordPos == NOT_A_DICT_POS) { - AKLOGE("Cannot find terminal PtNode position to add shortcut target."); + const int wordId = getWordId(codePointArrayView, false /* forceLowerCaseSearch */); + if (wordId == NOT_A_WORD_ID) { + AKLOGE("Cannot find word id to add shortcut target."); return false; } + const int wordPos = + mBuffers->getTerminalPositionLookupTable()->getTerminalPtNodePosition(wordId); for (const auto &shortcut : unigramProperty->getShortcuts()) { if (!mUpdatingHelper.addShortcutTarget(wordPos, shortcut.getTargetCodePoints()->data(), @@ -261,20 +259,19 @@ bool Ver4PatriciaTriePolicy::removeUnigramEntry(const CodePointArrayView wordCod AKLOGI("Warning: removeUnigramEntry() is called for non-updatable dictionary."); return false; } - const int ptNodePos = getTerminalPtNodePositionOfWord(wordCodePoints, - false /* forceLowerCaseSearch */); - if (ptNodePos == NOT_A_DICT_POS) { + const int wordId = getWordId(wordCodePoints, false /* forceLowerCaseSearch */); + if (wordId == NOT_A_WORD_ID) { return false; } + const int ptNodePos = + mBuffers->getTerminalPositionLookupTable()->getTerminalPtNodePosition(wordId); const PtNodeParams ptNodeParams = mNodeReader.fetchPtNodeParamsInBufferFromPtNodePos(ptNodePos); if (!mNodeWriter.markPtNodeAsDeleted(&ptNodeParams)) { AKLOGE("Cannot remove unigram. ptNodePos: %d", ptNodePos); return false; } - if (!mBuffers->getMutableLanguageModelDictContent()->removeProbabilityEntry( - ptNodeParams.getTerminalId())) { - // TODO: Uncomment. - // return false; + if (!mBuffers->getMutableLanguageModelDictContent()->removeProbabilityEntry(wordId)) { + return false; } if (!ptNodeParams.representsNonWordInfo()) { mUnigramCount--; @@ -302,12 +299,10 @@ bool Ver4PatriciaTriePolicy::addNgramEntry(const PrevWordsInfo *const prevWordsI "length: %zd", bigramProperty->getTargetCodePoints()->size()); return false; } - int prevWordsPtNodePos[MAX_PREV_WORD_COUNT_FOR_N_GRAM]; - prevWordsInfo->getPrevWordsTerminalPtNodePos(this, prevWordsPtNodePos, - false /* tryLowerCaseSearch */); - const auto prevWordsPtNodePosView = PtNodePosArrayView::fromFixedSizeArray(prevWordsPtNodePos); + int prevWordIds[MAX_PREV_WORD_COUNT_FOR_N_GRAM]; + prevWordsInfo->getPrevWordIds(this, prevWordIds, false /* tryLowerCaseSearch */); // TODO: Support N-gram. - if (prevWordsPtNodePos[0] == NOT_A_DICT_POS) { + if (prevWordIds[0] == NOT_A_WORD_ID) { if (prevWordsInfo->isNthPrevWordBeginningOfSentence(1 /* n */)) { const std::vector<UnigramProperty::ShortcutProperty> shortcuts; const UnigramProperty beginningOfSentenceUnigramProperty( @@ -319,22 +314,27 @@ bool Ver4PatriciaTriePolicy::addNgramEntry(const PrevWordsInfo *const prevWordsI AKLOGE("Cannot add unigram entry for the beginning-of-sentence."); return false; } - // Refresh Terminal PtNode positions. - prevWordsInfo->getPrevWordsTerminalPtNodePos(this, prevWordsPtNodePos, - false /* tryLowerCaseSearch */); + // Refresh word ids. + prevWordsInfo->getPrevWordIds(this, prevWordIds, false /* tryLowerCaseSearch */); } else { return false; } } - const int word1Pos = getTerminalPtNodePositionOfWord( - CodePointArrayView(*bigramProperty->getTargetCodePoints()), + const int wordId = getWordId(CodePointArrayView(*bigramProperty->getTargetCodePoints()), false /* forceLowerCaseSearch */); - if (word1Pos == NOT_A_DICT_POS) { + if (wordId == NOT_A_WORD_ID) { return false; } bool addedNewEntry = false; - if (mUpdatingHelper.addNgramEntry(prevWordsPtNodePosView, word1Pos, bigramProperty, - &addedNewEntry)) { + int prevWordsPtNodePos[MAX_PREV_WORD_COUNT_FOR_N_GRAM]; + for (size_t i = 0; i < NELEMS(prevWordIds); ++i) { + prevWordsPtNodePos[i] = mBuffers->getTerminalPositionLookupTable() + ->getTerminalPtNodePosition(prevWordIds[i]); + } + const int wordPtNodePos = mBuffers->getTerminalPositionLookupTable() + ->getTerminalPtNodePosition(wordId); + if (mUpdatingHelper.addNgramEntry(WordIdArrayView::fromFixedSizeArray(prevWordsPtNodePos), + wordPtNodePos, bigramProperty, &addedNewEntry)) { if (addedNewEntry) { mBigramCount++; } @@ -363,20 +363,25 @@ bool Ver4PatriciaTriePolicy::removeNgramEntry(const PrevWordsInfo *const prevWor AKLOGE("word is too long to remove n-gram entry form the dictionary. length: %zd", wordCodePoints.size()); } - int prevWordsPtNodePos[MAX_PREV_WORD_COUNT_FOR_N_GRAM]; - prevWordsInfo->getPrevWordsTerminalPtNodePos(this, prevWordsPtNodePos, - false /* tryLowerCaseSerch */); - const auto prevWordsPtNodePosView = PtNodePosArrayView::fromFixedSizeArray(prevWordsPtNodePos); + int prevWordIds[MAX_PREV_WORD_COUNT_FOR_N_GRAM]; + prevWordsInfo->getPrevWordIds(this, prevWordIds, false /* tryLowerCaseSerch */); // TODO: Support N-gram. - if (prevWordsPtNodePos[0] == NOT_A_DICT_POS) { + if (prevWordIds[0] == NOT_A_WORD_ID) { return false; } - const int wordPos = getTerminalPtNodePositionOfWord(wordCodePoints, - false /* forceLowerCaseSearch */); - if (wordPos == NOT_A_DICT_POS) { + const int wordId = getWordId(wordCodePoints, false /* forceLowerCaseSearch */); + if (wordId == NOT_A_WORD_ID) { return false; } - if (mUpdatingHelper.removeNgramEntry(prevWordsPtNodePosView, wordPos)) { + int prevWordsPtNodePos[MAX_PREV_WORD_COUNT_FOR_N_GRAM]; + for (size_t i = 0; i < NELEMS(prevWordIds); ++i) { + prevWordsPtNodePos[i] = mBuffers->getTerminalPositionLookupTable() + ->getTerminalPtNodePosition(prevWordIds[i]); + } + const int wordPtNodePos = mBuffers->getTerminalPositionLookupTable() + ->getTerminalPtNodePosition(wordId); + if (mUpdatingHelper.removeNgramEntry(WordIdArrayView::fromFixedSizeArray(prevWordsPtNodePos), + wordPtNodePos)) { mBigramCount--; return true; } else { @@ -457,12 +462,13 @@ void Ver4PatriciaTriePolicy::getProperty(const char *const query, const int quer const WordProperty Ver4PatriciaTriePolicy::getWordProperty( const CodePointArrayView wordCodePoints) const { - const int ptNodePos = getTerminalPtNodePositionOfWord(wordCodePoints, - false /* forceLowerCaseSearch */); - if (ptNodePos == NOT_A_DICT_POS) { + const int wordId = getWordId(wordCodePoints, false /* forceLowerCaseSearch */); + if (wordId == NOT_A_WORD_ID) { AKLOGE("getWordProperty is called for invalid word."); return WordProperty(); } + const int ptNodePos = + mBuffers->getTerminalPositionLookupTable()->getTerminalPtNodePosition(wordId); const PtNodeParams ptNodeParams = mNodeReader.fetchPtNodeParamsInBufferFromPtNodePos(ptNodePos); std::vector<int> codePointVector(ptNodeParams.getCodePoints(), ptNodeParams.getCodePoints() + ptNodeParams.getCodePointCount()); @@ -473,7 +479,6 @@ const WordProperty Ver4PatriciaTriePolicy::getWordProperty( // Fetch bigram information. // TODO: Support n-gram. std::vector<BigramProperty> bigrams; - const int wordId = ptNodeParams.getTerminalId(); const WordIdArrayView prevWordIds = WordIdArrayView::fromObject(&wordId); const TerminalPositionLookupTable *const terminalPositionLookupTable = mBuffers->getTerminalPositionLookupTable(); diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_policy.h b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_policy.h index 24f92a4aa..1d2712a4b 100644 --- a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_policy.h +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_policy.h @@ -66,15 +66,13 @@ class Ver4PatriciaTriePolicy : public DictionaryStructureWithBufferPolicy { const int terminalPtNodePos, const int maxCodePointCount, int *const outCodePoints, int *const outUnigramProbability) const; - int getTerminalPtNodePositionOfWord(const CodePointArrayView wordCodePoints, - const bool forceLowerCaseSearch) const; + int getWordId(const CodePointArrayView wordCodePoints, const bool forceLowerCaseSearch) const; int getProbability(const int unigramProbability, const int bigramProbability) const; - int getProbabilityOfPtNode(const int *const prevWordsPtNodePos, const int ptNodePos) const; + int getProbabilityOfWord(const int *const prevWordIds, const int wordId) const; - void iterateNgramEntries(const int *const prevWordsPtNodePos, - NgramListener *const listener) const; + void iterateNgramEntries(const int *const prevWordIds, NgramListener *const listener) const; int getShortcutPositionOfPtNode(const int ptNodePos) const; diff --git a/native/jni/src/utils/char_utils.cpp b/native/jni/src/utils/char_utils.cpp index b17e0847d..3bb9055b2 100644 --- a/native/jni/src/utils/char_utils.cpp +++ b/native/jni/src/utils/char_utils.cpp @@ -1057,11 +1057,11 @@ static int compare_pair_capital(const void *a, const void *b) { - static_cast<int>((static_cast<const struct LatinCapitalSmallPair *>(b))->capital); } -/* static */ unsigned short CharUtils::latin_tolower(const unsigned short c) { +/* static */ int CharUtils::latin_tolower(const int c) { struct LatinCapitalSmallPair *p = static_cast<struct LatinCapitalSmallPair *>(bsearch(&c, SORTED_CHAR_MAP, NELEMS(SORTED_CHAR_MAP), sizeof(SORTED_CHAR_MAP[0]), compare_pair_capital)); - return p ? p->small : c; + return p ? static_cast<int>(p->small) : c; } /* diff --git a/native/jni/src/utils/char_utils.h b/native/jni/src/utils/char_utils.h index 63786502b..5e9cdd9b2 100644 --- a/native/jni/src/utils/char_utils.h +++ b/native/jni/src/utils/char_utils.h @@ -27,20 +27,14 @@ namespace latinime { class CharUtils { public: + static const std::vector<int> EMPTY_STRING; + static AK_FORCE_INLINE bool isAsciiUpper(int c) { // Note: isupper(...) reports false positives for some Cyrillic characters, causing them to // be incorrectly lower-cased using toAsciiLower(...) rather than latin_tolower(...). return (c >= 'A' && c <= 'Z'); } - static AK_FORCE_INLINE int toAsciiLower(int c) { - return c - 'A' + 'a'; - } - - static AK_FORCE_INLINE bool isAscii(int c) { - return isascii(c) != 0; - } - static AK_FORCE_INLINE int toLowerCase(const int c) { if (isAsciiUpper(c)) { return toAsciiLower(c); @@ -48,7 +42,7 @@ class CharUtils { if (isAscii(c)) { return c; } - return static_cast<int>(latin_tolower(static_cast<unsigned short>(c))); + return latin_tolower(c); } static AK_FORCE_INLINE int toBaseLowerCase(const int c) { @@ -59,7 +53,6 @@ class CharUtils { // TODO: Do not hardcode here return codePoint == KEYCODE_SINGLE_QUOTE || codePoint == KEYCODE_HYPHEN_MINUS; } - static AK_FORCE_INLINE int getCodePointCount(const int arraySize, const int *const codePoints) { int size = 0; for (; size < arraySize; ++size) { @@ -91,9 +84,6 @@ class CharUtils { return codePoint >= MIN_UNICODE_CODE_POINT && codePoint <= MAX_UNICODE_CODE_POINT; } - static unsigned short latin_tolower(const unsigned short c); - static const std::vector<int> EMPTY_STRING; - // Returns updated code point count. Returns 0 when the code points cannot be marked as a // Beginning-of-Sentence. static AK_FORCE_INLINE int attachBeginningOfSentenceMarker(int *const codePoints, @@ -125,6 +115,16 @@ class CharUtils { */ static const int BASE_CHARS_SIZE = 0x0500; static const unsigned short BASE_CHARS[BASE_CHARS_SIZE]; + + static AK_FORCE_INLINE bool isAscii(int c) { + return isascii(c) != 0; + } + + static AK_FORCE_INLINE int toAsciiLower(int c) { + return c - 'A' + 'a'; + } + + static int latin_tolower(const int c); }; } // namespace latinime #endif // LATINIME_CHAR_UTILS_H diff --git a/native/jni/tests/suggest/core/layout/geometry_utils_test.cpp b/native/jni/tests/suggest/core/layout/geometry_utils_test.cpp new file mode 100644 index 000000000..f5f89ede1 --- /dev/null +++ b/native/jni/tests/suggest/core/layout/geometry_utils_test.cpp @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2014 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. + */ + +#include "suggest/core/layout/geometry_utils.h" + +#include <gtest/gtest.h> + +namespace latinime { +namespace { + +::testing::AssertionResult ExpectAngleDiffEq(const char* expectedExpression, + const char* actualExpression, float expected, float actual) { + if (actual < 0.0f || M_PI_F < actual) { + return ::testing::AssertionFailure() + << "Must be in the range of [0.0f, M_PI_F]." + << " expected: " << expected + << " actual: " << actual; + } + return ::testing::internal::CmpHelperFloatingPointEQ<float>( + expectedExpression, actualExpression, expected, actual); +} + +#define EXPECT_ANGLE_DIFF_EQ(expected, actual) \ + EXPECT_PRED_FORMAT2(ExpectAngleDiffEq, expected, actual); + +TEST(GeometryUtilsTest, testSquareFloat) { + const float test_data[] = { 0.0f, 1.0f, 123.456f, -1.0f, -9876.54321f }; + for (const float value : test_data) { + EXPECT_FLOAT_EQ(value * value, GeometryUtils::SQUARE_FLOAT(value)); + } +} + +TEST(GeometryUtilsTest, testGetAngle) { + EXPECT_FLOAT_EQ(0.0f, GeometryUtils::getAngle(0, 0, 0, 0)); + EXPECT_FLOAT_EQ(0.0f, GeometryUtils::getAngle(100, -10, 100, -10)); + + EXPECT_FLOAT_EQ(M_PI_F / 4.0f, GeometryUtils::getAngle(1, 1, 0, 0)); + EXPECT_FLOAT_EQ(M_PI_F, GeometryUtils::getAngle(-1, 0, 0, 0)); + + EXPECT_FLOAT_EQ(GeometryUtils::getAngle(0, 0, -1, 0), GeometryUtils::getAngle(1, 0, 0, 0)); + EXPECT_FLOAT_EQ(GeometryUtils::getAngle(1, 2, 3, 4), + GeometryUtils::getAngle(100, 200, 300, 400)); +} + +TEST(GeometryUtilsTest, testGetAngleDiff) { + EXPECT_ANGLE_DIFF_EQ(0.0f, GeometryUtils::getAngleDiff(0.0f, 0.0f)); + EXPECT_ANGLE_DIFF_EQ(0.0f, GeometryUtils::getAngleDiff(10000.0f, 10000.0f)); + EXPECT_ANGLE_DIFF_EQ(ROUND_FLOAT_10000(M_PI_F), + GeometryUtils::getAngleDiff(0.0f, M_PI_F)); + EXPECT_ANGLE_DIFF_EQ(ROUND_FLOAT_10000(M_PI_F / 6.0f), + GeometryUtils::getAngleDiff(M_PI_F / 3.0f, M_PI_F / 2.0f)); + EXPECT_ANGLE_DIFF_EQ(ROUND_FLOAT_10000(M_PI_F / 2.0f), + GeometryUtils::getAngleDiff(0.0f, M_PI_F * 1.5f)); + EXPECT_ANGLE_DIFF_EQ(0.0f, GeometryUtils::getAngleDiff(0.0f, M_PI_F * 1024.0f)); + EXPECT_ANGLE_DIFF_EQ(0.0f, GeometryUtils::getAngleDiff(-M_PI_F, M_PI_F)); +} + +TEST(GeometryUtilsTest, testGetDistanceInt) { + EXPECT_EQ(0, GeometryUtils::getDistanceInt(0, 0, 0, 0)); + EXPECT_EQ(0, GeometryUtils::getAngle(100, -10, 100, -10)); + + EXPECT_EQ(5, GeometryUtils::getDistanceInt(0, 0, 5, 0)); + EXPECT_EQ(5, GeometryUtils::getDistanceInt(0, 0, 3, 4)); + EXPECT_EQ(5, GeometryUtils::getDistanceInt(0, -4, 3, 0)); + EXPECT_EQ(5, GeometryUtils::getDistanceInt(0, 0, -3, -4)); + EXPECT_EQ(500, GeometryUtils::getDistanceInt(0, 0, 300, -400)); +} + +} // namespace +} // namespace latinime diff --git a/native/jni/tests/suggest/policyimpl/utils/damerau_levenshtein_edit_distance_policy_test.cpp b/native/jni/tests/suggest/policyimpl/utils/damerau_levenshtein_edit_distance_policy_test.cpp new file mode 100644 index 000000000..d13417964 --- /dev/null +++ b/native/jni/tests/suggest/policyimpl/utils/damerau_levenshtein_edit_distance_policy_test.cpp @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2014 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. + */ + +#include "suggest/policyimpl/utils/damerau_levenshtein_edit_distance_policy.h" + +#include <gtest/gtest.h> + +#include <vector> + +#include "suggest/policyimpl/utils/edit_distance.h" +#include "utils/int_array_view.h" + +namespace latinime { +namespace { + +TEST(DamerauLevenshteinEditDistancePolicyTest, TestConstructPolicy) { + const std::vector<int> codePoints0 = { 0x20, 0x40, 0x60 }; + const std::vector<int> codePoints1 = { 0x10, 0x20, 0x30, 0x40, 0x50, 0x60 }; + DamerauLevenshteinEditDistancePolicy policy(codePoints0.data(), codePoints0.size(), + codePoints1.data(), codePoints1.size()); + + EXPECT_EQ(static_cast<int>(codePoints0.size()), policy.getString0Length()); + EXPECT_EQ(static_cast<int>(codePoints1.size()), policy.getString1Length()); +} + +float getEditDistance(const std::vector<int> &codePoints0, const std::vector<int> &codePoints1) { + DamerauLevenshteinEditDistancePolicy policy(codePoints0.data(), codePoints0.size(), + codePoints1.data(), codePoints1.size()); + return EditDistance::getEditDistance(&policy); +} + +TEST(DamerauLevenshteinEditDistancePolicyTest, TestEditDistance) { + EXPECT_FLOAT_EQ(0.0f, getEditDistance({}, {})); + EXPECT_FLOAT_EQ(0.0f, getEditDistance({ 1 }, { 1 })); + EXPECT_FLOAT_EQ(0.0f, getEditDistance({ 1, 2, 3 }, { 1, 2, 3 })); + + EXPECT_FLOAT_EQ(1.0f, getEditDistance({ 1 }, { })); + EXPECT_FLOAT_EQ(1.0f, getEditDistance({}, { 100 })); + EXPECT_FLOAT_EQ(5.0f, getEditDistance({}, { 1, 2, 3, 4, 5 })); + + EXPECT_FLOAT_EQ(1.0f, getEditDistance({ 0 }, { 100 })); + EXPECT_FLOAT_EQ(5.0f, getEditDistance({ 1, 2, 3, 4, 5 }, { 11, 12, 13, 14, 15 })); + + EXPECT_FLOAT_EQ(1.0f, getEditDistance({ 1 }, { 1, 2 })); + EXPECT_FLOAT_EQ(2.0f, getEditDistance({ 1, 2 }, { 0, 1, 2, 3 })); + EXPECT_FLOAT_EQ(2.0f, getEditDistance({ 0, 1, 2, 3 }, { 1, 2 })); + + EXPECT_FLOAT_EQ(1.0f, getEditDistance({ 1, 2 }, { 2, 1 })); + EXPECT_FLOAT_EQ(2.0f, getEditDistance({ 1, 2, 3, 4 }, { 2, 1, 4, 3 })); +} +} // namespace +} // namespace latinime diff --git a/native/jni/tests/utils/char_utils_test.cpp b/native/jni/tests/utils/char_utils_test.cpp new file mode 100644 index 000000000..01d534043 --- /dev/null +++ b/native/jni/tests/utils/char_utils_test.cpp @@ -0,0 +1,122 @@ +/* + * Copyright (C) 2014 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. + */ + +#include "utils/char_utils.h" + +#include <gtest/gtest.h> + +#include "defines.h" + +namespace latinime { +namespace { + +TEST(CharUtilsTest, TestIsAsciiUpper) { + EXPECT_TRUE(CharUtils::isAsciiUpper('A')); + EXPECT_TRUE(CharUtils::isAsciiUpper('Z')); + EXPECT_FALSE(CharUtils::isAsciiUpper('a')); + EXPECT_FALSE(CharUtils::isAsciiUpper('z')); + EXPECT_FALSE(CharUtils::isAsciiUpper('@')); + EXPECT_FALSE(CharUtils::isAsciiUpper(' ')); + EXPECT_FALSE(CharUtils::isAsciiUpper(0x00C0 /* LATIN CAPITAL LETTER A WITH GRAVE */)); + EXPECT_FALSE(CharUtils::isAsciiUpper(0x00E0 /* LATIN SMALL LETTER A WITH GRAVE */)); + EXPECT_FALSE(CharUtils::isAsciiUpper(0x03C2 /* GREEK SMALL LETTER FINAL SIGMA */)); + EXPECT_FALSE(CharUtils::isAsciiUpper(0x0410 /* CYRILLIC CAPITAL LETTER A */)); + EXPECT_FALSE(CharUtils::isAsciiUpper(0x0430 /* CYRILLIC SMALL LETTER A */)); + EXPECT_FALSE(CharUtils::isAsciiUpper(0x3042 /* HIRAGANA LETTER A */)); + EXPECT_FALSE(CharUtils::isAsciiUpper(0x1F36A /* COOKIE */)); +} + +TEST(CharUtilsTest, TestToLowerCase) { + EXPECT_EQ('a', CharUtils::toLowerCase('A')); + EXPECT_EQ('z', CharUtils::toLowerCase('Z')); + EXPECT_EQ('a', CharUtils::toLowerCase('a')); + EXPECT_EQ('z', CharUtils::toLowerCase('z')); + EXPECT_EQ('@', CharUtils::toLowerCase('@')); + EXPECT_EQ(' ', CharUtils::toLowerCase(' ')); + EXPECT_EQ(0x00E0 /* LATIN SMALL LETTER A WITH GRAVE */, + CharUtils::toLowerCase(0x00C0 /* LATIN CAPITAL LETTER A WITH GRAVE */)); + EXPECT_EQ(0x00E0 /* LATIN SMALL LETTER A WITH GRAVE */, + CharUtils::toLowerCase(0x00E0 /* LATIN SMALL LETTER A WITH GRAVE */)); + EXPECT_EQ(0x03C2 /* GREEK SMALL LETTER FINAL SIGMA */, + CharUtils::toLowerCase(0x03C2 /* GREEK SMALL LETTER FINAL SIGMA */)); + EXPECT_EQ(0x0430 /* CYRILLIC SMALL LETTER A */, + CharUtils::toLowerCase(0x0410 /* CYRILLIC CAPITAL LETTER A */)); + EXPECT_EQ(0x0430 /* CYRILLIC SMALL LETTER A */, + CharUtils::toLowerCase(0x0430 /* CYRILLIC SMALL LETTER A */)); + EXPECT_EQ(0x3042 /* HIRAGANA LETTER A */, + CharUtils::toLowerCase(0x3042 /* HIRAGANA LETTER A */)); + EXPECT_EQ(0x1F36A /* COOKIE */, CharUtils::toLowerCase(0x1F36A /* COOKIE */)); +} + +TEST(CharUtilsTest, TestToBaseLowerCase) { + EXPECT_EQ('a', CharUtils::toBaseLowerCase('A')); + EXPECT_EQ('z', CharUtils::toBaseLowerCase('Z')); + EXPECT_EQ('a', CharUtils::toBaseLowerCase('a')); + EXPECT_EQ('z', CharUtils::toBaseLowerCase('z')); + EXPECT_EQ('@', CharUtils::toBaseLowerCase('@')); + EXPECT_EQ(' ', CharUtils::toBaseLowerCase(' ')); + EXPECT_EQ('a', CharUtils::toBaseLowerCase(0x00C0 /* LATIN CAPITAL LETTER A WITH GRAVE */)); + EXPECT_EQ('a', CharUtils::toBaseLowerCase(0x00E0 /* LATIN SMALL LETTER A WITH GRAVE */)); + EXPECT_EQ(0x03C2 /* GREEK SMALL LETTER FINAL SIGMA */, + CharUtils::toBaseLowerCase(0x03C2 /* GREEK SMALL LETTER FINAL SIGMA */)); + EXPECT_EQ(0x0430 /* CYRILLIC SMALL LETTER A */, + CharUtils::toBaseLowerCase(0x0410 /* CYRILLIC CAPITAL LETTER A */)); + EXPECT_EQ(0x0430 /* CYRILLIC SMALL LETTER A */, + CharUtils::toBaseLowerCase(0x0430 /* CYRILLIC SMALL LETTER A */)); + EXPECT_EQ(0x3042 /* HIRAGANA LETTER A */, + CharUtils::toBaseLowerCase(0x3042 /* HIRAGANA LETTER A */)); + EXPECT_EQ(0x1F36A /* COOKIE */, CharUtils::toBaseLowerCase(0x1F36A /* COOKIE */)); +} + +TEST(CharUtilsTest, TestToBaseCodePoint) { + EXPECT_EQ('A', CharUtils::toBaseCodePoint('A')); + EXPECT_EQ('Z', CharUtils::toBaseCodePoint('Z')); + EXPECT_EQ('a', CharUtils::toBaseCodePoint('a')); + EXPECT_EQ('z', CharUtils::toBaseCodePoint('z')); + EXPECT_EQ('@', CharUtils::toBaseCodePoint('@')); + EXPECT_EQ(' ', CharUtils::toBaseCodePoint(' ')); + EXPECT_EQ('A', CharUtils::toBaseCodePoint(0x00C0 /* LATIN CAPITAL LETTER A WITH GRAVE */)); + EXPECT_EQ('a', CharUtils::toBaseCodePoint(0x00E0 /* LATIN SMALL LETTER A WITH GRAVE */)); + EXPECT_EQ(0x03C2 /* GREEK SMALL LETTER FINAL SIGMA */, + CharUtils::toBaseLowerCase(0x03C2 /* GREEK SMALL LETTER FINAL SIGMA */)); + EXPECT_EQ(0x0410 /* CYRILLIC CAPITAL LETTER A */, + CharUtils::toBaseCodePoint(0x0410 /* CYRILLIC CAPITAL LETTER A */)); + EXPECT_EQ(0x0430 /* CYRILLIC SMALL LETTER A */, + CharUtils::toBaseCodePoint(0x0430 /* CYRILLIC SMALL LETTER A */)); + EXPECT_EQ(0x3042 /* HIRAGANA LETTER A */, + CharUtils::toBaseCodePoint(0x3042 /* HIRAGANA LETTER A */)); + EXPECT_EQ(0x1F36A /* COOKIE */, CharUtils::toBaseCodePoint(0x1F36A /* COOKIE */)); +} + +TEST(CharUtilsTest, TestIsIntentionalOmissionCodePoint) { + EXPECT_TRUE(CharUtils::isIntentionalOmissionCodePoint('\'')); + EXPECT_TRUE(CharUtils::isIntentionalOmissionCodePoint('-')); + EXPECT_FALSE(CharUtils::isIntentionalOmissionCodePoint('a')); + EXPECT_FALSE(CharUtils::isIntentionalOmissionCodePoint('?')); + EXPECT_FALSE(CharUtils::isIntentionalOmissionCodePoint('/')); +} + +TEST(CharUtilsTest, TestIsInUnicodeSpace) { + EXPECT_FALSE(CharUtils::isInUnicodeSpace(NOT_A_CODE_POINT)); + EXPECT_FALSE(CharUtils::isInUnicodeSpace(CODE_POINT_BEGINNING_OF_SENTENCE)); + EXPECT_TRUE(CharUtils::isInUnicodeSpace('a')); + EXPECT_TRUE(CharUtils::isInUnicodeSpace(0x0410 /* CYRILLIC CAPITAL LETTER A */)); + EXPECT_TRUE(CharUtils::isInUnicodeSpace(0x3042 /* HIRAGANA LETTER A */)); + EXPECT_TRUE(CharUtils::isInUnicodeSpace(0x1F36A /* COOKIE */)); +} + +} // namespace +} // namespace latinime |