Skip to content
This repository has been archived by the owner on Nov 3, 2021. It is now read-only.

Commit

Permalink
Merge pull request #23655 from timdream/keyboard-rocketbar-miss
Browse files Browse the repository at this point in the history
Bug 1061439 - Stop JS error by preventing IMEngine from interact with Glue, r=rudyl
Conflicts:
	apps/keyboard/index.html
  • Loading branch information
timdream authored and rvandermeulen committed Sep 5, 2014
1 parent b7e2409 commit 7c417d2
Show file tree
Hide file tree
Showing 21 changed files with 307 additions and 124 deletions.
2 changes: 1 addition & 1 deletion apps/keyboard/index.html
Expand Up @@ -14,7 +14,7 @@
<script defer type="text/javascript" src="js/keyboard/layout_loader.js"></script>
<script defer type="text/javascript" src="js/keyboard/layout_manager.js"></script>
<script defer type="text/javascript" src="js/render.js"></script>
<script defer type="text/javascript" src="js/keyboard/performance_timer.js"></script>
<script defer type="text/javascript" src="js/keyboard/console.js"></script>
<script defer type="text/javascript" src="js/keyboard/input_method_manager.js"></script>
<script defer type="text/javascript" src="js/keyboard/settings.js"></script>
<script defer type="text/javascript" src="js/keyboard/feedback_manager.js"></script>
Expand Down
3 changes: 3 additions & 0 deletions apps/keyboard/js/imes/latin/latin.js
Expand Up @@ -418,6 +418,9 @@
}, function() {
// the previous sendKey or replaceSurroundingText has been rejected,
// No need to update the state.
})['catch'](function(e) { // ['catch'] for gjslint error
// Print the error and make sure inputSequencePromise always resolves.
console.error(e);
});

// Need to return the promise, so that the caller could know
Expand Down
7 changes: 7 additions & 0 deletions apps/keyboard/js/keyboard/active_targets_manager.js
Expand Up @@ -43,6 +43,7 @@ ActiveTargetsManager.prototype.LONG_PRESS_TIMEOUT = 700;
ActiveTargetsManager.prototype.DOUBLE_TAP_TIMEOUT = 450;

