Prevent excessive calls to deleteBackward method which may cause crashes on Android (#2248)

* Pass the number of characters to delete from a TextField

* Include TextFieldEx.h reference in axmoil-ui.h

* Remove logging calls used for testing

* Update parameter name
This commit is contained in:
RH 2024-11-29 02:12:21 +11:00 committed by GitHub
parent 1e8fbb991d
commit c37bcf8977
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
16 changed files with 65 additions and 42 deletions

View File

@ -24,6 +24,8 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
#include <algorithm>
#include "2d/TextFieldTTF.h"
#include "base/Director.h"
@ -310,7 +312,7 @@ void TextFieldTTF::insertText(const char* text, size_t len)
detachWithIME();
}
void TextFieldTTF::deleteBackward()
void TextFieldTTF::deleteBackward(size_t numChars)
{
size_t len = _inputText.length();
if (!len)
@ -319,23 +321,33 @@ void TextFieldTTF::deleteBackward()
return;
}
// get the delete byte number
size_t deleteLen = 1; // default, erase 1 byte
// Length of characters to delete is based on input editor, but the actual
// length of the displayed text may be less
numChars = std::min(numChars, len);
while (0x80 == (0xC0 & _inputText.at(len - deleteLen)))
size_t totalDeleteLen = 0;
for (auto i = 0; i < numChars; ++i)
{
++deleteLen;
// get the delete byte number
size_t deleteLen = 1; // default, erase 1 byte
// Calculate the actual number of bytes to delete for a specific character
while (0x80 == (0xC0 & _inputText.at(len - totalDeleteLen - deleteLen)))
{
++deleteLen;
}
totalDeleteLen += deleteLen;
}
if (_delegate &&
_delegate->onTextFieldDeleteBackward(this, _inputText.c_str() + len - deleteLen, static_cast<int>(deleteLen)))
_delegate->onTextFieldDeleteBackward(this, _inputText.c_str() + len - totalDeleteLen, static_cast<int>(totalDeleteLen)))
{
// delegate doesn't want to delete backwards
return;
}
// if all text deleted, show placeholder string
if (len <= deleteLen)
if (len <= totalDeleteLen)
{
_inputText = "";
_charCount = 0;
@ -362,7 +374,7 @@ void TextFieldTTF::deleteBackward()
}
else
{
std::string text(_inputText.c_str(), len - deleteLen);
std::string text(_inputText.c_str(), len - totalDeleteLen);
setString(text);
}
}

View File

@ -261,7 +261,7 @@ protected:
virtual void didAttachWithIME() override;
virtual void didDetachWithIME() override;
virtual void insertText(const char* text, size_t len) override;
virtual void deleteBackward() override;
virtual void deleteBackward(size_t numChars) override;
virtual std::string_view getContentText() override;
virtual void controlKey(EventKeyboard::KeyCode keyCode) override;

View File

