From 196e7965b79829c237f5daa04255b007a7ebb345 Mon Sep 17 00:00:00 2001 From: laoguanyao <806103474@qq.com> Date: Mon, 14 Oct 2024 08:52:12 +0800 Subject: [PATCH 1/3] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E5=88=A0=E9=99=A4emoji?= =?UTF-8?q?=E6=96=B9=E6=B3=95=E5=8F=8A=E5=AF=BC=E8=87=B4=E7=9A=84=E9=97=AE?= =?UTF-8?q?=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: laoguanyao <806103474@qq.com> --- .../src/main/cpp/types/libflutter/index.d.ets | 10 + .../main/ets/embedding/engine/FlutterNapi.ets | 20 + .../plugin/editing/ListenableEditingState.ets | 26 +- .../src/main/ets/plugin/editing/TextUtils.ets | 357 ++++++++++++++++++ shell/platform/ohos/library_loader.cpp | 16 + .../ohos/napi/platform_view_ohos_napi.cpp | 117 ++++++ .../ohos/napi/platform_view_ohos_napi.h | 15 + 7 files changed, 547 insertions(+), 14 deletions(-) create mode 100644 shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/editing/TextUtils.ets diff --git a/shell/platform/ohos/flutter_embedding/flutter/src/main/cpp/types/libflutter/index.d.ets b/shell/platform/ohos/flutter_embedding/flutter/src/main/cpp/types/libflutter/index.d.ets index 0cf14a41b0..be366b7cb7 100644 --- a/shell/platform/ohos/flutter_embedding/flutter/src/main/cpp/types/libflutter/index.d.ets +++ b/shell/platform/ohos/flutter_embedding/flutter/src/main/cpp/types/libflutter/index.d.ets @@ -157,3 +157,13 @@ export const nativeSetFontWeightScale: (nativeShellHolderId: number, fontWeightS export const nativeGetShellHolderId: (nativeShellHolderId: number) => void; export const nativeLookupCallbackInformation: (callback: FlutterCallbackInformation, handler: number) => number; + +export const nativeUnicodeIsEmoji: (code: number) => number; + +export const nativeUnicodeIsEmojiModifier: (code: number) => number; + +export const nativeUnicodeIsEmojiModifierBase: (code: number) => number; + +export const nativeUnicodeIsVariationSelector: (code: number) => number; + +export const nativeUnicodeIsRegionalIndicatorSymbol: (code: number) => number; \ No newline at end of file diff --git a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/FlutterNapi.ets b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/FlutterNapi.ets index 787722ab06..9be47241dc 100644 --- a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/FlutterNapi.ets +++ b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/FlutterNapi.ets @@ -522,6 +522,26 @@ export default class FlutterNapi { } } + static unicodeIsEmoji(code: number): boolean { + return Boolean(flutter.nativeUnicodeIsEmoji(code)); + } + + static unicodeIsEmojiModifier(code: number): boolean { + return Boolean(flutter.nativeUnicodeIsEmojiModifier(code)); + } + + static unicodeIsEmojiModifierBase(code: number): boolean { + return Boolean(flutter.nativeUnicodeIsEmojiModifierBase(code)); + } + + static unicodeIsVariationSelector(code: number): boolean { + return Boolean(flutter.nativeUnicodeIsVariationSelector(code)); + } + + static unicodeIsRegionalIndicatorSymbol(code: number): boolean { + return Boolean(flutter.nativeUnicodeIsRegionalIndicatorSymbol(code)); + } + } export interface AccessibilityDelegate { diff --git a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/editing/ListenableEditingState.ets b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/editing/ListenableEditingState.ets index 837253925b..351277019b 100644 --- a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/editing/ListenableEditingState.ets +++ b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/editing/ListenableEditingState.ets @@ -19,6 +19,7 @@ import inputMethod from '@ohos.inputMethod'; import ArrayList from '@ohos.util.ArrayList'; import { TextEditingDelta } from './TextEditingDelta'; import TextInputChannel from '../../embedding/engine/systemchannels/TextInputChannel'; +import { FlutterTextUtils } from './TextUtils'; const TAG = "ListenableEditingState"; @@ -260,15 +261,13 @@ export class ListenableEditingState { if (start == 0 && end == 0) { return; } - let tbStart = start == end ? start - 1 : start; - let tbEnd = start == end ? -1 : 0; - let crCode: number = this.mStringCache.charCodeAt(tbStart) - if ( 0xdc00 <= crCode && crCode <= 0xdffff ) { - tbStart = tbStart - 1 + let unicodeStart = start; + if (start == end) { + unicodeStart = FlutterTextUtils.getOffsetBefore(this.mStringCache, start); } - this.replace(tbStart, end, "", 0, tbEnd); - this.mSelectionStartCache = tbStart; - let tempStr: string = this.mStringCache.slice(0, tbStart) + this.mStringCache.slice(end); + this.replace(unicodeStart, end, "", 0, 0); + this.mSelectionStartCache = unicodeStart; + let tempStr: string = this.mStringCache.slice(0, unicodeStart) + this.mStringCache.slice(end); this.mStringCache = tempStr; this.mSelectionEndCache = this.mSelectionStartCache; } else if (leftOrRight == true) { @@ -276,14 +275,13 @@ export class ListenableEditingState { if (start == this.mStringCache.length) { return; } - let tbStart = start == end ? 1 : 0; - let crCode: number = this.mStringCache.charCodeAt(tbStart) - if ( 0xdc00 <= crCode && crCode <= 0xdffff ) { - tbStart = tbStart - 1 + let unicodeEnd = end; + if (start == end) { + unicodeEnd = FlutterTextUtils.getOffsetAfter(this.mStringCache, start); } - this.replace(start, end, "", tbStart, 0); + this.replace(start, unicodeEnd, "", 0, 0); this.mSelectionEndCache = start; - let tempStr: string = this.mStringCache.slice(0, start) + (end + 1 >= this.mStringCache.length ? "" : this.mStringCache.slice(end + 1)); + let tempStr: string = this.mStringCache.slice(0, start) + (unicodeEnd >= this.mStringCache.length ? "" : this.mStringCache.slice(unicodeEnd)); this.mStringCache = tempStr; this.mSelectionStartCache = this.mSelectionEndCache; } diff --git a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/editing/TextUtils.ets b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/editing/TextUtils.ets new file mode 100644 index 0000000000..f1948d01be --- /dev/null +++ b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/editing/TextUtils.ets @@ -0,0 +1,357 @@ +import FlutterNapi from '../../embedding/engine/FlutterNapi'; +import Log from '../../util/Log'; + +const LINE_FEED: number = 0x0A; +const CARRIAGE_RETURN: number = 0x0D; +const COMBINING_ENCLOSING_KEYCAP: number = 0x20E3; +const CANCEL_TAG: number = 0xE007F; +const ZERO_WIDTH_JOINER: number = 0x200D; + +const TAG = "TextUtils"; + +export class FlutterTextUtils { + + static isEmoji(code: number): boolean { + return FlutterNapi.unicodeIsEmoji(code); + } + + static isEmojiModifier(code: number): boolean { + return FlutterNapi.unicodeIsEmojiModifier(code); + } + + static isEmojiModifierBase(code: number): boolean { + return FlutterNapi.unicodeIsEmojiModifierBase(code); + } + + static isVariationSelector(code: number): boolean { + return FlutterNapi.unicodeIsVariationSelector(code); + } + + static isRegionalIndicatorSymbol(code: number): boolean { + return FlutterNapi.unicodeIsRegionalIndicatorSymbol(code); + } + + static isTagSpecChar(code: number): boolean { + return 0xE0020 <= code && code <= 0xE007E; + } + + static isKeycapBase(code: number): boolean { + return ('0'.charCodeAt(0) <= code && code <= '9'.charCodeAt(0)) || code == '#'.charCodeAt(0) || code == '*'.charCodeAt(0); + } + + static codePointBefore(text: string, offset: number): number { + if (offset <= 0 || offset > text.length) { + throw new RangeError('Offset out of range'); + } + + // Get the character before the offset + const char = text[offset - 1]; + + // Check if it is a low surrogate (part of a surrogate pair) + if (offset > 1 && char >= '\uDC00' && char <= '\uDFFF') { + const prevChar = text[offset - 2]; + // Check if the previous character is a high surrogate + if (prevChar >= '\uD800' && prevChar <= '\uDBFF') { + // If it is, combine the surrogate pair into a full Unicode code point + return (prevChar.charCodeAt(0) - 0xD800) * 0x400 + (char.charCodeAt(0) - 0xDC00) + 0x10000; + } + } + + // Return the code point of the single character (if it's not a surrogate pair) + return char.charCodeAt(0); + } + + static codePointAt(text: string, offset: number): number { + if (offset >= text.length) { + throw new RangeError('Offset out of range'); + } + let char = text[offset]; + + // Check if it is a high surrogate (part of a surrogate pair) + if (char >= '\uD800' && char <= '\uDBFF' && offset + 1 < text.length) { + const nextChar = text[offset + 1]; + // Check if the previous character is a low surrogate + if (nextChar >= '\uDC00' && nextChar <= '\uDFFF') { + // If it is, combine the surrogate pair into a full Unicode code point + return (char.charCodeAt(0) - 0xD800) * 0x400 + (nextChar.charCodeAt(0) - 0xDC00) + 0x10000; + } + } + return char.charCodeAt(0); + } + + static charCount(codePoint: number): number { + // If the code point is in the BMP range (0x0000 - 0xFFFF), it needs 1 UTF-16 code unit + if (codePoint <= 0xFFFF) { + return 1; + } + // If the code point is in the supplementary range (0x10000 - 0x10FFFF), it needs 2 UTF-16 code units + return 2; + } + + static getOffsetBefore(text: string, offset: number): number { + if (offset <= 1) { + return 0; + } + + let codePoint: number = FlutterTextUtils.codePointBefore(text, offset); + let deleteCharCount: number = FlutterTextUtils.charCount(codePoint); + let lastOffset: number = offset - deleteCharCount; + + if (lastOffset == 0) { + return 0; + } + + // Line Feed + if (codePoint == LINE_FEED) { + codePoint = FlutterTextUtils.codePointBefore(text, lastOffset); + if (codePoint == CARRIAGE_RETURN) { + ++deleteCharCount; + } + return offset - deleteCharCount; + } + + // Flags + if (FlutterTextUtils.isRegionalIndicatorSymbol(codePoint)) { + codePoint = FlutterTextUtils.codePointBefore(text, lastOffset); + lastOffset -= FlutterTextUtils.charCount(codePoint); + let regionalIndicatorSymbolCount: number = 1; + while (lastOffset > 0 && FlutterTextUtils.isRegionalIndicatorSymbol(codePoint)) { + codePoint = FlutterTextUtils.codePointBefore(text, lastOffset); + lastOffset -= FlutterTextUtils.charCount(codePoint); + regionalIndicatorSymbolCount++; + } + if (FlutterTextUtils.isRegionalIndicatorSymbol(codePoint)) { + regionalIndicatorSymbolCount++; + } + if (regionalIndicatorSymbolCount % 2 == 0) { + deleteCharCount += 2; + } + return offset - deleteCharCount; + } + + // Keycaps + if (codePoint == COMBINING_ENCLOSING_KEYCAP) { + codePoint = FlutterTextUtils.codePointBefore(text, lastOffset); + lastOffset -= FlutterTextUtils.charCount(codePoint); + if (lastOffset > 0 && FlutterTextUtils.isVariationSelector(codePoint)) { + let tmpCodePoint: number = FlutterTextUtils.codePointBefore(text, lastOffset); + if (FlutterTextUtils.isKeycapBase(tmpCodePoint)) { + deleteCharCount += FlutterTextUtils.charCount(codePoint) + FlutterTextUtils.charCount(tmpCodePoint); + } + } else if (FlutterTextUtils.isKeycapBase(codePoint)) { + deleteCharCount += FlutterTextUtils.charCount(codePoint); + } + return offset - deleteCharCount; + } + + /** + * Following if statements for Emoji tag sequence and Variation selector are skipping these + * modifiers for going through the last statement that is for handling emojis. They return the + * offset if they don't find proper base characters + */ + // Emoji Tag Sequence + if (codePoint == CANCEL_TAG) { // tag_end + codePoint = FlutterTextUtils.codePointBefore(text, lastOffset); + lastOffset -= FlutterTextUtils.charCount(codePoint); + while (lastOffset > 0 && FlutterTextUtils.isTagSpecChar(codePoint)) { // tag_spec + deleteCharCount += FlutterTextUtils.charCount(codePoint); + codePoint = FlutterTextUtils.codePointBefore(text, lastOffset); + lastOffset -= FlutterTextUtils.charCount(codePoint); + } + if (!FlutterTextUtils.isEmoji(codePoint)) { // tag_base not found. Just delete the end. + return offset - 2; + } + deleteCharCount += FlutterTextUtils.charCount(codePoint); + } + + if (FlutterTextUtils.isVariationSelector(codePoint)) { + codePoint = FlutterTextUtils.codePointBefore(text, lastOffset); + if (!FlutterTextUtils.isEmoji(codePoint)) { + return offset - deleteCharCount; + } + deleteCharCount += FlutterTextUtils.charCount(codePoint); + + lastOffset -= FlutterTextUtils.charCount(codePoint); + } + + if (FlutterTextUtils.isEmoji(codePoint)) { + let isZwj: boolean = false; + let lastSeenVariantSelectorCharCount: number = 0; + do { + if (isZwj) { + deleteCharCount += FlutterTextUtils.charCount(codePoint) + lastSeenVariantSelectorCharCount + 1; + isZwj = false; + } + lastSeenVariantSelectorCharCount = 0; + if (FlutterTextUtils.isEmojiModifier(codePoint)) { + codePoint = FlutterTextUtils.codePointBefore(text, lastOffset); + lastOffset -= FlutterTextUtils.charCount(codePoint); + if (lastOffset > 0 && FlutterTextUtils.isVariationSelector(codePoint)) { + codePoint = FlutterTextUtils.codePointBefore(text, lastOffset); + if (!FlutterTextUtils.isEmoji(codePoint)) { + return offset - deleteCharCount; + } + lastSeenVariantSelectorCharCount = FlutterTextUtils.charCount(codePoint); + lastOffset -= FlutterTextUtils.charCount(codePoint); + } + if (FlutterTextUtils.isEmojiModifierBase(codePoint)) { + deleteCharCount += lastSeenVariantSelectorCharCount + FlutterTextUtils.charCount(codePoint); + } + break; + } + + if (lastOffset > 0) { + codePoint = FlutterTextUtils.codePointBefore(text, lastOffset); + lastOffset -= FlutterTextUtils.charCount(codePoint); + if (codePoint == ZERO_WIDTH_JOINER) { + isZwj = true; + codePoint = FlutterTextUtils.codePointBefore(text, lastOffset); + lastOffset -= FlutterTextUtils.charCount(codePoint); + if (lastOffset > 0 && FlutterTextUtils.isVariationSelector(codePoint)) { + codePoint = FlutterTextUtils.codePointBefore(text, lastOffset); + lastSeenVariantSelectorCharCount = FlutterTextUtils.charCount(codePoint); + lastOffset -= FlutterTextUtils.charCount(codePoint); + } + } + } + + if (lastOffset == 0) { + break; + } + } while (isZwj && FlutterTextUtils.isEmoji(codePoint)); + + if (isZwj && lastOffset == 0) { + deleteCharCount += FlutterTextUtils.charCount(codePoint) + lastSeenVariantSelectorCharCount + 1; + isZwj = false; + } + } + + return offset - deleteCharCount; + } + + static getOffsetAfter(text: string, offset: number): number { + const len = text.length; + if (offset >= len - 1) { + return len; + } + + let codePoint: number = FlutterTextUtils.codePointAt(text, offset); + let nextCharCount: number = FlutterTextUtils.charCount(codePoint); + let nextOffset: number = offset + nextCharCount; + + if (nextOffset == 0) { + return 0; + } + // Line Feed + if (codePoint == LINE_FEED) { + codePoint = FlutterTextUtils.codePointAt(text, nextOffset); + if (codePoint == CARRIAGE_RETURN) { + ++nextCharCount; + } + return offset + nextCharCount; + } + + // Flags + if (FlutterTextUtils.isRegionalIndicatorSymbol(codePoint)) { + if (nextOffset >= len - 1 + || !FlutterTextUtils.isRegionalIndicatorSymbol(FlutterTextUtils.codePointAt(text, nextOffset))) { + return offset + nextCharCount; + } + // In this case there are at least two regional indicator symbols ahead of + // offset. If those two regional indicator symbols are a pair that + // represent a region together, the next offset should be after both of + // them. + let regionalIndicatorSymbolCount: number = 0; + let regionOffset: number = offset; + while (regionOffset > 0 + && FlutterTextUtils.isRegionalIndicatorSymbol(FlutterTextUtils.codePointBefore(text, regionOffset))) { + regionOffset -= FlutterTextUtils.charCount(FlutterTextUtils.codePointBefore(text, regionOffset)); + regionalIndicatorSymbolCount++; + } + if (regionalIndicatorSymbolCount % 2 == 0) { + nextCharCount += 2; + } + return offset + nextCharCount; + } + + // Keycaps + if (FlutterTextUtils.isKeycapBase(codePoint)) { + nextCharCount += FlutterTextUtils.charCount(codePoint); + } + if (codePoint == COMBINING_ENCLOSING_KEYCAP) { + codePoint = FlutterTextUtils.codePointBefore(text, nextOffset); + nextOffset += FlutterTextUtils.charCount(codePoint); + if (nextOffset < len && FlutterTextUtils.isVariationSelector(codePoint)) { + let tmpCodePoint: number = FlutterTextUtils.codePointAt(text, nextOffset); + if (FlutterTextUtils.isKeycapBase(tmpCodePoint)) { + nextCharCount += FlutterTextUtils.charCount(codePoint) + FlutterTextUtils.charCount(tmpCodePoint); + } + } else if (FlutterTextUtils.isKeycapBase(codePoint)) { + nextCharCount += FlutterTextUtils.charCount(codePoint); + } + return offset + nextCharCount; + } + + if (FlutterTextUtils.isEmoji(codePoint)) { + let isZwj: boolean = false; + let lastSeenVariantSelectorCharCount: number = 0; + do { + if (isZwj) { + nextCharCount += FlutterTextUtils.charCount(codePoint) + lastSeenVariantSelectorCharCount + 1; + isZwj = false; + } + lastSeenVariantSelectorCharCount = 0; + if (FlutterTextUtils.isEmojiModifier(codePoint)) { + break; + } + + if (nextOffset < len) { + codePoint = FlutterTextUtils.codePointAt(text, nextOffset); + nextOffset += FlutterTextUtils.charCount(codePoint); + if (codePoint == COMBINING_ENCLOSING_KEYCAP) { + codePoint = FlutterTextUtils.codePointBefore(text, nextOffset); + nextOffset += FlutterTextUtils.charCount(codePoint); + if (nextOffset < len && FlutterTextUtils.isVariationSelector(codePoint)) { + let tmpCodePoint: number = FlutterTextUtils.codePointAt(text, nextOffset); + if (FlutterTextUtils.isKeycapBase(tmpCodePoint)) { + nextCharCount += FlutterTextUtils.charCount(codePoint) + FlutterTextUtils.charCount(tmpCodePoint); + } + } else if (FlutterTextUtils.isKeycapBase(codePoint)) { + nextCharCount += FlutterTextUtils.charCount(codePoint); + } + return offset + nextCharCount; + } + if (FlutterTextUtils.isEmojiModifier(codePoint)) { + nextCharCount += lastSeenVariantSelectorCharCount + FlutterTextUtils.charCount(codePoint); + break; + } + if (FlutterTextUtils.isVariationSelector(codePoint)) { + nextCharCount += lastSeenVariantSelectorCharCount + FlutterTextUtils.charCount(codePoint); + break; + } + if (codePoint == ZERO_WIDTH_JOINER) { + isZwj = true; + codePoint = FlutterTextUtils.codePointAt(text, nextOffset); + nextOffset += FlutterTextUtils.charCount(codePoint); + if (nextOffset < len && FlutterTextUtils.isVariationSelector(codePoint)) { + codePoint = FlutterTextUtils.codePointAt(text, nextOffset); + lastSeenVariantSelectorCharCount = FlutterTextUtils.charCount(codePoint); + nextOffset += FlutterTextUtils.charCount(codePoint); + } + } + } + + if (nextOffset >= len) { + break; + } + } while (isZwj && FlutterTextUtils.isEmoji(codePoint)); + + if (isZwj && nextOffset >= len) { + nextCharCount += FlutterTextUtils.charCount(codePoint) + lastSeenVariantSelectorCharCount + 1; + isZwj = false; + } + } + + return offset + nextCharCount; + } +} \ No newline at end of file diff --git a/shell/platform/ohos/library_loader.cpp b/shell/platform/ohos/library_loader.cpp index f596341474..b04d4c0016 100644 --- a/shell/platform/ohos/library_loader.cpp +++ b/shell/platform/ohos/library_loader.cpp @@ -153,6 +153,22 @@ static napi_value Init(napi_env env, napi_value exports) { DECLARE_NAPI_FUNCTION( "nativeLookupCallbackInformation", flutter::PlatformViewOHOSNapi::nativeLookupCallbackInformation), + + DECLARE_NAPI_FUNCTION( + "nativeUnicodeIsEmoji", + flutter::PlatformViewOHOSNapi::nativeUnicodeIsEmoji), + DECLARE_NAPI_FUNCTION( + "nativeUnicodeIsEmojiModifier", + flutter::PlatformViewOHOSNapi::nativeUnicodeIsEmojiModifier), + DECLARE_NAPI_FUNCTION( + "nativeUnicodeIsEmojiModifierBase", + flutter::PlatformViewOHOSNapi::nativeUnicodeIsEmojiModifierBase), + DECLARE_NAPI_FUNCTION( + "nativeUnicodeIsVariationSelector", + flutter::PlatformViewOHOSNapi::nativeUnicodeIsVariationSelector), + DECLARE_NAPI_FUNCTION( + "nativeUnicodeIsRegionalIndicatorSymbol", + flutter::PlatformViewOHOSNapi::nativeUnicodeIsRegionalIndicatorSymbol), }; FML_DLOG(INFO) << "Init NAPI size=" << sizeof(desc) / sizeof(desc[0]); diff --git a/shell/platform/ohos/napi/platform_view_ohos_napi.cpp b/shell/platform/ohos/napi/platform_view_ohos_napi.cpp index 2594687c15..a8242691dd 100644 --- a/shell/platform/ohos/napi/platform_view_ohos_napi.cpp +++ b/shell/platform/ohos/napi/platform_view_ohos_napi.cpp @@ -1899,4 +1899,121 @@ napi_value PlatformViewOHOSNapi::nativeLookupCallbackInformation(napi_env env, n napi_create_int32(env, 0, &result); return result; } + +napi_value PlatformViewOHOSNapi::nativeUnicodeIsEmoji(napi_env env, + napi_callback_info info) { + size_t argc = 1; + napi_value args[1] = {nullptr}; + napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); + + bool is_emoji = false; + int64_t codePoint = 0; + bool ret = napi_get_value_int64(env, args[0], &codePoint); + if (ret != napi_ok) { + FML_DLOG(ERROR) << "nativeXComponentAttachFlutterEngine shell_holder " + "napi_get_value_int64 error"; + return nullptr; + } + + is_emoji = u_hasBinaryProperty(codePoint, UProperty::UCHAR_EMOJI); + + napi_value result; + napi_create_int32(env, (int)is_emoji, &result); + return result; +} + +napi_value PlatformViewOHOSNapi::nativeUnicodeIsEmojiModifier( + napi_env env, + napi_callback_info info) { + size_t argc = 1; + napi_value args[1] = {nullptr}; + napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); + + bool is_emoji = false; + int64_t codePoint = 0; + bool ret = napi_get_value_int64(env, args[0], &codePoint); + if (ret != napi_ok) { + FML_DLOG(ERROR) << "nativeXComponentAttachFlutterEngine shell_holder " + "napi_get_value_int64 error"; + return nullptr; + } + + is_emoji = u_hasBinaryProperty(codePoint, UProperty::UCHAR_EMOJI_MODIFIER); + + napi_value result; + napi_create_int32(env, (int)is_emoji, &result); + return result; +} + +napi_value PlatformViewOHOSNapi::nativeUnicodeIsEmojiModifierBase( + napi_env env, + napi_callback_info info) { + size_t argc = 1; + napi_value args[1] = {nullptr}; + napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); + + bool is_emoji = false; + int64_t codePoint = 0; + bool ret = napi_get_value_int64(env, args[0], &codePoint); + if (ret != napi_ok) { + FML_DLOG(ERROR) << "nativeXComponentAttachFlutterEngine shell_holder " + "napi_get_value_int64 error"; + return nullptr; + } + + is_emoji = + u_hasBinaryProperty(codePoint, UProperty::UCHAR_EMOJI_MODIFIER_BASE); + + napi_value result; + napi_create_int32(env, (int)is_emoji, &result); + return result; +} + +napi_value PlatformViewOHOSNapi::nativeUnicodeIsVariationSelector( + napi_env env, + napi_callback_info info) { + size_t argc = 1; + napi_value args[1] = {nullptr}; + napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); + + bool is_emoji = false; + int64_t codePoint = 0; + bool ret = napi_get_value_int64(env, args[0], &codePoint); + if (ret != napi_ok) { + FML_DLOG(ERROR) << "nativeXComponentAttachFlutterEngine shell_holder " + "napi_get_value_int64 error"; + return nullptr; + } + + is_emoji = + u_hasBinaryProperty(codePoint, UProperty::UCHAR_VARIATION_SELECTOR); + + napi_value result; + napi_create_int32(env, (int)is_emoji, &result); + return result; +} + +napi_value PlatformViewOHOSNapi::nativeUnicodeIsRegionalIndicatorSymbol( + napi_env env, + napi_callback_info info) { + size_t argc = 1; + napi_value args[1] = {nullptr}; + napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); + + bool is_emoji = false; + int64_t codePoint = 0; + bool ret = napi_get_value_int64(env, args[0], &codePoint); + if (ret != napi_ok) { + FML_DLOG(ERROR) << "nativeXComponentAttachFlutterEngine shell_holder " + "napi_get_value_int64 error"; + return nullptr; + } + + is_emoji = + u_hasBinaryProperty(codePoint, UProperty::UCHAR_REGIONAL_INDICATOR); + + napi_value result; + napi_create_int32(env, (int)is_emoji, &result); + return result; +} } // namespace flutter \ No newline at end of file diff --git a/shell/platform/ohos/napi/platform_view_ohos_napi.h b/shell/platform/ohos/napi/platform_view_ohos_napi.h index 4cbe6cd572..1a42f5b3b0 100644 --- a/shell/platform/ohos/napi/platform_view_ohos_napi.h +++ b/shell/platform/ohos/napi/platform_view_ohos_napi.h @@ -224,6 +224,21 @@ class PlatformViewOHOSNapi { napi_env env, napi_callback_info info); + static napi_value nativeUnicodeIsEmoji(napi_env env, napi_callback_info info); + + static napi_value nativeUnicodeIsEmojiModifier(napi_env env, + napi_callback_info info); + + static napi_value nativeUnicodeIsEmojiModifierBase(napi_env env, + napi_callback_info info); + + static napi_value nativeUnicodeIsVariationSelector(napi_env env, + napi_callback_info info); + + static napi_value nativeUnicodeIsRegionalIndicatorSymbol( + napi_env env, + napi_callback_info info); + private: static napi_env env_; napi_ref ref_napi_obj_; -- Gitee From c5b3773b47be12dad2a481909a9188117205077b Mon Sep 17 00:00:00 2001 From: laoguanyao <806103474@qq.com> Date: Mon, 14 Oct 2024 09:39:08 +0800 Subject: [PATCH 2/3] =?UTF-8?q?=E4=BB=A3=E7=A0=81=E8=A7=84=E8=8C=83?= =?UTF-8?q?=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: laoguanyao <806103474@qq.com> --- shell/platform/ohos/library_loader.cpp | 30 ++++++++--------- .../ohos/napi/platform_view_ohos_napi.cpp | 33 ++++++++----------- .../ohos/napi/platform_view_ohos_napi.h | 19 +++++++---- 3 files changed, 40 insertions(+), 42 deletions(-) diff --git a/shell/platform/ohos/library_loader.cpp b/shell/platform/ohos/library_loader.cpp index b04d4c0016..ab9f2df807 100644 --- a/shell/platform/ohos/library_loader.cpp +++ b/shell/platform/ohos/library_loader.cpp @@ -154,21 +154,21 @@ static napi_value Init(napi_env env, napi_value exports) { "nativeLookupCallbackInformation", flutter::PlatformViewOHOSNapi::nativeLookupCallbackInformation), - DECLARE_NAPI_FUNCTION( - "nativeUnicodeIsEmoji", - flutter::PlatformViewOHOSNapi::nativeUnicodeIsEmoji), - DECLARE_NAPI_FUNCTION( - "nativeUnicodeIsEmojiModifier", - flutter::PlatformViewOHOSNapi::nativeUnicodeIsEmojiModifier), - DECLARE_NAPI_FUNCTION( - "nativeUnicodeIsEmojiModifierBase", - flutter::PlatformViewOHOSNapi::nativeUnicodeIsEmojiModifierBase), - DECLARE_NAPI_FUNCTION( - "nativeUnicodeIsVariationSelector", - flutter::PlatformViewOHOSNapi::nativeUnicodeIsVariationSelector), - DECLARE_NAPI_FUNCTION( - "nativeUnicodeIsRegionalIndicatorSymbol", - flutter::PlatformViewOHOSNapi::nativeUnicodeIsRegionalIndicatorSymbol), + DECLARE_NAPI_FUNCTION( + "nativeUnicodeIsEmoji", + flutter::PlatformViewOHOSNapi::nativeUnicodeIsEmoji), + DECLARE_NAPI_FUNCTION( + "nativeUnicodeIsEmojiModifier", + flutter::PlatformViewOHOSNapi::nativeUnicodeIsEmojiModifier), + DECLARE_NAPI_FUNCTION( + "nativeUnicodeIsEmojiModifierBase", + flutter::PlatformViewOHOSNapi::nativeUnicodeIsEmojiModifierBase), + DECLARE_NAPI_FUNCTION( + "nativeUnicodeIsVariationSelector", + flutter::PlatformViewOHOSNapi::nativeUnicodeIsVariationSelector), + DECLARE_NAPI_FUNCTION( + "nativeUnicodeIsRegionalIndicatorSymbol", + flutter::PlatformViewOHOSNapi::nativeUnicodeIsRegionalIndicatorSymbol), }; FML_DLOG(INFO) << "Init NAPI size=" << sizeof(desc) / sizeof(desc[0]); diff --git a/shell/platform/ohos/napi/platform_view_ohos_napi.cpp b/shell/platform/ohos/napi/platform_view_ohos_napi.cpp index a8242691dd..f6f23e803a 100644 --- a/shell/platform/ohos/napi/platform_view_ohos_napi.cpp +++ b/shell/platform/ohos/napi/platform_view_ohos_napi.cpp @@ -1900,8 +1900,8 @@ napi_value PlatformViewOHOSNapi::nativeLookupCallbackInformation(napi_env env, n return result; } -napi_value PlatformViewOHOSNapi::nativeUnicodeIsEmoji(napi_env env, - napi_callback_info info) { +napi_value PlatformViewOHOSNapi::nativeUnicodeIsEmoji(napi_env env, napi_callback_info info) +{ size_t argc = 1; napi_value args[1] = {nullptr}; napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); @@ -1922,9 +1922,8 @@ napi_value PlatformViewOHOSNapi::nativeUnicodeIsEmoji(napi_env env, return result; } -napi_value PlatformViewOHOSNapi::nativeUnicodeIsEmojiModifier( - napi_env env, - napi_callback_info info) { +napi_value PlatformViewOHOSNapi::nativeUnicodeIsEmojiModifier(napi_env env, napi_callback_info info) +{ size_t argc = 1; napi_value args[1] = {nullptr}; napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); @@ -1945,9 +1944,8 @@ napi_value PlatformViewOHOSNapi::nativeUnicodeIsEmojiModifier( return result; } -napi_value PlatformViewOHOSNapi::nativeUnicodeIsEmojiModifierBase( - napi_env env, - napi_callback_info info) { +napi_value PlatformViewOHOSNapi::nativeUnicodeIsEmojiModifierBase(napi_env env, napi_callback_info info) +{ size_t argc = 1; napi_value args[1] = {nullptr}; napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); @@ -1961,17 +1959,15 @@ napi_value PlatformViewOHOSNapi::nativeUnicodeIsEmojiModifierBase( return nullptr; } - is_emoji = - u_hasBinaryProperty(codePoint, UProperty::UCHAR_EMOJI_MODIFIER_BASE); + is_emoji = u_hasBinaryProperty(codePoint, UProperty::UCHAR_EMOJI_MODIFIER_BASE); napi_value result; napi_create_int32(env, (int)is_emoji, &result); return result; } -napi_value PlatformViewOHOSNapi::nativeUnicodeIsVariationSelector( - napi_env env, - napi_callback_info info) { +napi_value PlatformViewOHOSNapi::nativeUnicodeIsVariationSelector(napi_env env, napi_callback_info info) +{ size_t argc = 1; napi_value args[1] = {nullptr}; napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); @@ -1985,17 +1981,15 @@ napi_value PlatformViewOHOSNapi::nativeUnicodeIsVariationSelector( return nullptr; } - is_emoji = - u_hasBinaryProperty(codePoint, UProperty::UCHAR_VARIATION_SELECTOR); + is_emoji = u_hasBinaryProperty(codePoint, UProperty::UCHAR_VARIATION_SELECTOR); napi_value result; napi_create_int32(env, (int)is_emoji, &result); return result; } -napi_value PlatformViewOHOSNapi::nativeUnicodeIsRegionalIndicatorSymbol( - napi_env env, - napi_callback_info info) { +napi_value PlatformViewOHOSNapi::nativeUnicodeIsRegionalIndicatorSymbol(napi_env env, napi_callback_info info) +{ size_t argc = 1; napi_value args[1] = {nullptr}; napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); @@ -2009,8 +2003,7 @@ napi_value PlatformViewOHOSNapi::nativeUnicodeIsRegionalIndicatorSymbol( return nullptr; } - is_emoji = - u_hasBinaryProperty(codePoint, UProperty::UCHAR_REGIONAL_INDICATOR); + is_emoji = u_hasBinaryProperty(codePoint, UProperty::UCHAR_REGIONAL_INDICATOR); napi_value result; napi_create_int32(env, (int)is_emoji, &result); diff --git a/shell/platform/ohos/napi/platform_view_ohos_napi.h b/shell/platform/ohos/napi/platform_view_ohos_napi.h index 1a42f5b3b0..65f11e8776 100644 --- a/shell/platform/ohos/napi/platform_view_ohos_napi.h +++ b/shell/platform/ohos/napi/platform_view_ohos_napi.h @@ -224,16 +224,21 @@ class PlatformViewOHOSNapi { napi_env env, napi_callback_info info); - static napi_value nativeUnicodeIsEmoji(napi_env env, napi_callback_info info); + static napi_value nativeUnicodeIsEmoji( + napi_env env, + napi_callback_info info); - static napi_value nativeUnicodeIsEmojiModifier(napi_env env, - napi_callback_info info); + static napi_value nativeUnicodeIsEmojiModifier( + napi_env env, + napi_callback_info info); - static napi_value nativeUnicodeIsEmojiModifierBase(napi_env env, - napi_callback_info info); + static napi_value nativeUnicodeIsEmojiModifierBase( + napi_env env, + napi_callback_info info); - static napi_value nativeUnicodeIsVariationSelector(napi_env env, - napi_callback_info info); + static napi_value nativeUnicodeIsVariationSelector( + napi_env env, + napi_callback_info info); static napi_value nativeUnicodeIsRegionalIndicatorSymbol( napi_env env, -- Gitee From fe95af4363d1968854e4bb33933f393b54872776 Mon Sep 17 00:00:00 2001 From: laoguanyao <806103474@qq.com> Date: Mon, 14 Oct 2024 09:49:10 +0800 Subject: [PATCH 3/3] =?UTF-8?q?OAT=20=E8=AE=B8=E5=8F=AF=E8=AF=81=E5=A4=B4?= =?UTF-8?q?=E6=B7=BB=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: laoguanyao <806103474@qq.com> --- .../src/main/ets/plugin/editing/TextUtils.ets | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/editing/TextUtils.ets b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/editing/TextUtils.ets index f1948d01be..61aa4b3dee 100644 --- a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/editing/TextUtils.ets +++ b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/editing/TextUtils.ets @@ -1,3 +1,17 @@ +/* +* Copyright (c) 2023 Hunan OpenValley Digital Industry Development Co., Ltd. +* 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. +*/ import FlutterNapi from '../../embedding/engine/FlutterNapi'; import Log from '../../util/Log'; -- Gitee