ActiveTargetsManager.prototype.start = function() {
this.app.console.log('ActiveTargetsManager.start()');
this.activeTargets = new Map();
this.doubleTapTimers = new WeakMap();

Expand All @@ -59,6 +60,7 @@ ActiveTargetsManager.prototype.start = function() {
};

ActiveTargetsManager.prototype.stop = function() {
this.app.console.log('ActiveTargetsManager.stop()');
this.activeTargets = null;

this.userPressManager.stop();
Expand All @@ -71,6 +73,7 @@ ActiveTargetsManager.prototype.stop = function() {
};

ActiveTargetsManager.prototype.clearAllTargets = function() {
this.app.console.log('ActiveTargetsManager.clearAllTargets()');
if (this.activeTargets.size) {
console.warn('ActiveTargetsManager: clear ' +
this.activeTargets.size + ' active target(s).');
Expand All @@ -90,6 +93,7 @@ ActiveTargetsManager.prototype.clearAllTargets = function() {
};

ActiveTargetsManager.prototype._handlePressStart = function(press, id) {
this.app.console.log('ActiveTargetsManager._handlePressStart()');
// Ignore new touches if menu is shown
if (this.alternativesCharMenuManager.isShown) {
return;
Expand Down Expand Up @@ -117,6 +121,7 @@ ActiveTargetsManager.prototype._handlePressStart = function(press, id) {
};

ActiveTargetsManager.prototype._handlePressMove = function(press, id) {
this.app.console.log('ActiveTargetsManager._handlePressMove()');
if (!this.activeTargets.has(id)) {
return;
}
Expand Down Expand Up @@ -178,6 +183,7 @@ ActiveTargetsManager.prototype._handlePressMove = function(press, id) {
};

ActiveTargetsManager.prototype._handleLongPress = function(press, id) {
this.app.console.log('ActiveTargetsManager._handleLongPress()');
if (!this.activeTargets.has(id)) {
return;
}
Expand All @@ -196,6 +202,7 @@ ActiveTargetsManager.prototype._handleLongPress = function(press, id) {
};

ActiveTargetsManager.prototype._handlePressEnd = function(press, id) {
this.app.console.log('ActiveTargetsManager._handlePressEnd()');
if (!this.activeTargets.has(id)) {
return;
}
Expand Down
86 changes: 86 additions & 0 deletions apps/keyboard/js/keyboard/console.js
@@ -0,0 +1,86 @@
'use strict';

/* global console, performance */

/**
* KeyboardConsole is an incomplete implementation of console so we could
* turn it on and off on build time.
*/

(function(exports) {
var KeyboardConsole = function KeyboardConsole() {
this._timers = null;
};

KeyboardConsole.prototype.start = function() {
var timers = this._timers = new Map();
timers.set('domLoading', performance.timing.domLoading);

this._startTime = Date.now();
};

/**
*
* Log level decides whether or not to print log.
*
* 0 - warn() and error()
* 1 - info()
* 2 - log() and time() and timeEnd()
* 3 - trace()
*
* Note that we want console.warn() and console.error() show up in
* production too so warn() and error() is not implemented here.
*
*/
KeyboardConsole.prototype.LOG_LEVEL = 0;

KeyboardConsole.prototype.trace = function() {
if (this.LOG_LEVEL < 3) {
return;
}

console.trace.apply(console, arguments);
};

KeyboardConsole.prototype.time = function(timerName) {
if (this.LOG_LEVEL < 2) {
return;
}

console.time(timerName);
};

KeyboardConsole.prototype.timeEnd = function(timerName) {
if (this.LOG_LEVEL < 2) {
return;
}

if (this._timers.has(timerName)) {
console.log(timerName + ': ' +
(Date.now() - this._timers.get(timerName)) + 'ms');

return;
}

console.timeEnd(timerName);
};

KeyboardConsole.prototype.log = function() {
if (this.LOG_LEVEL < 2) {
return;
}

console.log.apply(console, arguments);
};

KeyboardConsole.prototype.info = function() {
if (this.LOG_LEVEL < 1) {
return;
}

console.info.apply(console, arguments);
};

exports.KeyboardConsole = KeyboardConsole;

})(window);
87 changes: 81 additions & 6 deletions apps/keyboard/js/keyboard/input_method_manager.js
Expand Up @@ -141,30 +141,51 @@ InputMethodGlue.prototype.init = function(app, imEngineName) {
};

InputMethodGlue.prototype.sendCandidates = function(candidates) {
this.app.console.trace();
if (!this.app.inputContext) {
console.warn('InputMethodGlue: call sendCandidates() when ' +
'inputContext does not exist.');
return;
}
this.app.candidatePanelManager.updateCandidates(candidates);
};

InputMethodGlue.prototype.setComposition = function(symbols, cursor) {
this.app.console.trace();
if (!this.app.inputContext) {
console.warn('InputMethodGlue: call setComposition() when ' +
'inputContext does not exist.');
return;
}
cursor = cursor || symbols.length;
this.app.inputContext.setComposition(symbols, cursor);
this.app.console.info('inputContext.setComposition()');
this.app.inputContext.setComposition(symbols, cursor).catch(function(e) {
console.warn('InputMethodGlue: setComposition() rejected with error', e);
this.app.console.log(symbols, cursor);

return Promise.reject(e);
}.bind(this));
};

InputMethodGlue.prototype.endComposition = function(text) {
this.app.console.trace();
if (!this.app.inputContext) {
console.warn('InputMethodGlue: call endComposition() when ' +
'inputContext does not exist.');
return;
}
text = text || '';
this.app.inputContext.endComposition(text);
this.app.console.info('inputContext.endComposition()');
return this.app.inputContext.endComposition(text).catch(function(e) {
console.warn('InputMethodGlue: endComposition() rejected with error', e);
this.app.console.log(text);

return Promise.reject(e);
}.bind(this));
};

InputMethodGlue.prototype.sendKey = function(keyCode, isRepeat) {
this.app.console.trace();
if (!this.app.inputContext) {
console.warn('InputMethodGlue: call sendKey() when ' +
'inputContext does not exist.');
Expand All @@ -173,6 +194,7 @@ InputMethodGlue.prototype.sendKey = function(keyCode, isRepeat) {

var promise;

this.app.console.info('inputContext.sendKey()');
switch (keyCode) {
case KeyEvent.DOM_VK_BACK_SPACE:
promise = this.app.inputContext.sendKey(keyCode, 0, 0, isRepeat);
Expand All @@ -187,11 +209,17 @@ InputMethodGlue.prototype.sendKey = function(keyCode, isRepeat) {
break;
}

return promise;
return promise.catch(function(e) {
console.warn('InputMethodGlue: sendKey() rejected with error', e);
this.app.console.log(keyCode, isRepeat);

return Promise.reject(e);
}.bind(this));
};

// XXX deprecated
InputMethodGlue.prototype.sendString = function(str) {
this.app.console.trace();
for (var i = 0; i < str.length; i++) {
this.sendKey(str.charCodeAt(i));
}
Expand All @@ -200,11 +228,23 @@ InputMethodGlue.prototype.sendString = function(str) {
// Set the current rendered layout to a specific named layout
// XXX deprecated; overwrite alternative/symbol layout instead.
InputMethodGlue.prototype.alterKeyboard = function(layoutName) {
this.app.console.trace();
if (!this.app.inputContext) {
console.warn('InputMethodGlue: call alterKeyboard() when ' +
'inputContext does not exist.');
return;
}
this.app.layoutManager.updateForcedModifiedLayout(layoutName);
this.app.layoutRenderingManager.updateLayoutRendering();
};

InputMethodGlue.prototype.setLayoutPage = function(newpage) {
this.app.console.trace();
if (!this.app.inputContext) {
console.warn('InputMethodGlue: call setLayoutPage() when ' +
'inputContext does not exist.');
return;
}
if (newpage !== this.app.layoutManager.LAYOUT_PAGE_DEFAULT) {
throw new Error('InputMethodGlue: ' +
'imEngine is only allowed to switch to default page');
Expand All @@ -213,22 +253,41 @@ InputMethodGlue.prototype.setLayoutPage = function(newpage) {
};

InputMethodGlue.prototype.setUpperCase = function(state) {
this.app.console.trace();
if (!this.app.inputContext) {
console.warn('InputMethodGlue: call setUpperCase() when ' +
'inputContext does not exist.');
return;
}
this.app.upperCaseStateManager.switchUpperCaseState(state);
};

InputMethodGlue.prototype.isCapitalized = function() {
this.app.console.trace();
return this.app.upperCaseStateManager.isUpperCase;
};

InputMethodGlue.prototype.replaceSurroundingText = function(text, offset,
length) {
this.app.console.trace();

if (!this.app.inputContext) {
console.warn('InputMethodGlue: call replaceSurroundingText() when ' +
'inputContext does not exist.');
return Promise.reject();
}

return this.app.inputContext.replaceSurroundingText(text, offset, length);
this.app.console.info('inputContext.replaceSurroundingText()');
var p = this.app.inputContext.replaceSurroundingText(text, offset, length);
p.catch(function(e) {
console.warn('InputMethodGlue: ' +
'replaceSurroundingText() rejected with error', e);
this.app.console.log(text, offset, length);

return Promise.reject(e);
}.bind(this));

return p;
};

InputMethodGlue.prototype.getNumberOfCandidatesPerRow = function() {
Expand Down Expand Up @@ -333,6 +392,7 @@ InputMethodManager.prototype.start = function() {
* the data needs to activate the IMEngine.
*/
InputMethodManager.prototype.updateInputContextData = function() {
this.app.console.log('InputMethodManager.updateInputContextData()');
// Do nothing if there is already a promise or there is no inputContext
if (!this.app.inputContext || this._inputContextData) {
return;
Expand All @@ -344,7 +404,7 @@ InputMethodManager.prototype.updateInputContextData = function() {
var inputContext = this.app.inputContext;

var p = inputContext.getText().then(function(value) {
this.app.perfTimer.printTime('updateInputContextData:promise resolved');
this.app.console.log('updateInputContextData:promise resolved');

// Resolve to this object containing information of inputContext
return {
Expand Down Expand Up @@ -381,7 +441,11 @@ InputMethodManager.prototype.updateInputContextData = function() {
*
*/
InputMethodManager.prototype.switchCurrentIMEngine = function(imEngineName) {
this.app.console.log(
'InputMethodManager.switchCurrentIMEngine()', imEngineName);

var switchStateId = ++this._switchStateId;
this.app.console.time('switchCurrentIMEngine' + switchStateId);

// dataPromise is the one we previously created with updateInputContextData()
var dataPromise = this._inputContextData;
Expand All @@ -397,6 +461,8 @@ InputMethodManager.prototype.switchCurrentIMEngine = function(imEngineName) {

// Deactivate and switch the currentIMEngine to 'default' first.
if (this.currentIMEngine && this.currentIMEngine.deactivate) {
this.app.console.log(
'InputMethodManager::currentIMEngine.deactivate()');
this.currentIMEngine.deactivate();
}
if (this.app.inputContext) {
Expand All @@ -413,7 +479,7 @@ InputMethodManager.prototype.switchCurrentIMEngine = function(imEngineName) {
var p = Promise.all([loaderPromise, dataPromise, settingsPromise])
.then(function(values) {
if (switchStateId !== this._switchStateId) {
console.log('InputMethodManager: ' +
console.warn('InputMethodManager: ' +
'Promise is resolved after another switchCurrentIMEngine() call.');

return Promise.reject();
Expand All @@ -429,6 +495,8 @@ InputMethodManager.prototype.switchCurrentIMEngine = function(imEngineName) {
currentLayout.autoCorrectPunctuation :
true;

this.app.console.log(
'InputMethodManager::currentIMEngine.activate()');
imEngine.activate(
this.app.layoutManager.currentModifiedLayout.autoCorrectLanguage,
dataValues,
Expand All @@ -448,19 +516,26 @@ InputMethodManager.prototype.switchCurrentIMEngine = function(imEngineName) {
this.app.inputContext.addEventListener('surroundingtextchange', this);
}
this.currentIMEngine = imEngine;
this.app.console.timeEnd('switchCurrentIMEngine' + switchStateId);
}.bind(this));

return p;
};

InputMethodManager.prototype.handleEvent = function(evt) {
this.app.console.info('InputMethodManager.handleEvent()', evt);
switch (evt.type) {
case 'selectionchange':
this.app.console.log(
'InputMethodManager::currentIMEngine.selectionChange()', evt.detail);
this.currentIMEngine.selectionChange(evt.detail);

break;

case 'surroundingtextchange':
this.app.console.log(
'InputMethodManager::currentIMEngine.surroundingtextChange()',
evt.detail);
this.currentIMEngine.surroundingtextChange(evt.detail);

break;
Expand Down

0 comments on commit 7c417d2

Please sign in to comment.