@ -124,7 +124,7 @@ protected:
* @js NA
* @lua NA
*/
virtual void deleteBackward() {}
virtual void deleteBackward(size_t numChars) {}
/**
@brief Called by IMEDispatcher after the user press control key.

View File

@ -222,7 +222,7 @@ void IMEDispatcher::dispatchInsertText(const char* text, size_t len)
} while (0);
}
void IMEDispatcher::dispatchDeleteBackward()
void IMEDispatcher::dispatchDeleteBackward(int numChars)
{
do
{
@ -231,7 +231,7 @@ void IMEDispatcher::dispatchDeleteBackward()
// there is no delegate attached to IME
AX_BREAK_IF(!_impl->_delegateWithIme);
_impl->_delegateWithIme->deleteBackward();
_impl->_delegateWithIme->deleteBackward(numChars);
} while (0);
}

View File

@ -65,7 +65,7 @@ public:
* @brief Dispatches the delete-backward operation.
* @lua NA
*/
void dispatchDeleteBackward();
void dispatchDeleteBackward(int numChars);
/**
* @brief Dispatches the press control key operation.

View File

@ -1220,7 +1220,7 @@ void GLViewImpl::onGLFWKeyCallback(GLFWwindow* /*window*/, int key, int /*scanco
switch (g_keyCodeMap[key])
{
case EventKeyboard::KeyCode::KEY_BACKSPACE:
IMEDispatcher::sharedDispatcher()->dispatchDeleteBackward();
IMEDispatcher::sharedDispatcher()->dispatchDeleteBackward(1);
break;
case EventKeyboard::KeyCode::KEY_HOME:
case EventKeyboard::KeyCode::KEY_KP_HOME:

View File

@ -458,11 +458,11 @@ public class AxmolGLSurfaceView extends GLSurfaceView {
});
}
public void deleteBackward() {
public void deleteBackward(int numChars) {
this.queueEvent(new Runnable() {
@Override
public void run() {
AxmolGLSurfaceView.this.mRenderer.handleDeleteBackward();
AxmolGLSurfaceView.this.mRenderer.handleDeleteBackward(numChars);
}
});
}

View File

@ -176,15 +176,15 @@ public class AxmolRenderer implements GLSurfaceView.Renderer {
}
private static native void nativeInsertText(final String text);
private static native void nativeDeleteBackward();
private static native void nativeDeleteBackward(final int numChars);
private static native String nativeGetContentText();
public void handleInsertText(final String text) {
AxmolRenderer.nativeInsertText(text);
}
public void handleDeleteBackward() {
AxmolRenderer.nativeDeleteBackward();
public void handleDeleteBackward(final int numChars) {
AxmolRenderer.nativeDeleteBackward(numChars);
}
public String getContentText() {

View File

@ -90,8 +90,8 @@ public class TextInputWrapper implements TextWatcher, OnEditorActionListener {
new_i += 1;
}
for (; old_i < this.mText.length(); ++old_i) {
this.mGLSurfaceView.deleteBackward();
if (old_i < this.mText.length()) {
this.mGLSurfaceView.deleteBackward(this.mText.length() - old_i);
}
int nModified = s.length() - new_i;
@ -118,13 +118,13 @@ public class TextInputWrapper implements TextWatcher, OnEditorActionListener {
if (this.mGLSurfaceView.getEditText() == pTextView && this.isFullScreenEdit()) {
// user press the action button, delete all old text and insert new text
if (null != mOriginText) {
for (int i = this.mOriginText.length(); i > 0; i--) {
this.mGLSurfaceView.deleteBackward();
if (!this.mOriginText.isEmpty()) {
this.mGLSurfaceView.deleteBackward(this.mOriginText.length());
}
}
String text = pTextView.getText().toString();
if (text != null) {
/* If user input nothing, translate "\n" to engine. */
if ( text.compareTo("") == 0) {
@ -135,16 +135,16 @@ public class TextInputWrapper implements TextWatcher, OnEditorActionListener {
text += '\n';
}
}
final String insertText = text;
this.mGLSurfaceView.insertText(insertText);
}
if (pActionID == EditorInfo.IME_ACTION_DONE) {
this.mGLSurfaceView.requestFocus();
}
return false;
}
}
}

View File

@ -70,9 +70,9 @@ JNIEXPORT void JNICALL Java_org_axmol_lib_AxmolRenderer_nativeInsertText(JNIEnv*
ax::IMEDispatcher::sharedDispatcher()->dispatchInsertText(pszText, strlen(pszText));
}
JNIEXPORT void JNICALL Java_org_axmol_lib_AxmolRenderer_nativeDeleteBackward(JNIEnv*, jclass)
JNIEXPORT void JNICALL Java_org_axmol_lib_AxmolRenderer_nativeDeleteBackward(JNIEnv*, jclass, jint numChars)
{
ax::IMEDispatcher::sharedDispatcher()->dispatchDeleteBackward();
ax::IMEDispatcher::sharedDispatcher()->dispatchDeleteBackward(numChars);
}
JNIEXPORT jstring JNICALL Java_org_axmol_lib_AxmolRenderer_nativeGetContentText(JNIEnv* env, jclass)

