mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-29 07:42:04 +00:00
Bug 593891 - Part 3 : Fennec nsICapturePicker implementation [r=mfinkle]
This commit is contained in:
parent
d79d54482e
commit
5a5295587e
174
mobile/chrome/content/CaptureDialog.js
Normal file
174
mobile/chrome/content/CaptureDialog.js
Normal file
@ -0,0 +1,174 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (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.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* Portions created by the Initial Developer are Copyright (C) 2009
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Fabrice Desré <fabrice@mozilla.com>, Original author
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
var CaptureDialog = {
|
||||
_video: null,
|
||||
_container: null,
|
||||
_lastOrientationEvent: null,
|
||||
|
||||
init: function() {
|
||||
document.getElementsByAttribute('command', 'cmd_ok')[0].focus();
|
||||
this._video = document.getElementById("capturepicker-video");
|
||||
this._container = document.getElementById("capturepicker-container");
|
||||
window.addEventListener("resize", this, false);
|
||||
window.addEventListener("deviceorientation", this, false);
|
||||
this.handleEvent({ type: "resize" });
|
||||
},
|
||||
|
||||
setPreviewOrientation: function(aEvent) {
|
||||
if (window.innerWidth < window.innerHeight) {
|
||||
if (aEvent.beta > 0)
|
||||
this._video.style.MozTransform = "rotate(90deg)";
|
||||
else
|
||||
this._video.style.MozTransform = "rotate(-90deg)";
|
||||
this._container.classList.add("vertical");
|
||||
}
|
||||
else {
|
||||
if (aEvent.gamma > 0)
|
||||
this._video.style.MozTransform = "rotate(180deg)";
|
||||
else
|
||||
this._video.style.MozTransform = "";
|
||||
this._container.classList.remove("vertical");
|
||||
}
|
||||
},
|
||||
|
||||
handleEvent: function(aEvent) {
|
||||
if (aEvent.type == "deviceorientation") {
|
||||
if (!this._lastOrientationEvent)
|
||||
this.setPreviewOrientation(aEvent);
|
||||
this._lastOrientationEvent = aEvent;
|
||||
}
|
||||
else if (aEvent.type == "resize") {
|
||||
if (this._lastOrientationEvent)
|
||||
this.setPreviewOrientation(this._lastOrientationEvent);
|
||||
}
|
||||
},
|
||||
|
||||
cancel: function() {
|
||||
this.doClose(false);
|
||||
},
|
||||
|
||||
capture: function() {
|
||||
this.doClose(true);
|
||||
},
|
||||
|
||||
doClose: function(aResult) {
|
||||
window.removeEventListener("resize", this, false);
|
||||
window.removeEventListener("deviceorientation", this, false);
|
||||
let dialog = document.getElementById("capturepicker-dialog");
|
||||
dialog.arguments.result = aResult;
|
||||
if (aResult)
|
||||
dialog.arguments.path = this.saveFrame();
|
||||
document.getElementById("capturepicker-video").setAttribute("src", "");
|
||||
dialog.close();
|
||||
},
|
||||
|
||||
saveFrame: function() {
|
||||
let Cc = Components.classes;
|
||||
let Ci = Components.interfaces;
|
||||
Components.utils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
let width = 320;
|
||||
let height = 240;
|
||||
let rotation = 0;
|
||||
|
||||
if (window.innerWidth < window.innerHeight) {
|
||||
width = 240;
|
||||
height = 320;
|
||||
if (this._lastOrientationEvent.beta > 0)
|
||||
rotation = Math.PI / 2;
|
||||
else
|
||||
rotation = -Math.PI / 2;
|
||||
}
|
||||
else {
|
||||
if (this._lastOrientationEvent.gamma > 0)
|
||||
rotation = Math.PI;
|
||||
}
|
||||
|
||||
let canvas = document.createElementNS("http://www.w3.org/1999/xhtml", "canvas");
|
||||
canvas.width = width;
|
||||
canvas.height = height;
|
||||
let ctx = canvas.getContext("2d");
|
||||
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||||
//ctx.save();
|
||||
if (rotation != 0) {
|
||||
if (rotation == Math.PI / 2)
|
||||
ctx.translate(width, 0);
|
||||
else if (rotation == -Math.PI / 2)
|
||||
ctx.translate(-width, 0);
|
||||
else
|
||||
ctx.translate(width, height);
|
||||
ctx.rotate(rotation);
|
||||
}
|
||||
ctx.drawImage(document.getElementById("capturepicker-video"), 0, 0, 320, 240);
|
||||
//ctx.restore();
|
||||
let url = canvas.toDataURL("image/png");
|
||||
|
||||
let tmpDir = Services.dirsvc.get("TmpD", Ci.nsIFile);
|
||||
let file = tmpDir.clone();
|
||||
file.append("capture.png");
|
||||
file.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0600);
|
||||
let persist = Cc["@mozilla.org/embedding/browser/nsWebBrowserPersist;1"].createInstance(Ci.nsIWebBrowserPersist);
|
||||
|
||||
persist.persistFlags = Ci.nsIWebBrowserPersist.PERSIST_FLAGS_REPLACE_EXISTING_FILES | Ci.nsIWebBrowserPersist.PERSIST_FLAGS_AUTODETECT_APPLY_CONVERSION;
|
||||
|
||||
let mDone = false;
|
||||
let mFailed = false;
|
||||
|
||||
let progressListener = {
|
||||
onProgressChange: function() {
|
||||
/* Ignore progress callback */
|
||||
},
|
||||
onStateChange: function(aProgress, aRequest, aStateFlag, aStatus) {
|
||||
if (aStateFlag & Ci.nsIWebProgressListener.STATE_STOP) {
|
||||
mDone = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
persist.progressListener = progressListener;
|
||||
|
||||
let source = Services.io.newURI(url, "UTF8", null);;
|
||||
persist.saveURI(source, null, null, null, null, file);
|
||||
|
||||
// don't wait more than 3 seconds for a successful save
|
||||
window.setTimeout(function() {
|
||||
mDone = true;
|
||||
mFailed = true;
|
||||
}, 3000);
|
||||
|
||||
while (!mDone)
|
||||
Services.tm.currentThread.processNextEvent(true);
|
||||
|
||||
return (mFailed ? null : file.path);
|
||||
}
|
||||
}
|
35
mobile/chrome/content/CaptureDialog.xul
Normal file
35
mobile/chrome/content/CaptureDialog.xul
Normal file
@ -0,0 +1,35 @@
|
||||
<?xml version="1.0"?>
|
||||
<!DOCTYPE dialog SYSTEM "chrome://browser/locale/prompt.dtd">
|
||||
<dialog id="capturepicker-dialog"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
onload="document.getElementById('capturepicker-dialog').CaptureDialog.init()"
|
||||
script="chrome://browser/content/CaptureDialog.js">
|
||||
|
||||
<keyset>
|
||||
<key keycode="VK_RETURN" command="cmd_ok"/>
|
||||
<key keycode="VK_ESCAPE" command="cmd_cancel"/>
|
||||
</keyset>
|
||||
|
||||
<commandset>
|
||||
<command id="cmd_ok" oncommand="document.getElementById('capturepicker-dialog').CaptureDialog.capture();"/>
|
||||
<command id="cmd_cancel" oncommand="document.getElementById('capturepicker-dialog').CaptureDialog.cancel();"/>
|
||||
</commandset>
|
||||
|
||||
<vbox class="prompt-header" flex="1">
|
||||
<description id="capturepicker-title" class="prompt-title" crop="center" flex="1"/>
|
||||
<separator id="capturepicker-separator" class="prompt-line"/>
|
||||
<hbox flex="1" pack="center">
|
||||
<vbox id="capturepicker-container" pack="center">
|
||||
<video xmlns="http://www.w3.org/1999/xhtml" id="capturepicker-video"
|
||||
width="320" height="240"
|
||||
src="moz-device:?width=320&height=240&type=video/x-raw-yuv"
|
||||
autoplay="true"> </video>
|
||||
</vbox>
|
||||
</hbox>
|
||||
</vbox>
|
||||
|
||||
<hbox id="capturepicker-buttons-box" class="prompt-buttons">
|
||||
<button class="prompt-button" label="&ok.label;" command="cmd_ok"/>
|
||||
<button class="prompt-button" label="&cancel.label;" command="cmd_cancel"/>
|
||||
</hbox>
|
||||
</dialog>
|
20
mobile/chrome/content/CapturePickerUI.js
Normal file
20
mobile/chrome/content/CapturePickerUI.js
Normal file
@ -0,0 +1,20 @@
|
||||
var CapturePickerUI = {
|
||||
init: function() {
|
||||
this.messageManager = Cc["@mozilla.org/parentprocessmessagemanager;1"].getService(Ci.nsIFrameMessageManager);
|
||||
this.messageManager.addMessageListener("CapturePicker:Show", this);
|
||||
},
|
||||
|
||||
receiveMessage: function(aMessage) {
|
||||
switch (aMessage.name) {
|
||||
case "CapturePicker:Show":
|
||||
let params = { result: true };
|
||||
let dialog = importDialog(null, "chrome://browser/content/CaptureDialog.xul", params);
|
||||
document.getElementById("capturepicker-title").appendChild(document.createTextNode(aMessage.json.title));
|
||||
dialog.waitForClose();
|
||||
return { value: params.result, path: params.path };
|
||||
break;
|
||||
}
|
||||
// prevents warning from the script loader
|
||||
return null;
|
||||
}
|
||||
};
|
@ -114,7 +114,8 @@ XPCOMUtils.defineLazyGetter(this, "CommonUI", function() {
|
||||
["WeaveGlue", "chrome://browser/content/sync.js"],
|
||||
#endif
|
||||
["WebappsUI", "chrome://browser/content/WebappsUI.js"],
|
||||
["SSLExceptions", "chrome://browser/content/exceptions.js"]
|
||||
["SSLExceptions", "chrome://browser/content/exceptions.js"],
|
||||
["CapturePickerUI", "chrome://browser/content/CapturePickerUI.js"]
|
||||
].forEach(function (aScript) {
|
||||
let [name, script] = aScript;
|
||||
XPCOMUtils.defineLazyGetter(window, name, function() {
|
||||
|
@ -491,6 +491,7 @@ var BrowserUI = {
|
||||
FullScreenVideo.init();
|
||||
NewTabPopup.init();
|
||||
WebappsUI.init();
|
||||
CapturePickerUI.init();
|
||||
|
||||
// If some add-ons were disabled during during an application update, alert user
|
||||
let addonIDs = AddonManager.getStartupChanges("disabled");
|
||||
|
@ -80,6 +80,9 @@ chrome.jar:
|
||||
content/fullscreen-video.js (content/fullscreen-video.js)
|
||||
content/fullscreen-video.xhtml (content/fullscreen-video.xhtml)
|
||||
content/netError.xhtml (content/netError.xhtml)
|
||||
|
||||
content/CapturePickerUI.js (content/CapturePickerUI.js)
|
||||
content/CaptureDialog.js (content/CaptureDialog.js)
|
||||
content/CaptureDialog.xul (content/CaptureDialog.xul)
|
||||
|
||||
% override chrome://global/content/config.xul chrome://browser/content/config.xul
|
||||
% override chrome://global/content/netError.xhtml chrome://browser/content/netError.xhtml
|
||||
|
118
mobile/components/CapturePicker.js
Normal file
118
mobile/components/CapturePicker.js
Normal file
@ -0,0 +1,118 @@
|
||||
/* -*- Mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil; -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (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.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is CapturePicker.js
|
||||
*
|
||||
* The Initial Developer of the Original Code is Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Kyle Huey <me@kylehuey.com>
|
||||
* Fabrice Desré <fabrice@mozilla.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
const Cr = Components.results;
|
||||
const Cu = Components.utils;
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
function CapturePicker() {
|
||||
this.messageManager = Cc["@mozilla.org/childprocessmessagemanager;1"].getService(Ci.nsISyncMessageSender);
|
||||
}
|
||||
|
||||
CapturePicker.prototype = {
|
||||
_file: null,
|
||||
_mode: -1,
|
||||
_result: -1,
|
||||
_shown: false,
|
||||
_title: "",
|
||||
_type: "",
|
||||
_window: null,
|
||||
|
||||
//
|
||||
// nsICapturePicker
|
||||
//
|
||||
init: function(aWindow, aTitle, aMode) {
|
||||
this._window = aWindow;
|
||||
this._title = aTitle;
|
||||
this._mode = aMode;
|
||||
},
|
||||
|
||||
show: function() {
|
||||
if (this._shown)
|
||||
throw Cr.NS_ERROR_UNEXPECTED;
|
||||
|
||||
this._shown = true;
|
||||
|
||||
let res = this.messageManager.sendSyncMessage("CapturePicker:Show", { title: this._title, mode: this._mode, type: this._type })[0];
|
||||
if (res.value)
|
||||
this._file = res.path;
|
||||
|
||||
return (res.value ? Ci.nsICapturePicker.RETURN_OK : Ci.nsICapturePicker.RETURN_CANCEL);
|
||||
},
|
||||
|
||||
modeMayBeAvailable: function(aMode) {
|
||||
if (aMode != Ci.nsICapturePicker.MODE_STILL)
|
||||
return false;
|
||||
return true;
|
||||
},
|
||||
|
||||
get file() {
|
||||
if (this._file) {
|
||||
let file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsILocalFile);
|
||||
file.initWithPath(this._file);
|
||||
let utils = this._window.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils);
|
||||
return utils.wrapDOMFile(file);
|
||||
} else {
|
||||
throw Cr.NS_ERROR_FAILURE;
|
||||
}
|
||||
},
|
||||
|
||||
get type() {
|
||||
return this._type;
|
||||
},
|
||||
|
||||
set type(aNewType) {
|
||||
if (this._shown)
|
||||
throw Cr.NS_ERROR_UNEXPECTED;
|
||||
else
|
||||
this._type = aNewType;
|
||||
},
|
||||
|
||||
// QI
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsICapturePicker]),
|
||||
|
||||
// XPCOMUtils factory
|
||||
classID: Components.ID("{cb5a47f0-b58c-4fc3-b61a-358ee95f8238}"),
|
||||
};
|
||||
|
||||
var components = [ CapturePicker ];
|
||||
const NSGetFactory = XPCOMUtils.generateNSGetFactory(components);
|
@ -75,6 +75,7 @@ EXTRA_COMPONENTS = \
|
||||
LoginManager.js \
|
||||
LoginManagerPrompter.js \
|
||||
BlocklistPrompt.js \
|
||||
CapturePicker.js \
|
||||
$(NULL)
|
||||
|
||||
ifdef MOZ_SAFE_BROWSING
|
||||
|
@ -120,3 +120,8 @@ category app-startup SafeBrowsing service,@mozilla.org/safebrowsing/application;
|
||||
component {88b3eb21-d072-4e3b-886d-f89d8c49fe59} UpdatePrompt.js
|
||||
contract @mozilla.org/updates/update-prompt;1 {88b3eb21-d072-4e3b-886d-f89d8c49fe59}
|
||||
#endif
|
||||
|
||||
# CapturePicker.js
|
||||
component {cb5a47f0-b58c-4fc3-b61a-358ee95f8238} CapturePicker.js
|
||||
contract @mozilla.org/capturepicker;1 {cb5a47f0-b58c-4fc3-b61a-358ee95f8238}
|
||||
|
||||
|
@ -613,5 +613,6 @@ bin/components/@DLL_PREFIX@nkgnomevfs@DLL_SUFFIX@
|
||||
@BINPATH@/components/UpdatePrompt.js
|
||||
#endif
|
||||
@BINPATH@/components/XPIDialogService.js
|
||||
@BINPATH@/components/CapturePicker.js
|
||||
@BINPATH@/components/browsercomps.xpt
|
||||
@BINPATH@/extensions/feedback@mobile.mozilla.org.xpi
|
||||
|
@ -1617,4 +1617,18 @@ setting {
|
||||
}
|
||||
}
|
||||
|
||||
/* Capture picker ------------------------------------------------------------- */
|
||||
|
||||
#capturepicker-video {
|
||||
border: @border_width_tiny@ solid white;
|
||||
}
|
||||
|
||||
#capturepicker-container {
|
||||
margin: @margin_normal@;
|
||||
}
|
||||
|
||||
#capturepicker-container.vertical {
|
||||
height: 330px;
|
||||
}
|
||||
|
||||
%include tablet.css
|
||||
|
@ -1596,4 +1596,18 @@ setting:hover:active {
|
||||
list-style-image: url("chrome://browser/skin/images/handle-end.png");
|
||||
}
|
||||
|
||||
/* Capture picker ------------------------------------------------------------- */
|
||||
|
||||
#capturepicker-video {
|
||||
border: @border_width_tiny@ solid white;
|
||||
}
|
||||
|
||||
#capturepicker-container {
|
||||
margin: @margin_normal@;
|
||||
}
|
||||
|
||||
#capturepicker-container.vertical {
|
||||
height: 330px;
|
||||
}
|
||||
|
||||
%include ../tablet.css
|
||||
|
@ -1997,4 +1997,18 @@ setting {
|
||||
-moz-padding-start: @padding_large@;
|
||||
}
|
||||
|
||||
/* Capture picker ------------------------------------------------------------- */
|
||||
|
||||
#capturepicker-video {
|
||||
border: @border_width_tiny@ solid white;
|
||||
}
|
||||
|
||||
#capturepicker-container {
|
||||
margin: @margin_normal@;
|
||||
}
|
||||
|
||||
#capturepicker-container.vertical {
|
||||
height: 330px;
|
||||
}
|
||||
|
||||
%include ../tablet.css
|
||||
|
Loading…
Reference in New Issue
Block a user