Merge latest green fx-team changeset and mozilla-central

This commit is contained in:
Ed Morley 2013-08-30 17:19:46 +01:00
commit 19ef85f0b3
14 changed files with 380 additions and 38 deletions

View File

@ -197,6 +197,8 @@ let FormAssistant = {
addMessageListener("Forms:GetText", this);
addMessageListener("Forms:Input:SendKey", this);
addMessageListener("Forms:GetContext", this);
addMessageListener("Forms:SetComposition", this);
addMessageListener("Forms:EndComposition", this);
},
ignoredInputTypes: new Set([
@ -239,6 +241,7 @@ let FormAssistant = {
if (this.focusedElement) {
this.focusedElement.removeEventListener('mousedown', this);
this.focusedElement.removeEventListener('mouseup', this);
this.focusedElement.removeEventListener('compositionend', this);
if (this._observer) {
this._observer.disconnect();
this._observer = null;
@ -263,6 +266,7 @@ let FormAssistant = {
if (element) {
element.addEventListener('mousedown', this);
element.addEventListener('mouseup', this);
element.addEventListener('compositionend', this);
if (isContentEditable(element)) {
this._documentEncoder = getDocumentEncoder(element);
}
@ -423,6 +427,8 @@ let FormAssistant = {
break;
}
CompositionManager.endComposition('');
// Don't monitor the text change resulting from key event.
this._ignoreEditActionOnce = true;
@ -438,8 +444,18 @@ let FormAssistant = {
break;
}
CompositionManager.endComposition('');
this._ignoreEditActionOnce = false;
break;
case "compositionend":
if (!this.focusedElement) {
break;
}
CompositionManager.onCompositionEnd();
break;
}
},
@ -475,6 +491,8 @@ let FormAssistant = {
this._editing = true;
switch (msg.name) {
case "Forms:Input:Value": {
CompositionManager.endComposition('');
target.value = json.value;
let event = target.ownerDocument.createEvent('HTMLEvents');
@ -484,6 +502,8 @@ let FormAssistant = {
}
case "Forms:Input:SendKey":
CompositionManager.endComposition('');
["keydown", "keypress", "keyup"].forEach(function(type) {
domWindowUtils.sendKeyEvent(type, json.keyCode, json.charCode,
json.modifiers);
@ -528,6 +548,8 @@ let FormAssistant = {
}
case "Forms:SetSelectionRange": {
CompositionManager.endComposition('');
let start = json.selectionStart;
let end = json.selectionEnd;
setSelectionRange(target, start, end);
@ -543,6 +565,8 @@ let FormAssistant = {
}
case "Forms:ReplaceSurroundingText": {
CompositionManager.endComposition('');
let text = json.text;
let beforeLength = json.beforeLength;
let afterLength = json.afterLength;
@ -583,6 +607,23 @@ let FormAssistant = {
sendAsyncMessage("Forms:GetContext:Result:OK", obj);
break;
}
case "Forms:SetComposition": {
CompositionManager.setComposition(target, json.text, json.cursor,
json.clauses);
sendAsyncMessage("Forms:SetComposition:Result:OK", {
requestId: json.requestId,
});
break;
}
case "Forms:EndComposition": {
CompositionManager.endComposition(json.text);
sendAsyncMessage("Forms:EndComposition:Result:OK", {
requestId: json.requestId,
});
break;
}
}
this._editing = false;
@ -1015,3 +1056,97 @@ function replaceSurroundingText(element, text, selectionStart, beforeLength,
editor.insertText(text);
}
}
let CompositionManager = {
_isStarted: false,
_text: '',
_clauseAttrMap: {
'raw-input': domWindowUtils.COMPOSITION_ATTR_RAWINPUT,
'selected-raw-text': domWindowUtils.COMPOSITION_ATTR_SELECTEDRAWTEXT,
'converted-text': domWindowUtils.COMPOSITION_ATTR_CONVERTEDTEXT,
'selected-converted-text': domWindowUtils.COMPOSITION_ATTR_SELECTEDCONVERTEDTEXT
},
setComposition: function cm_setComposition(element, text, cursor, clauses) {
// Check parameters.
if (!element) {
return;
}
let len = text.length;
if (cursor < 0) {
cursor = 0;
} else if (cursor > len) {
cursor = len;
}
let clauseLens = [len, 0, 0];
let clauseAttrs = [domWindowUtils.COMPOSITION_ATTR_RAWINPUT,
domWindowUtils.COMPOSITION_ATTR_RAWINPUT,
domWindowUtils.COMPOSITION_ATTR_RAWINPUT];
if (clauses) {
let remainingLength = len;
// Currently we don't support 4 or more clauses composition string.
let clauseNum = Math.min(3, clauses.length);
for (let i = 0; i < clauseNum; i++) {
if (clauses[i]) {
let clauseLength = clauses[i].length || 0;
// Make sure the total clauses length is not bigger than that of the
// composition string.
if (clauseLength > remainingLength) {
clauseLength = remainingLength;
}
remainingLength -= clauseLength;
clauseLens[i] = clauseLength;
clauseAttrs[i] = this._clauseAttrMap[clauses[i].selectionType] ||
domWindowUtils.COMPOSITION_ATTR_RAWINPUT;
}
}
// If the total clauses length is less than that of the composition
// string, extend the last clause to the end of the composition string.
if (remainingLength > 0) {
clauseLens[2] += remainingLength;
}
}
// Start composition if need to.
if (!this._isStarted) {
this._isStarted = true;
domWindowUtils.sendCompositionEvent('compositionstart', '', '');
this._text = '';
}
// Update the composing text.
if (this._text !== text) {
this._text = text;
domWindowUtils.sendCompositionEvent('compositionupdate', text, '');
}
domWindowUtils.sendTextEvent(text,
clauseLens[0], clauseAttrs[0],
clauseLens[1], clauseAttrs[1],
clauseLens[2], clauseAttrs[2],
cursor, 0);
},
endComposition: function cm_endComposition(text) {
if (!this._isStarted) {
return;
}
// Update the composing text.
if (this._text !== text) {
domWindowUtils.sendCompositionEvent('compositionupdate', text, '');
}
domWindowUtils.sendTextEvent(text, 0, 0, 0, 0, 0, 0, 0, 0);
domWindowUtils.sendCompositionEvent('compositionend', text, '');
this._text = '';
this._isStarted = false;
},
// Composition ends due to external actions.
onCompositionEnd: function cm_onCompositionEnd() {
if (!this._isStarted) {
return;
}
this._text = '';
this._isStarted = false;
}
};

View File

@ -23,7 +23,8 @@ let Keyboard = {
'SetValue', 'RemoveFocus', 'SetSelectedOption', 'SetSelectedOptions',
'SetSelectionRange', 'ReplaceSurroundingText', 'ShowInputMethodPicker',
'SwitchToNextInputMethod', 'HideInputMethod',
'GetText', 'SendKey', 'GetContext'
'GetText', 'SendKey', 'GetContext',
'SetComposition', 'EndComposition'
],
get messageManager() {
@ -66,6 +67,8 @@ let Keyboard = {
mm.addMessageListener('Forms:SendKey:Result:OK', this);
mm.addMessageListener('Forms:SequenceError', this);
mm.addMessageListener('Forms:GetContext:Result:OK', this);
mm.addMessageListener('Forms:SetComposition:Result:OK', this);
mm.addMessageListener('Forms:EndComposition:Result:OK', this);
// When not running apps OOP, we need to load forms.js here since this
// won't happen from dom/ipc/preload.js
@ -116,6 +119,8 @@ let Keyboard = {
case 'Forms:SendKey:Result:OK':
case 'Forms:SequenceError':
case 'Forms:GetContext:Result:OK':
case 'Forms:SetComposition:Result:OK':
case 'Forms:EndComposition:Result:OK':
let name = msg.name.replace(/^Forms/, 'Keyboard');
this.forwardEvent(name, msg);
break;
@ -153,6 +158,12 @@ let Keyboard = {
case 'Keyboard:GetContext':
this.getContext(msg);
break;
case 'Keyboard:SetComposition':
this.setComposition(msg);
break;
case 'Keyboard:EndComposition':
this.endComposition(msg);
break;
}
},
@ -223,6 +234,14 @@ let Keyboard = {
getContext: function keyboardGetContext(msg) {
this.messageManager.sendAsyncMessage('Forms:GetContext', msg.data);
},
setComposition: function keyboardSetComposition(msg) {
this.messageManager.sendAsyncMessage('Forms:SetComposition', msg.data);
},
endComposition: function keyboardEndComposition(msg) {
this.messageManager.sendAsyncMessage('Forms:EndComposition', msg.data);
}
};

View File

@ -415,6 +415,8 @@ MozInputContext.prototype = {
"Keyboard:SetSelectionRange:Result:OK",
"Keyboard:ReplaceSurroundingText:Result:OK",
"Keyboard:SendKey:Result:OK",
"Keyboard:SetComposition:Result:OK",
"Keyboard:EndComposition:Result:OK",
"Keyboard:SequenceError"]);
},
@ -472,6 +474,10 @@ MozInputContext.prototype = {
// not invalidated yet...
resolver.reject("InputContext has expired");
break;
case "Keyboard:SetComposition:Result:OK": // Fall through.
case "Keyboard:EndComposition:Result:OK":
resolver.resolve();
break;
default:
dump("Could not find a handler for " + msg.name);
resolver.reject();
@ -627,12 +633,30 @@ MozInputContext.prototype = {
});
},
setComposition: function ic_setComposition(text, cursor) {
throw new this._window.DOMError("NotSupportedError", "Not implemented");
setComposition: function ic_setComposition(text, cursor, clauses) {
let self = this;
return this.createPromise(function(resolver) {
let resolverId = self.getPromiseResolverId(resolver);
cpmm.sendAsyncMessage('Keyboard:SetComposition', {
contextId: self._contextId,
requestId: resolverId,
text: text,
cursor: cursor || text.length,
clauses: clauses || null
});
});
},
endComposition: function ic_endComposition(text) {
throw new this._window.DOMError("NotSupportedError", "Not implemented");
let self = this;
return this.createPromise(function(resolver) {
let resolverId = self.getPromiseResolverId(resolver);
cpmm.sendAsyncMessage('Keyboard:EndComposition', {
contextId: self._contextId,
requestId: resolverId,
text: text || ''
});
});
}
};

View File

@ -1,4 +1,4 @@
{
"revision": "9adc8de2a121d92d43a4669c4326695fe703eb71",
"revision": "b3e578bc32cefba0e0ee997a945898a7c7b9024d",
"repo_path": "/integration/gaia-central"
}

View File

@ -89,10 +89,14 @@ public:
NS_IMETHODIMP Run()
{
MOZ_ASSERT(NS_IsMainThread());
mRecorder->mState = RecordingState::Inactive;
mRecorder->DispatchSimpleEvent(NS_LITERAL_STRING("stop"));
mRecorder->mReadThread->Shutdown();
mRecorder->mReadThread = nullptr;
// Setting mState to Inactive here is for the case where SourceStream
// ends itself, thus the recorder should stop itself too.
mRecorder->mState = RecordingState::Inactive;
mRecorder->DispatchSimpleEvent(NS_LITERAL_STRING("stop"));
return NS_OK;
}
@ -154,7 +158,7 @@ MediaRecorder::ExtractEncodedData()
NS_DispatchToMainThread(new PushBlobTask(this));
lastBlobTimeStamp = TimeStamp::Now();
}
} while (mState == RecordingState::Recording && !mEncoder->IsShutdown());
} while (!mEncoder->IsShutdown());
NS_DispatchToMainThread(new PushBlobTask(this));
}
@ -229,7 +233,12 @@ MediaRecorder::Stop(ErrorResult& aResult)
return;
}
mState = RecordingState::Inactive;
mTrackUnionStream->RemoveListener(mEncoder);
mStreamPort->Destroy();
mStreamPort = nullptr;
mTrackUnionStream->Destroy();
mTrackUnionStream = nullptr;
}
void

View File

@ -82,7 +82,7 @@ AudioTrackEncoder::NotifyEndOfStream()
// If source audio chunks are completely silent till the end of encoding,
// initialize the encoder with default channel counts and sampling rate, and
// append this many null data to the segment of track encoder.
if (!mCanceled && !mInitialized && mSilentDuration > 0) {
if (!mCanceled && !mInitialized) {
Init(DEFAULT_CHANNELS, DEFAULT_SAMPLING_RATE);
mRawSegment->AppendNullData(mSilentDuration);
mSilentDuration = 0;

View File

@ -127,6 +127,7 @@ MOCHITEST_FILES = \
test_decoder_disable.html \
test_mediarecorder_record_no_timeslice.html \
test_mediarecorder_reload_crash.html \
test_mediarecorder_record_immediate_stop.html \
test_media_selection.html \
test_playback.html \
test_seekLies.html \

View File

@ -0,0 +1,113 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Test MediaRecorder Immediate Stop</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
<script type="text/javascript" src="manifest.js"></script>
</head>
<body>
<pre id="test">
<script class="testbody" type="text/javascript">
var manager = new MediaTestManager;
/**
* Stops the media recorder immediately after starting the recorder. This test
* verifies whether the media recorder can handle this scenario nicely. The
* return blob size should be greater than zero, but its duration would be zero
* length when play.
*/
function startTest(test, token) {
var element = document.createElement('audio');
var expectedMimeType = test.type.substring(0, test.type.indexOf(';'));
element.token = token;
manager.started(token);
element.src = test.name;
element.test = test;
element.stream = element.mozCaptureStreamUntilEnded();
var mediaRecorder = new MediaRecorder(element.stream);
var onStopFired = false;
var onDataAvailableFired = false;
mediaRecorder.onerror = function () {
ok(false, 'Unexpected onerror callback fired');
};
mediaRecorder.onwarning = function () {
ok(false, 'Unexpected onwarning callback fired');
};
// This handler verifies that only a single onstop event handler is fired.
mediaRecorder.onstop = function () {
if (onStopFired) {
ok(false, 'onstop unexpectedly fired more than once');
} else {
onStopFired = true;
// ondataavailable should always fire before onstop
if (onDataAvailableFired) {
manager.finished(token);
} else {
ok(false, 'onstop fired without an ondataavailable event first');
}
}
};
// This handler verifies that only a single ondataavailable event handler
// is fired with the blob generated having greater than zero size
// and a correct mime type.
mediaRecorder.ondataavailable = function (evt) {
if (onDataAvailableFired) {
ok(false, 'ondataavailable unexpectedly fired more than once');
} else {
onDataAvailableFired = true;
ok(evt instanceof BlobEvent,
'Events fired from ondataavailable should be BlobEvent');
is(evt.type, 'dataavailable',
'Event type should dataavailable');
ok(evt.data.size > 0,
'Blob data received should be greater than zero');
is(evt.data.type, expectedMimeType,
'Blob data received should have type = ' + expectedMimeType);
is(mediaRecorder.mimeType, expectedMimeType,
'Mime type in ondataavailable = ' + expectedMimeType);
// onstop should not have fired before ondataavailable
if (onStopFired) {
ok(false, 'ondataavailable unexpectedly fired later than onstop');
manager.finished(token);
}
}
};
// This handler completes a start and stop of recording and verifies
// respective media recorder state.
var canPlayThrough = function() {
element.removeEventListener('canplaythrough', canPlayThrough, false);
mediaRecorder.start();
is(mediaRecorder.state, 'recording', 'Media recorder should be recording');
is(mediaRecorder.stream, element.stream,
'Media recorder stream = element stream at the start of recording');
mediaRecorder.stop();
is(mediaRecorder.state, 'inactive',
'Media recorder is inactive after being stopped');
is(mediaRecorder.stream, element.stream,
'Media recorder stream = element stream post recording');
};
element.addEventListener('canplaythrough', canPlayThrough, false);
element.play();
}
manager.runTests(gMediaRecorderTests, startTest);
</script>
</pre>
</body>
</html>

View File

@ -184,8 +184,12 @@ function xpcWaitForFinishedFrames(callback, numFrames) {
(win.document.body.textContent == body ||
win.document.body.textContent == popup_body) &&
win.document.readyState == "complete") {
if (!contains(win, finishedWindows)) {
finishedWindows.push(win);
var util = win.QueryInterface(SpecialPowers.Ci.nsIInterfaceRequestor)
.getInterface(SpecialPowers.Ci.nsIDOMWindowUtils);
var windowId = util.outerWindowID;
if (!contains(windowId, finishedWindows)) {
finishedWindows.push(windowId);
frameFinished();
}
}

View File

@ -146,24 +146,59 @@ interface MozInputContext: EventTarget {
Promise sendKey(long keyCode, long charCode, long modifiers);
/*
* Set current composition. It will start or update composition.
* @param cursor Position in the text of the cursor.
* Set current composing text. This method will start composition or update
* composition if it has started. The composition will be started right
* before the cursor position and any selected text will be replaced by the
* composing text. When the composition is started, calling this method can
* update the text and move cursor winthin the range of the composing text.
* @param text The new composition text to show.
* @param cursor The new cursor position relative to the start of the
* composition text. The cursor should be positioned within the composition
* text. This means the value should be >= 0 and <= the length of
* composition text. Defaults to the lenght of composition text, i.e., the
* cursor will be positioned after the composition text.
* @param clauses The array of composition clause information. If not set,
* only one clause is supported.
*
* The API implementation should automatically ends the composition
* session (with event and confirm the current composition) if
* endComposition is never called. Same apply when the inputContext is lost
* during a unfinished composition session.
* The composing text, which is shown with underlined style to distinguish
* from the existing text, is used to compose non-ASCII characters from
* keystrokes, e.g. Pinyin or Hiragana. The composing text is the
* intermediate text to help input complex character and is not committed to
* current input field. Therefore if any text operation other than
* composition is performed, the composition will automatically end. Same
* apply when the inputContext is lost during an unfinished composition
* session.
*
* To finish composition and commit text to current input field, an IME
* should call |endComposition|.
*/
Promise setComposition(DOMString text, long cursor);
Promise setComposition(DOMString text, optional long cursor,
optional sequence<CompositionClauseParameters> clauses);
/*
* End composition and actually commit the text. (was |commitText(text, offset, length)|)
* Ending the composition with an empty string will not send any text.
* Note that if composition always ends automatically (with the current composition committed)
* if the composition did not explicitly with |endComposition()| but was interrupted with
* |sendKey()|, |setSelectionRange()|, user moving the cursor, or remove the focus, etc.
* End composition, clear the composing text and commit given text to
* current input field. The text will be committed before the cursor
* position.
* @param text The text to commited before cursor position. If empty string
* is given, no text will be committed.
*
* @param text The text
* Note that composition always ends automatically with nothing to commit if
* the composition does not explicitly end by calling |endComposition|, but
* is interrupted by |sendKey|, |setSelectionRange|,
* |replaceSurroundingText|, |deleteSurroundingText|, user moving the
* cursor, changing the focus, etc.
*/
Promise endComposition(DOMString text);
Promise endComposition(optional DOMString text);
};
enum CompositionClauseSelectionType {
"raw-input",
"selected-raw-text",
"converted-text",
"selected-converted-text"
};
dictionary CompositionClauseParameters {
DOMString selectionType = "raw-input";
long length;
};

View File

@ -128,7 +128,7 @@ GrallocTextureClientOGL::AllocateForSurface(gfx::IntSize aSize)
}
bool
GrallocTextureClientOGL::AllocateForYCbCr(gfx::IntSize aYSize, gfx::IntSize aCbCrSize)
GrallocTextureClientOGL::AllocateForYCbCr(gfx::IntSize aYSize, gfx::IntSize aCbCrSize, StereoMode aStereoMode)
{
return AllocateGralloc(aYSize,
HAL_PIXEL_FORMAT_YV12,

View File

@ -78,7 +78,9 @@ public:
virtual bool AllocateForSurface(gfx::IntSize aSize) MOZ_OVERRIDE;
virtual bool AllocateForYCbCr(gfx::IntSize aYSize, gfx::IntSize aCbCrSize) MOZ_OVERRIDE;
virtual bool AllocateForYCbCr(gfx::IntSize aYSize,
gfx::IntSize aCbCrSize,
StereoMode aStereoMode) MOZ_OVERRIDE;
bool AllocateGralloc(gfx::IntSize aYSize, uint32_t aAndroidFormat, uint32_t aUsage);
@ -116,4 +118,4 @@ protected:
} // namespace mozilla
#endif // MOZ_WIDGET_GONK
#endif
#endif

View File

@ -143,7 +143,7 @@ GrallocTextureSourceOGL::GetTextureTarget() const
}
gfx::SurfaceFormat
GrallocTextureSourceOGL::GetFormat() const MOZ_OVERRIDE {
GrallocTextureSourceOGL::GetFormat() const {
if (!mGraphicBuffer.get()) {
return gfx::FORMAT_UNKNOWN;
}

View File

@ -26,23 +26,25 @@ public:
android::GraphicBuffer* aGraphicBuffer,
gfx::SurfaceFormat aFormat);
virtual TextureSourceOGL* AsSourceOGL() MOZ_OVERRIDE { return this; }
virtual bool IsValid() const MOZ_OVERRIDE;
virtual void BindTexture(GLenum aTextureUnit) MOZ_OVERRIDE;
virtual void UnbindTexture() MOZ_OVERRIDE {}
virtual gfx::IntSize GetSize() const MOZ_OVERRIDE;
virtual gfx::SurfaceFormat GetFormat() const MOZ_OVERRIDE;
virtual TextureSourceOGL* AsSourceOGL() MOZ_OVERRIDE { return this; }
virtual GLenum GetTextureTarget() const MOZ_OVERRIDE;
virtual gfx::SurfaceFormat GetFormat() const MOZ_OVERRIDE;
virtual GLenum GetWrapMode() const MOZ_OVERRIDE
{
return LOCAL_GL_CLAMP_TO_EDGE;
}
virtual void UnbindTexture() MOZ_OVERRIDE {}
void DeallocateDeviceData();
gl::GLContext* gl() const;
@ -57,8 +59,6 @@ public:
mGraphicBuffer = nullptr;
}
bool IsValid() const;
already_AddRefed<gfxImageSurface> GetAsSurface();
protected:
@ -84,8 +84,6 @@ public:
virtual void Unlock() MOZ_OVERRIDE;
virtual bool IsValid() const MOZ_OVERRIDE;
virtual void SetCompositor(Compositor* aCompositor) MOZ_OVERRIDE;
virtual void DeallocateSharedData() MOZ_OVERRIDE;
@ -105,6 +103,8 @@ public:
virtual already_AddRefed<gfxImageSurface> GetAsSurface() MOZ_OVERRIDE;
bool IsValid() const;
#ifdef MOZ_LAYERS_HAVE_LOG
virtual const char* Name() { return "GrallocTextureHostOGL"; }
#endif