View File

@ -98,7 +98,7 @@ THE SOFTWARE.
[self.myMarkedText release];
self.myMarkedText = nil;
}
ax::IMEDispatcher::sharedDispatcher()->dispatchDeleteBackward();
ax::IMEDispatcher::sharedDispatcher()->dispatchDeleteBackward(1);
}
- (void)insertText:(nonnull NSString*)text

View File

@ -112,7 +112,7 @@ void KeyboardEvent::execute()
//Director::getInstance()()->getKeypadDispatcher()->dispatchKeypadMSG(kTypeBackClicked);
break;
case AxmolKeyEvent::Back:
IMEDispatcher::sharedDispatcher()->dispatchDeleteBackward();
IMEDispatcher::sharedDispatcher()->dispatchDeleteBackward(1);
break;
case AxmolKeyEvent::Enter:
IMEDispatcher::sharedDispatcher()->dispatchInsertText("\n", 1);

View File

@ -304,7 +304,7 @@ void KeyBoardWinRT::OnWinRTKeyboardEvent(WinRTKeyboardEventType type, KeyEventAr
switch (keyCode)
{
case EventKeyboard::KeyCode::KEY_BACKSPACE:
IMEDispatcher::sharedDispatcher()->dispatchDeleteBackward();
IMEDispatcher::sharedDispatcher()->dispatchDeleteBackward(1);
break;
case EventKeyboard::KeyCode::KEY_HOME:
case EventKeyboard::KeyCode::KEY_KP_HOME:

View File

@ -617,7 +617,7 @@ void TextFieldEx::insertText(const char* text, size_t len)
this->closeIME();
}
void TextFieldEx::deleteBackward()
void TextFieldEx::deleteBackward(size_t numChars)
{
if (!_editable || !this->_enabled || 0 == _charCount)
{
@ -634,23 +634,33 @@ void TextFieldEx::deleteBackward()
return;
}
// get the delete byte number
size_t deleteLen = 1; // default, erase 1 byte
// Length of characters to delete is based on input editor, but the actual
// length of the displayed text may be less
numChars = std::min(numChars, len);
while (0x80 == (0xC0 & _inputText.at(_insertPos - deleteLen)))
size_t totalDeleteLen = 0;
for (auto i = 0; i < numChars; ++i)
{
++deleteLen;
// get the delete byte number
size_t deleteLen = 1; // default, erase 1 byte
// Calculate the actual number of bytes to delete for a specific character
while (0x80 == (0xC0 & _inputText.at(_insertPos - totalDeleteLen - deleteLen)))
{
++deleteLen;
}
totalDeleteLen += deleteLen;
}
// if (_delegate && _delegate->onTextFieldDeleteBackward(this, _inputText.c_str() + len - deleteLen,
// static_cast<int>(deleteLen)))
//{
// // delegate doesn't wan't to delete backwards
// // delegate doesn't want to delete backwards
// return;
// }
// if all text deleted, show placeholder string
if (len <= deleteLen)
if (len <= totalDeleteLen)
{
__moveCursor(-1);
@ -670,7 +680,7 @@ void TextFieldEx::deleteBackward()
// set new input text
std::string text = _inputText; // (inputText.c_str(), len - deleteLen);
text.erase(_insertPos - deleteLen, deleteLen);
text.erase(_insertPos - totalDeleteLen, totalDeleteLen);
__moveCursor(-1);

View File

@ -140,7 +140,7 @@ protected:
bool canAttachWithIME() override;
bool canDetachWithIME() override;
void deleteBackward() override;
void deleteBackward(size_t numChars) override;
std::string_view getContentText() override;
void handleDeleteKeyEvent();

View File

@ -40,6 +40,7 @@ THE SOFTWARE.
#include "ui/UIListView.h"
#include "ui/UISlider.h"
#include "ui/UITextField.h"
#include "ui/UITextFieldEx.h"
#include "ui/UITextBMFont.h"
#include "ui/UIPageView.h"
#include "ui/UIHelper.h"