mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Merge m-c to m-i
This commit is contained in:
commit
7c24bbe9a8
@ -16,7 +16,7 @@
|
|||||||
<ShortName>Google</ShortName>
|
<ShortName>Google</ShortName>
|
||||||
<Description>Google Search</Description>
|
<Description>Google Search</Description>
|
||||||
<InputEncoding>UTF-8</InputEncoding>
|
<InputEncoding>UTF-8</InputEncoding>
|
||||||
<Image width="16" height="16">data:image/png;base64,AAABAAEAEBAAAAEAGABoAwAAFgAAACgAAAAQAAAAIAAAAAEAGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADs9Pt8xetPtu9FsfFNtu%2BTzvb2%2B%2Fne4dFJeBw0egA%2FfAJAfAA8ewBBegAAAAD%2B%2FPtft98Mp%2BwWsfAVsvEbs%2FQeqvF8xO7%2F%2F%2F63yqkxdgM7gwE%2FggM%2BfQA%2BegBDeQDe7PIbotgQufcMufEPtfIPsvAbs%2FQvq%2Bfz%2Bf%2F%2B%2B%2FZKhR05hgBBhQI8hgBAgAI9ewD0%2B%2Fg3pswAtO8Cxf4Kw%2FsJvvYAqupKsNv%2B%2Fv7%2F%2FP5VkSU0iQA7jQA9hgBDgQU%2BfQH%2F%2Ff%2FQ6fM4sM4KsN8AteMCruIqqdbZ7PH8%2Fv%2Fg6Nc%2Fhg05kAA8jAM9iQI%2BhQA%2BgQDQu6b97uv%2F%2F%2F7V8Pqw3eiWz97q8%2Ff%2F%2F%2F%2F7%2FPptpkkqjQE4kwA7kAA5iwI8iAA8hQCOSSKdXjiyflbAkG7u2s%2F%2B%2F%2F39%2F%2F7r8utrqEYtjQE8lgA7kwA7kwA9jwA9igA9hACiWSekVRyeSgiYSBHx6N%2F%2B%2Fv7k7OFRmiYtlAA5lwI7lwI4lAA7kgI9jwE9iwI4iQCoVhWcTxCmb0K%2BooT8%2Fv%2F7%2F%2F%2FJ2r8fdwI1mwA3mQA3mgA8lAE8lAE4jwA9iwE%2BhwGfXifWvqz%2B%2Ff%2F58u%2Fev6Dt4tr%2B%2F%2F2ZuIUsggA7mgM6mAM3lgA5lgA6kQE%2FkwBChwHt4dv%2F%2F%2F728ei1bCi7VAC5XQ7kz7n%2F%2F%2F6bsZkgcB03lQA9lgM7kwA2iQktZToPK4r9%2F%2F%2F9%2F%2F%2FSqYK5UwDKZAS9WALIkFn%2B%2F%2F3%2F%2BP8oKccGGcIRJrERILYFEMwAAuEAAdX%2F%2Ff7%2F%2FP%2B%2BfDvGXQLIZgLEWgLOjlf7%2F%2F%2F%2F%2F%2F9QU90EAPQAAf8DAP0AAfMAAOUDAtr%2F%2F%2F%2F7%2B%2Fu2bCTIYwDPZgDBWQDSr4P%2F%2Fv%2F%2F%2FP5GRuABAPkAA%2FwBAfkDAPAAAesAAN%2F%2F%2B%2Fz%2F%2F%2F64g1C5VwDMYwK8Yg7y5tz8%2Fv%2FV1PYKDOcAAP0DAf4AAf0AAfYEAOwAAuAAAAD%2F%2FPvi28ymXyChTATRrIb8%2F%2F3v8fk6P8MAAdUCAvoAAP0CAP0AAfYAAO4AAACAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAQAA</Image>
|
<Image width="16" height="16">data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABUUlEQVR42pWTzUsCYRCH9y9zu3SooCCkjhIRRLeIykXokiWCJ7PvDpZRlz6si1lIQZ3SQxQdOhREpgSm0JeQvfu0+i6I7LKLh4F5h5nnnRl+o6jTdHn8omAYbVqhXqvYFXcEBKFDwcoZZB8B4LkEB9cwGGmFKHb01A1EU9JXzfdvDYZi1lwLwBcVAIwsNWPesIwls7gDtB2Z7N9ujVe+IX2LO2AgItB1OL9vJqsmILDrOoK02IkBAdYy4FsQJC5h+VQCHQDWTqYSgo8fuHuRxS4Ae3stQ7UGE5ttAHqCUgfxC7m4ryrowOyeO6CxqHwZxtYFqtYc5+kNan/gDTsAeueEIRj7n/rmRQMwueUAGF0VAAT3rQBTC0Y3DoDOGbm00icML4oWHYSTgo0MFqjlmPpDgqMcFCuQf4erBzjOwXjcriu9qHg0uutO2+es6fl67T9ptebvFRjBVgAAAABJRU5ErkJggg==</Image>
|
||||||
<Url type="application/x-suggestions+json" method="GET" template="https://www.google.com/complete/search?client=firefox&q={searchTerms}"/>
|
<Url type="application/x-suggestions+json" method="GET" template="https://www.google.com/complete/search?client=firefox&q={searchTerms}"/>
|
||||||
<Url type="text/html" method="GET" template="https://www.google.com/search">
|
<Url type="text/html" method="GET" template="https://www.google.com/search">
|
||||||
#expand __GOOGLE_PARAMS__
|
#expand __GOOGLE_PARAMS__
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
|
||||||
dnl -*- Mode: Autoconf; tab-width: 4; indent-tabs-mode: nil; -*-
|
dnl -*- Mode: Autoconf; tab-width: 4; indent-tabs-mode: nil; -*-
|
||||||
dnl vi: set tabstop=4 shiftwidth=4 expandtab syntax=m4:
|
dnl vi: set tabstop=4 shiftwidth=4 expandtab syntax=m4:
|
||||||
dnl This Source Code Form is subject to the terms of the Mozilla Public
|
dnl This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
@ -197,7 +198,7 @@ if test -n "$gonkdir" ; then
|
|||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
CPPFLAGS="-DANDROID -isystem $gonkdir/bionic/libc/$ARCH_DIR/include -isystem $gonkdir/bionic/libc/include/ -isystem $gonkdir/bionic/libc/kernel/common -isystem $gonkdir/bionic/libc/kernel/$ARCH_DIR -isystem $gonkdir/bionic/libm/include -I$gonkdir/frameworks/base/opengl/include -I$gonkdir/frameworks/base/native/include -I$gonkdir/hardware/libhardware/include -I$gonkdir/hardware/libhardware_legacy/include -I$gonkdir/system -I$gonkdir/system/core/include -isystem $gonkdir/bionic -I$gonkdir/frameworks/base/include -I$gonkdir/external/dbus -I$gonkdir/external/bluetooth/bluez/lib $CPPFLAGS -I$gonkdir/frameworks/base/services/sensorservice -I$gonkdir/frameworks/base/services/camera -I$gonkdir/system/media/wilhelm/include"
|
CPPFLAGS="-DANDROID -isystem $gonkdir/bionic/libc/$ARCH_DIR/include -isystem $gonkdir/bionic/libc/include/ -isystem $gonkdir/bionic/libc/kernel/common -isystem $gonkdir/bionic/libc/kernel/$ARCH_DIR -isystem $gonkdir/bionic/libm/include -I$gonkdir/frameworks/base/opengl/include -I$gonkdir/frameworks/base/native/include -I$gonkdir/hardware/libhardware/include -I$gonkdir/hardware/libhardware_legacy/include -I$gonkdir/system -I$gonkdir/system/core/include -isystem $gonkdir/bionic -I$gonkdir/frameworks/base/include -I$gonkdir/external/dbus -I$gonkdir/external/bluetooth/bluez/lib $CPPFLAGS -I$gonkdir/frameworks/base/services/sensorservice -I$gonkdir/frameworks/base/services/camera -I$gonkdir/system/media/wilhelm/include -I$gonkdir/frameworks/base/include/media/stagefright -I$gonkdir/frameworks/base/include/media/stagefright/openmax -I$gonkdir/frameworks/base/media/libstagefright/rtsp -I$gonkdir/frameworks/base/media/libstagefright/include -I$gonkdir/dalvik/libnativehelper/include/nativehelper"
|
||||||
CFLAGS="-mandroid -fno-short-enums -fno-exceptions $CFLAGS"
|
CFLAGS="-mandroid -fno-short-enums -fno-exceptions $CFLAGS"
|
||||||
CXXFLAGS="-mandroid -fno-short-enums -fno-exceptions -Wno-psabi $CXXFLAGS $STLPORT_CPPFLAGS"
|
CXXFLAGS="-mandroid -fno-short-enums -fno-exceptions -Wno-psabi $CXXFLAGS $STLPORT_CPPFLAGS"
|
||||||
dnl Add -llog by default, since we use it all over the place.
|
dnl Add -llog by default, since we use it all over the place.
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
<body onpopstate='opener.page1Popstate();' onload='opener.page1Load();'
|
<body onpopstate='opener.page1Popstate();' onload='opener.page1Load();'
|
||||||
onpageshow='opener.page1PageShow();'>
|
onpageshow='opener.page1PageShow();'>
|
||||||
|
|
||||||
<div style='height:300%' id='div1'>This is a very tall div.</div>
|
<div style='height:10000px' id='div1'>This is a very tall div.</div>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
@ -206,42 +206,20 @@ const ContentPanning = {
|
|||||||
let metrics = data.json;
|
let metrics = data.json;
|
||||||
let displayPort = metrics.displayPort;
|
let displayPort = metrics.displayPort;
|
||||||
|
|
||||||
let screenWidth = metrics.screenSize.width;
|
let compositionWidth = metrics.compositionBounds.width;
|
||||||
let screenHeight = metrics.screenSize.height;
|
let compositionHeight = metrics.compositionBounds.height;
|
||||||
|
|
||||||
let x = metrics.x;
|
let x = metrics.x;
|
||||||
let y = metrics.y;
|
let y = metrics.y;
|
||||||
|
|
||||||
this._zoom = metrics.zoom;
|
this._zoom = metrics.zoom;
|
||||||
this._viewport = new Rect(x, y,
|
this._viewport = new Rect(x, y,
|
||||||
screenWidth / metrics.zoom,
|
compositionWidth / metrics.zoom,
|
||||||
screenHeight / metrics.zoom);
|
compositionHeight / metrics.zoom);
|
||||||
this._cssPageRect = new Rect(metrics.cssPageRect.x,
|
this._cssPageRect = new Rect(metrics.cssPageRect.x,
|
||||||
metrics.cssPageRect.y,
|
metrics.cssPageRect.y,
|
||||||
metrics.cssPageRect.width,
|
metrics.cssPageRect.width,
|
||||||
metrics.cssPageRect.height);
|
metrics.cssPageRect.height);
|
||||||
|
|
||||||
let cwu = content.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils);
|
|
||||||
if (this._screenWidth != screenWidth || this._screenHeight != screenHeight) {
|
|
||||||
cwu.setCSSViewport(screenWidth, screenHeight);
|
|
||||||
this._screenWidth = screenWidth;
|
|
||||||
this._screenHeight = screenHeight;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set scroll position
|
|
||||||
cwu.setScrollPositionClampingScrollPortSize(
|
|
||||||
screenWidth / metrics.zoom, screenHeight / metrics.zoom);
|
|
||||||
content.scrollTo(x, y);
|
|
||||||
cwu.setResolution(displayPort.resolution, displayPort.resolution);
|
|
||||||
|
|
||||||
let element = null;
|
|
||||||
if (content.document && (element = content.document.documentElement)) {
|
|
||||||
cwu.setDisplayPortForElement(displayPort.left,
|
|
||||||
displayPort.top,
|
|
||||||
displayPort.width,
|
|
||||||
displayPort.height,
|
|
||||||
element);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_recvDoubleTap: function(data) {
|
_recvDoubleTap: function(data) {
|
||||||
@ -272,7 +250,7 @@ const ContentPanning = {
|
|||||||
|
|
||||||
let cssPageRect = this._cssPageRect;
|
let cssPageRect = this._cssPageRect;
|
||||||
let viewport = this._viewport;
|
let viewport = this._viewport;
|
||||||
let bRect = new Rect(Math.max(cssPageRect.left, rect.x - margin),
|
let bRect = new Rect(Math.max(cssPageRect.x, rect.x - margin),
|
||||||
rect.y,
|
rect.y,
|
||||||
rect.w + 2 * margin,
|
rect.w + 2 * margin,
|
||||||
rect.h);
|
rect.h);
|
||||||
|
179
dom/camera/AudioParameter.cpp
Normal file
179
dom/camera/AudioParameter.cpp
Normal file
@ -0,0 +1,179 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2006-2011 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define LOG_TAG "AudioParameter"
|
||||||
|
//#define LOG_NDEBUG 0
|
||||||
|
|
||||||
|
#include <utils/Log.h>
|
||||||
|
|
||||||
|
#include <media/AudioParameter.h>
|
||||||
|
|
||||||
|
namespace android {
|
||||||
|
|
||||||
|
const char *AudioParameter::keyRouting = "routing";
|
||||||
|
const char *AudioParameter::keySamplingRate = "sampling_rate";
|
||||||
|
const char *AudioParameter::keyFormat = "format";
|
||||||
|
const char *AudioParameter::keyChannels = "channels";
|
||||||
|
const char *AudioParameter::keyFrameCount = "frame_count";
|
||||||
|
const char *AudioParameter::keyInputSource = "input_source";
|
||||||
|
|
||||||
|
AudioParameter::AudioParameter(const String8& keyValuePairs)
|
||||||
|
{
|
||||||
|
char *str = new char[keyValuePairs.length()+1];
|
||||||
|
mKeyValuePairs = keyValuePairs;
|
||||||
|
|
||||||
|
strcpy(str, keyValuePairs.string());
|
||||||
|
char *pair = strtok(str, ";");
|
||||||
|
while (pair != NULL) {
|
||||||
|
if (strlen(pair) != 0) {
|
||||||
|
size_t eqIdx = strcspn(pair, "=");
|
||||||
|
String8 key = String8(pair, eqIdx);
|
||||||
|
String8 value;
|
||||||
|
if (eqIdx == strlen(pair)) {
|
||||||
|
value = String8("");
|
||||||
|
} else {
|
||||||
|
value = String8(pair + eqIdx + 1);
|
||||||
|
}
|
||||||
|
if (mParameters.indexOfKey(key) < 0) {
|
||||||
|
mParameters.add(key, value);
|
||||||
|
} else {
|
||||||
|
mParameters.replaceValueFor(key, value);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
LOGV("AudioParameter() cstor empty key value pair");
|
||||||
|
}
|
||||||
|
pair = strtok(NULL, ";");
|
||||||
|
}
|
||||||
|
|
||||||
|
delete[] str;
|
||||||
|
}
|
||||||
|
|
||||||
|
AudioParameter::~AudioParameter()
|
||||||
|
{
|
||||||
|
mParameters.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
String8 AudioParameter::toString()
|
||||||
|
{
|
||||||
|
String8 str = String8("");
|
||||||
|
|
||||||
|
size_t size = mParameters.size();
|
||||||
|
for (size_t i = 0; i < size; i++) {
|
||||||
|
str += mParameters.keyAt(i);
|
||||||
|
str += "=";
|
||||||
|
str += mParameters.valueAt(i);
|
||||||
|
if (i < (size - 1)) str += ";";
|
||||||
|
}
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
status_t AudioParameter::add(const String8& key, const String8& value)
|
||||||
|
{
|
||||||
|
if (mParameters.indexOfKey(key) < 0) {
|
||||||
|
mParameters.add(key, value);
|
||||||
|
return NO_ERROR;
|
||||||
|
} else {
|
||||||
|
mParameters.replaceValueFor(key, value);
|
||||||
|
return ALREADY_EXISTS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
status_t AudioParameter::addInt(const String8& key, const int value)
|
||||||
|
{
|
||||||
|
char str[12];
|
||||||
|
if (snprintf(str, 12, "%d", value) > 0) {
|
||||||
|
String8 str8 = String8(str);
|
||||||
|
return add(key, str8);
|
||||||
|
} else {
|
||||||
|
return BAD_VALUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
status_t AudioParameter::addFloat(const String8& key, const float value)
|
||||||
|
{
|
||||||
|
char str[23];
|
||||||
|
if (snprintf(str, 23, "%.10f", value) > 0) {
|
||||||
|
String8 str8 = String8(str);
|
||||||
|
return add(key, str8);
|
||||||
|
} else {
|
||||||
|
return BAD_VALUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
status_t AudioParameter::remove(const String8& key)
|
||||||
|
{
|
||||||
|
if (mParameters.indexOfKey(key) >= 0) {
|
||||||
|
mParameters.removeItem(key);
|
||||||
|
return NO_ERROR;
|
||||||
|
} else {
|
||||||
|
return BAD_VALUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
status_t AudioParameter::get(const String8& key, String8& value)
|
||||||
|
{
|
||||||
|
if (mParameters.indexOfKey(key) >= 0) {
|
||||||
|
value = mParameters.valueFor(key);
|
||||||
|
return NO_ERROR;
|
||||||
|
} else {
|
||||||
|
return BAD_VALUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
status_t AudioParameter::getInt(const String8& key, int& value)
|
||||||
|
{
|
||||||
|
String8 str8;
|
||||||
|
status_t result = get(key, str8);
|
||||||
|
value = 0;
|
||||||
|
if (result == NO_ERROR) {
|
||||||
|
int val;
|
||||||
|
if (sscanf(str8.string(), "%d", &val) == 1) {
|
||||||
|
value = val;
|
||||||
|
} else {
|
||||||
|
result = INVALID_OPERATION;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
status_t AudioParameter::getFloat(const String8& key, float& value)
|
||||||
|
{
|
||||||
|
String8 str8;
|
||||||
|
status_t result = get(key, str8);
|
||||||
|
value = 0;
|
||||||
|
if (result == NO_ERROR) {
|
||||||
|
float val;
|
||||||
|
if (sscanf(str8.string(), "%f", &val) == 1) {
|
||||||
|
value = val;
|
||||||
|
} else {
|
||||||
|
result = INVALID_OPERATION;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
status_t AudioParameter::getAt(size_t index, String8& key, String8& value)
|
||||||
|
{
|
||||||
|
if (mParameters.size() > index) {
|
||||||
|
key = mParameters.keyAt(index);
|
||||||
|
value = mParameters.valueAt(index);
|
||||||
|
return NO_ERROR;
|
||||||
|
} else {
|
||||||
|
return BAD_VALUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}; // namespace android
|
@ -196,9 +196,9 @@ CameraControlImpl::TakePicture(CameraSize aSize, int32_t aRotation, const nsAStr
|
|||||||
}
|
}
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
CameraControlImpl::StartRecording(CameraSize aSize, nsICameraStartRecordingCallback* onSuccess, nsICameraErrorCallback* onError)
|
CameraControlImpl::StartRecording(nsIDOMDeviceStorage* aStorageArea, const nsAString& aFilename, nsICameraStartRecordingCallback* onSuccess, nsICameraErrorCallback* onError)
|
||||||
{
|
{
|
||||||
nsCOMPtr<nsIRunnable> startRecordingTask = new StartRecordingTask(this, aSize, onSuccess, onError);
|
nsCOMPtr<nsIRunnable> startRecordingTask = new StartRecordingTask(this, aStorageArea, aFilename, onSuccess, onError);
|
||||||
return mCameraThread->Dispatch(startRecordingTask, NS_DISPATCH_NORMAL);
|
return mCameraThread->Dispatch(startRecordingTask, NS_DISPATCH_NORMAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -223,6 +223,13 @@ CameraControlImpl::StopPreview()
|
|||||||
mCameraThread->Dispatch(stopPreviewTask, NS_DISPATCH_NORMAL);
|
mCameraThread->Dispatch(stopPreviewTask, NS_DISPATCH_NORMAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nsresult
|
||||||
|
CameraControlImpl::GetPreviewStreamVideoMode(CameraRecordingOptions* aOptions, nsICameraPreviewStreamCallback* onSuccess, nsICameraErrorCallback* onError)
|
||||||
|
{
|
||||||
|
nsCOMPtr<nsIRunnable> getPreviewStreamVideoModeTask = new GetPreviewStreamVideoModeTask(this, *aOptions, onSuccess, onError);
|
||||||
|
return mCameraThread->Dispatch(getPreviewStreamVideoModeTask, NS_DISPATCH_NORMAL);
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
CameraControlImpl::ReceiveFrame(void* aBuffer, ImageFormat aFormat, FrameBuilder aBuilder)
|
CameraControlImpl::ReceiveFrame(void* aBuffer, ImageFormat aFormat, FrameBuilder aBuilder)
|
||||||
{
|
{
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
#include "nsCOMPtr.h"
|
#include "nsCOMPtr.h"
|
||||||
#include "nsDOMFile.h"
|
#include "nsDOMFile.h"
|
||||||
#include "DictionaryHelpers.h"
|
#include "DictionaryHelpers.h"
|
||||||
|
#include "nsIDOMDeviceStorage.h"
|
||||||
#include "nsIDOMCameraManager.h"
|
#include "nsIDOMCameraManager.h"
|
||||||
#include "ICameraControl.h"
|
#include "ICameraControl.h"
|
||||||
#include "CameraCommon.h"
|
#include "CameraCommon.h"
|
||||||
@ -25,6 +26,7 @@ class StartRecordingTask;
|
|||||||
class StopRecordingTask;
|
class StopRecordingTask;
|
||||||
class SetParameterTask;
|
class SetParameterTask;
|
||||||
class GetParameterTask;
|
class GetParameterTask;
|
||||||
|
class GetPreviewStreamVideoModeTask;
|
||||||
|
|
||||||
class DOMCameraPreview;
|
class DOMCameraPreview;
|
||||||
|
|
||||||
@ -39,6 +41,7 @@ class CameraControlImpl : public ICameraControl
|
|||||||
friend class StopRecordingTask;
|
friend class StopRecordingTask;
|
||||||
friend class SetParameterTask;
|
friend class SetParameterTask;
|
||||||
friend class GetParameterTask;
|
friend class GetParameterTask;
|
||||||
|
friend class GetPreviewStreamVideoModeTask;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CameraControlImpl(uint32_t aCameraId, nsIThread* aCameraThread)
|
CameraControlImpl(uint32_t aCameraId, nsIThread* aCameraThread)
|
||||||
@ -64,8 +67,9 @@ public:
|
|||||||
void StopPreview();
|
void StopPreview();
|
||||||
nsresult AutoFocus(nsICameraAutoFocusCallback* onSuccess, nsICameraErrorCallback* onError);
|
nsresult AutoFocus(nsICameraAutoFocusCallback* onSuccess, nsICameraErrorCallback* onError);
|
||||||
nsresult TakePicture(CameraSize aSize, int32_t aRotation, const nsAString& aFileFormat, CameraPosition aPosition, nsICameraTakePictureCallback* onSuccess, nsICameraErrorCallback* onError);
|
nsresult TakePicture(CameraSize aSize, int32_t aRotation, const nsAString& aFileFormat, CameraPosition aPosition, nsICameraTakePictureCallback* onSuccess, nsICameraErrorCallback* onError);
|
||||||
nsresult StartRecording(CameraSize aSize, nsICameraStartRecordingCallback* onSuccess, nsICameraErrorCallback* onError);
|
nsresult StartRecording(nsIDOMDeviceStorage* aStorageArea, const nsAString& aFilename, nsICameraStartRecordingCallback* onSuccess, nsICameraErrorCallback* onError);
|
||||||
nsresult StopRecording();
|
nsresult StopRecording();
|
||||||
|
nsresult GetPreviewStreamVideoMode(CameraRecordingOptions* aOptions, nsICameraPreviewStreamCallback* onSuccess, nsICameraErrorCallback* onError);
|
||||||
|
|
||||||
nsresult Set(uint32_t aKey, const nsAString& aValue);
|
nsresult Set(uint32_t aKey, const nsAString& aValue);
|
||||||
nsresult Get(uint32_t aKey, nsAString& aValue);
|
nsresult Get(uint32_t aKey, nsAString& aValue);
|
||||||
@ -111,6 +115,7 @@ protected:
|
|||||||
virtual nsresult StopRecordingImpl(StopRecordingTask* aStopRecording) = 0;
|
virtual nsresult StopRecordingImpl(StopRecordingTask* aStopRecording) = 0;
|
||||||
virtual nsresult PushParametersImpl() = 0;
|
virtual nsresult PushParametersImpl() = 0;
|
||||||
virtual nsresult PullParametersImpl() = 0;
|
virtual nsresult PullParametersImpl() = 0;
|
||||||
|
virtual nsresult GetPreviewStreamVideoModeImpl(GetPreviewStreamVideoModeTask* aGetPreviewStreamVideoMode) = 0;
|
||||||
|
|
||||||
uint32_t mCameraId;
|
uint32_t mCameraId;
|
||||||
nsCOMPtr<nsIThread> mCameraThread;
|
nsCOMPtr<nsIThread> mCameraThread;
|
||||||
@ -347,9 +352,8 @@ public:
|
|||||||
class StartRecordingResult : public nsRunnable
|
class StartRecordingResult : public nsRunnable
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
StartRecordingResult(nsIDOMMediaStream* aStream, nsICameraStartRecordingCallback* onSuccess)
|
StartRecordingResult(nsICameraStartRecordingCallback* onSuccess)
|
||||||
: mStream(aStream)
|
: mOnSuccessCb(onSuccess)
|
||||||
, mOnSuccessCb(onSuccess)
|
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
virtual ~StartRecordingResult() { }
|
virtual ~StartRecordingResult() { }
|
||||||
@ -359,13 +363,12 @@ public:
|
|||||||
MOZ_ASSERT(NS_IsMainThread());
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
|
|
||||||
if (mOnSuccessCb) {
|
if (mOnSuccessCb) {
|
||||||
mOnSuccessCb->HandleEvent(mStream);
|
mOnSuccessCb->HandleEvent();
|
||||||
}
|
}
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
nsCOMPtr<nsIDOMMediaStream> mStream;
|
|
||||||
nsCOMPtr<nsICameraStartRecordingCallback> mOnSuccessCb;
|
nsCOMPtr<nsICameraStartRecordingCallback> mOnSuccessCb;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -373,9 +376,10 @@ protected:
|
|||||||
class StartRecordingTask : public nsRunnable
|
class StartRecordingTask : public nsRunnable
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
StartRecordingTask(CameraControlImpl* aCameraControl, CameraSize aSize, nsICameraStartRecordingCallback* onSuccess, nsICameraErrorCallback* onError)
|
StartRecordingTask(CameraControlImpl* aCameraControl, nsIDOMDeviceStorage* aStorageArea, const nsAString& aFilename, nsICameraStartRecordingCallback* onSuccess, nsICameraErrorCallback* onError)
|
||||||
: mSize(aSize)
|
: mCameraControl(aCameraControl)
|
||||||
, mCameraControl(aCameraControl)
|
, mStorageArea(aStorageArea)
|
||||||
|
, mFilename(aFilename)
|
||||||
, mOnSuccessCb(onSuccess)
|
, mOnSuccessCb(onSuccess)
|
||||||
, mOnErrorCb(onError)
|
, mOnErrorCb(onError)
|
||||||
{
|
{
|
||||||
@ -391,17 +395,21 @@ public:
|
|||||||
{
|
{
|
||||||
DOM_CAMERA_LOGT("%s:%d\n", __func__, __LINE__);
|
DOM_CAMERA_LOGT("%s:%d\n", __func__, __LINE__);
|
||||||
nsresult rv = mCameraControl->StartRecordingImpl(this);
|
nsresult rv = mCameraControl->StartRecordingImpl(this);
|
||||||
DOM_CAMERA_LOGT("%s:%d\n", __func__, __LINE__);
|
DOM_CAMERA_LOGT("%s:%d : result %d\n", __func__, __LINE__, rv);
|
||||||
|
|
||||||
if (NS_FAILED(rv) && mOnErrorCb) {
|
if (NS_SUCCEEDED(rv)) {
|
||||||
|
if (mOnSuccessCb) {
|
||||||
|
rv = NS_DispatchToMainThread(new StartRecordingResult(mOnSuccessCb));
|
||||||
|
}
|
||||||
|
} else if (mOnErrorCb) {
|
||||||
rv = NS_DispatchToMainThread(new CameraErrorResult(mOnErrorCb, NS_LITERAL_STRING("FAILURE")));
|
rv = NS_DispatchToMainThread(new CameraErrorResult(mOnErrorCb, NS_LITERAL_STRING("FAILURE")));
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
|
||||||
}
|
}
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
CameraSize mSize;
|
|
||||||
nsRefPtr<CameraControlImpl> mCameraControl;
|
nsRefPtr<CameraControlImpl> mCameraControl;
|
||||||
|
nsCOMPtr<nsIDOMDeviceStorage> mStorageArea;
|
||||||
|
nsString mFilename;
|
||||||
nsCOMPtr<nsICameraStartRecordingCallback> mOnSuccessCb;
|
nsCOMPtr<nsICameraStartRecordingCallback> mOnSuccessCb;
|
||||||
nsCOMPtr<nsICameraErrorCallback> mOnErrorCb;
|
nsCOMPtr<nsICameraErrorCallback> mOnErrorCb;
|
||||||
};
|
};
|
||||||
@ -491,6 +499,67 @@ public:
|
|||||||
nsRefPtr<CameraControlImpl> mCameraControl;
|
nsRefPtr<CameraControlImpl> mCameraControl;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Return the resulting preview stream to JS. Runs on the main thread.
|
||||||
|
class GetPreviewStreamVideoModeResult : public nsRunnable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
GetPreviewStreamVideoModeResult(nsIDOMMediaStream* aStream, nsICameraPreviewStreamCallback* onSuccess)
|
||||||
|
: mStream(aStream)
|
||||||
|
, mOnSuccessCb(onSuccess)
|
||||||
|
{
|
||||||
|
DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ~GetPreviewStreamVideoModeResult()
|
||||||
|
{
|
||||||
|
DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMETHOD Run()
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
|
|
||||||
|
if (mOnSuccessCb) {
|
||||||
|
mOnSuccessCb->HandleEvent(mStream);
|
||||||
|
}
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
nsCOMPtr<nsIDOMMediaStream> mStream;
|
||||||
|
nsCOMPtr<nsICameraPreviewStreamCallback> mOnSuccessCb;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Get the video mode preview stream.
|
||||||
|
class GetPreviewStreamVideoModeTask : public nsRunnable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
GetPreviewStreamVideoModeTask(CameraControlImpl* aCameraControl, CameraRecordingOptions aOptions, nsICameraPreviewStreamCallback* onSuccess, nsICameraErrorCallback* onError)
|
||||||
|
: mCameraControl(aCameraControl)
|
||||||
|
, mOptions(aOptions)
|
||||||
|
, mOnSuccessCb(onSuccess)
|
||||||
|
, mOnErrorCb(onError)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
NS_IMETHOD Run()
|
||||||
|
{
|
||||||
|
DOM_CAMERA_LOGI("%s:%d -- BEFORE IMPL\n", __func__, __LINE__);
|
||||||
|
nsresult rv = mCameraControl->GetPreviewStreamVideoModeImpl(this);
|
||||||
|
DOM_CAMERA_LOGI("%s:%d -- AFTER IMPL : rv = %d\n", __func__, __LINE__, rv);
|
||||||
|
|
||||||
|
if (NS_FAILED(rv) && mOnErrorCb) {
|
||||||
|
rv = NS_DispatchToMainThread(new CameraErrorResult(mOnErrorCb, NS_LITERAL_STRING("FAILURE")));
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
}
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsRefPtr<CameraControlImpl> mCameraControl;
|
||||||
|
CameraRecordingOptions mOptions;
|
||||||
|
nsCOMPtr<nsICameraPreviewStreamCallback> mOnSuccessCb;
|
||||||
|
nsCOMPtr<nsICameraErrorCallback> mOnErrorCb;
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace mozilla
|
} // namespace mozilla
|
||||||
|
|
||||||
#endif // DOM_CAMERA_CAMERACONTROLIMPL_H
|
#endif // DOM_CAMERA_CAMERACONTROLIMPL_H
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
#include "nsThread.h"
|
#include "nsThread.h"
|
||||||
#include "mozilla/Services.h"
|
#include "mozilla/Services.h"
|
||||||
#include "nsIObserverService.h"
|
#include "nsIObserverService.h"
|
||||||
|
#include "nsIDOMDeviceStorage.h"
|
||||||
#include "DOMCameraManager.h"
|
#include "DOMCameraManager.h"
|
||||||
#include "DOMCameraCapabilities.h"
|
#include "DOMCameraCapabilities.h"
|
||||||
#include "DOMCameraControl.h"
|
#include "DOMCameraControl.h"
|
||||||
@ -218,16 +219,12 @@ nsDOMCameraControl::SetOnShutter(nsICameraShutterCallback* aOnShutter)
|
|||||||
return NS_ERROR_NOT_IMPLEMENTED;
|
return NS_ERROR_NOT_IMPLEMENTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* void startRecording (in jsval aOptions, in nsICameraStartRecordingCallback onSuccess, [optional] in nsICameraErrorCallback onError); */
|
/* [implicit_jscontext] void startRecording (in nsIDOMDeviceStorage storageArea, in DOMString filename, in nsICameraStartRecordingCallback onSuccess, [optional] in nsICameraErrorCallback onError); */
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
nsDOMCameraControl::StartRecording(const JS::Value& aOptions, nsICameraStartRecordingCallback* onSuccess, nsICameraErrorCallback* onError, JSContext* cx)
|
nsDOMCameraControl::StartRecording(nsIDOMDeviceStorage* storageArea, const nsAString& filename, nsICameraStartRecordingCallback* onSuccess, nsICameraErrorCallback* onError, JSContext* cx)
|
||||||
{
|
{
|
||||||
NS_ENSURE_TRUE(onSuccess, NS_ERROR_INVALID_ARG);
|
NS_ENSURE_TRUE(onSuccess, NS_ERROR_INVALID_ARG);
|
||||||
|
|
||||||
CameraSize size;
|
|
||||||
nsresult rv = size.Init(cx, &aOptions);
|
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
|
||||||
|
|
||||||
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
|
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
|
||||||
if (!obs) {
|
if (!obs) {
|
||||||
NS_WARNING("Could not get the Observer service for CameraControl::StartRecording.");
|
NS_WARNING("Could not get the Observer service for CameraControl::StartRecording.");
|
||||||
@ -238,7 +235,7 @@ nsDOMCameraControl::StartRecording(const JS::Value& aOptions, nsICameraStartReco
|
|||||||
"recording-device-events",
|
"recording-device-events",
|
||||||
NS_LITERAL_STRING("starting").get());
|
NS_LITERAL_STRING("starting").get());
|
||||||
|
|
||||||
return mCameraControl->StartRecording(size, onSuccess, onError);
|
return mCameraControl->StartRecording(storageArea, filename, onSuccess, onError);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* void stopRecording (); */
|
/* void stopRecording (); */
|
||||||
@ -316,6 +313,19 @@ nsDOMCameraControl::TakePicture(const JS::Value& aOptions, nsICameraTakePictureC
|
|||||||
return mCameraControl->TakePicture(size, options.rotation, options.fileFormat, pos, onSuccess, onError);
|
return mCameraControl->TakePicture(size, options.rotation, options.fileFormat, pos, onSuccess, onError);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* [implicit_jscontext] void GetPreviewStreamVideoMode (in jsval aOptions, in nsICameraPreviewStreamCallback onSuccess, [optional] in nsICameraErrorCallback onError); */
|
||||||
|
NS_IMETHODIMP
|
||||||
|
nsDOMCameraControl::GetPreviewStreamVideoMode(const JS::Value& aOptions, nsICameraPreviewStreamCallback* onSuccess, nsICameraErrorCallback* onError, JSContext* cx)
|
||||||
|
{
|
||||||
|
NS_ENSURE_TRUE(onSuccess, NS_ERROR_INVALID_ARG);
|
||||||
|
|
||||||
|
CameraRecordingOptions options;
|
||||||
|
nsresult rv = options.Init(cx, &aOptions);
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
|
return mCameraControl->GetPreviewStreamVideoMode(&options, onSuccess, onError);
|
||||||
|
}
|
||||||
|
|
||||||
class GetCameraResult : public nsRunnable
|
class GetCameraResult : public nsRunnable
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -15,6 +15,10 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <libgen.h>
|
||||||
#include "base/basictypes.h"
|
#include "base/basictypes.h"
|
||||||
#include "libcameraservice/CameraHardwareInterface.h"
|
#include "libcameraservice/CameraHardwareInterface.h"
|
||||||
#include "camera/CameraParameters.h"
|
#include "camera/CameraParameters.h"
|
||||||
@ -23,6 +27,8 @@
|
|||||||
#include "nsMemory.h"
|
#include "nsMemory.h"
|
||||||
#include "jsapi.h"
|
#include "jsapi.h"
|
||||||
#include "nsThread.h"
|
#include "nsThread.h"
|
||||||
|
#include <media/MediaProfiles.h>
|
||||||
|
#include "nsDirectoryServiceDefs.h" // for NS_GetSpecialDirectory
|
||||||
#include "nsPrintfCString.h"
|
#include "nsPrintfCString.h"
|
||||||
#include "DOMCameraManager.h"
|
#include "DOMCameraManager.h"
|
||||||
#include "GonkCameraHwMgr.h"
|
#include "GonkCameraHwMgr.h"
|
||||||
@ -547,19 +553,27 @@ nsGonkCameraControl::StartPreviewImpl(StartPreviewTask* aStartPreview)
|
|||||||
}
|
}
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
nsGonkCameraControl::StopPreviewImpl(StopPreviewTask* aStopPreview)
|
nsGonkCameraControl::StopPreviewInternal(bool aForced)
|
||||||
{
|
{
|
||||||
DOM_CAMERA_LOGI("%s: stopping preview\n", __func__);
|
DOM_CAMERA_LOGI("%s: stopping preview\n", __func__);
|
||||||
|
|
||||||
// StopPreview() is a synchronous call--it doesn't return
|
// StopPreview() is a synchronous call--it doesn't return
|
||||||
// until the camera preview thread exits.
|
// until the camera preview thread exits.
|
||||||
GonkCameraHardware::StopPreview(mHwHandle);
|
if (mDOMPreview) {
|
||||||
mDOMPreview->Stopped();
|
GonkCameraHardware::StopPreview(mHwHandle);
|
||||||
mDOMPreview = nullptr;
|
mDOMPreview->Stopped(aForced);
|
||||||
|
mDOMPreview = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nsresult
|
||||||
|
nsGonkCameraControl::StopPreviewImpl(StopPreviewTask* aStopPreview)
|
||||||
|
{
|
||||||
|
return StopPreviewInternal();
|
||||||
|
}
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
nsGonkCameraControl::AutoFocusImpl(AutoFocusTask* aAutoFocus)
|
nsGonkCameraControl::AutoFocusImpl(AutoFocusTask* aAutoFocus)
|
||||||
{
|
{
|
||||||
@ -691,13 +705,71 @@ nsGonkCameraControl::PullParametersImpl()
|
|||||||
nsresult
|
nsresult
|
||||||
nsGonkCameraControl::StartRecordingImpl(StartRecordingTask* aStartRecording)
|
nsGonkCameraControl::StartRecordingImpl(StartRecordingTask* aStartRecording)
|
||||||
{
|
{
|
||||||
return NS_ERROR_NOT_IMPLEMENTED;
|
mStartRecordingOnSuccessCb = aStartRecording->mOnSuccessCb;
|
||||||
|
mStartRecordingOnErrorCb = aStartRecording->mOnErrorCb;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* We need to pull in the base path from aStartRecording->mStorageArea
|
||||||
|
* once that feature lands. See bug 795201.
|
||||||
|
*
|
||||||
|
* For now, we just assume /sdcard/Movies.
|
||||||
|
*
|
||||||
|
* Also, the camera app needs to provide the file extension '.3gp' for now.
|
||||||
|
* See bug 795202.
|
||||||
|
*/
|
||||||
|
#if 1
|
||||||
|
nsCOMPtr<nsIFile> filename;
|
||||||
|
aStartRecording->mStorageArea->GetRootDirectory(getter_AddRefs(filename));
|
||||||
|
filename->Append(aStartRecording->mFilename);
|
||||||
|
|
||||||
|
nsAutoCString pathname;
|
||||||
|
filename->GetNativePath(pathname);
|
||||||
|
#else
|
||||||
|
nsAutoCString pathname(NS_LITERAL_CSTRING("/sdcard/Movies/"));
|
||||||
|
nsAutoCString filename(NS_ConvertUTF16toUTF8(aStartRecording->mFilename));
|
||||||
|
|
||||||
|
// Make sure that the file name doesn't contain any directory components.
|
||||||
|
if (strcmp(filename.get(), basename(filename.get())) != 0) {
|
||||||
|
DOM_CAMERA_LOGE("Video filename '%s' is not valid\n", filename.get());
|
||||||
|
return NS_ERROR_INVALID_ARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
pathname.Append(filename);
|
||||||
|
#endif
|
||||||
|
DOM_CAMERA_LOGI("Video pathname is '%s'\n", pathname.get());
|
||||||
|
int fd = open(pathname.get(), O_RDWR | O_CREAT, 0644);
|
||||||
|
if (fd < 0) {
|
||||||
|
DOM_CAMERA_LOGE("Couldn't create file '%s' with error (%d) %s\n", pathname.get(), errno, strerror(errno));
|
||||||
|
return NS_ERROR_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SetupRecording(fd) != NS_OK) {
|
||||||
|
DOM_CAMERA_LOGE("SetupRecording() failed\n");
|
||||||
|
close(fd);
|
||||||
|
return NS_ERROR_FAILURE;
|
||||||
|
}
|
||||||
|
if (mRecorder->start() != OK) {
|
||||||
|
DOM_CAMERA_LOGE("mRecorder->start() failed\n");
|
||||||
|
close(fd);
|
||||||
|
return NS_ERROR_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// dispatch the callback
|
||||||
|
nsCOMPtr<nsIRunnable> startRecordingResult = new StartRecordingResult(mStartRecordingOnSuccessCb);
|
||||||
|
nsresult rv = NS_DispatchToMainThread(startRecordingResult);
|
||||||
|
if (NS_FAILED(rv)) {
|
||||||
|
DOM_CAMERA_LOGE("Failed to dispatch start recording result to main thread (%d)!", rv);
|
||||||
|
}
|
||||||
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
nsGonkCameraControl::StopRecordingImpl(StopRecordingTask* aStopRecording)
|
nsGonkCameraControl::StopRecordingImpl(StopRecordingTask* aStopRecording)
|
||||||
{
|
{
|
||||||
return NS_ERROR_NOT_IMPLEMENTED;
|
mRecorder->stop();
|
||||||
|
delete mRecorder;
|
||||||
|
mRecorder = nullptr;
|
||||||
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -809,6 +881,152 @@ nsGonkCameraControl::SetPreviewSize(uint32_t aWidth, uint32_t aHeight)
|
|||||||
PushParameters();
|
PushParameters();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nsresult
|
||||||
|
nsGonkCameraControl::SetupVideoMode()
|
||||||
|
{
|
||||||
|
// read preferences for camcorder
|
||||||
|
mMediaProfiles = MediaProfiles::getInstance();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Right now default to profile 3, which is 352x288 on Otoro. In the
|
||||||
|
* future, allow the application to select a recording quality and
|
||||||
|
* configuration.
|
||||||
|
*
|
||||||
|
* See bug 795379.
|
||||||
|
*/
|
||||||
|
int quality = 3; // cif:352x288
|
||||||
|
camcorder_quality q = static_cast<camcorder_quality>(quality);
|
||||||
|
mDuration = mMediaProfiles->getCamcorderProfileParamByName("duration", (int)mCameraId, q);
|
||||||
|
mVideoFileFormat = mMediaProfiles->getCamcorderProfileParamByName("file.format", (int)mCameraId, q);
|
||||||
|
mVideoCodec = mMediaProfiles->getCamcorderProfileParamByName("vid.codec", (int)mCameraId, q);
|
||||||
|
mVideoBitRate = mMediaProfiles->getCamcorderProfileParamByName("vid.bps", (int)mCameraId, q);
|
||||||
|
mVideoFrameRate = mMediaProfiles->getCamcorderProfileParamByName("vid.fps", (int)mCameraId, q);
|
||||||
|
mVideoFrameWidth = mMediaProfiles->getCamcorderProfileParamByName("vid.width", (int)mCameraId, q);
|
||||||
|
mVideoFrameHeight = mMediaProfiles->getCamcorderProfileParamByName("vid.height", (int)mCameraId, q);
|
||||||
|
mAudioCodec = mMediaProfiles->getCamcorderProfileParamByName("aud.codec", (int)mCameraId, q);
|
||||||
|
mAudioBitRate = mMediaProfiles->getCamcorderProfileParamByName("aud.bps", (int)mCameraId, q);
|
||||||
|
mAudioSampleRate = mMediaProfiles->getCamcorderProfileParamByName("aud.hz", (int)mCameraId, q);
|
||||||
|
mAudioChannels = mMediaProfiles->getCamcorderProfileParamByName("aud.ch", (int)mCameraId, q);
|
||||||
|
|
||||||
|
if (mVideoFrameRate == -1) {
|
||||||
|
DOM_CAMERA_LOGE("Failed to get a valid frame rate!\n");
|
||||||
|
DOM_CAMERA_LOGE("Also got width=%d, height=%d\n", mVideoFrameWidth, mVideoFrameHeight);
|
||||||
|
return NS_ERROR_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
PullParametersImpl();
|
||||||
|
|
||||||
|
// Configure camera video recording parameters.
|
||||||
|
const size_t SIZE = 256;
|
||||||
|
char buffer[SIZE];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ignore the width and height settings from app, just use the one in profile.
|
||||||
|
* Eventually, will try to choose a profile which respects the settings from app.
|
||||||
|
* See bug 795330.
|
||||||
|
*/
|
||||||
|
mParams.setPreviewSize(mVideoFrameWidth, mVideoFrameHeight);
|
||||||
|
mParams.setPreviewFrameRate(mVideoFrameRate);
|
||||||
|
snprintf(buffer, SIZE, "%dx%d", mVideoFrameWidth, mVideoFrameHeight);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* "record-size" is probably deprecated in later ICS;
|
||||||
|
* might need to set "video-size" instead of "record-size".
|
||||||
|
* See bug 795332.
|
||||||
|
*/
|
||||||
|
mParams.set("record-size", buffer);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If we want to enable picture-taking _while_ recording video, this sets the
|
||||||
|
* size of the captured picture. For now, just set it to the same dimensions
|
||||||
|
* as the video we're recording; ideally, we should probably make sure it
|
||||||
|
* matches one of the supported picture sizes.
|
||||||
|
*/
|
||||||
|
mParams.setPictureSize(mVideoFrameWidth, mVideoFrameHeight);
|
||||||
|
|
||||||
|
PushParametersImpl();
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef CHECK_SETARG
|
||||||
|
#define CHECK_SETARG(x) \
|
||||||
|
do { \
|
||||||
|
if (x) { \
|
||||||
|
DOM_CAMERA_LOGE(#x " failed\n"); \
|
||||||
|
return NS_ERROR_INVALID_ARG; \
|
||||||
|
} \
|
||||||
|
} while(0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
nsresult
|
||||||
|
nsGonkCameraControl::SetupRecording(int aFd)
|
||||||
|
{
|
||||||
|
// choosing a size big enough to hold the params
|
||||||
|
const size_t SIZE = 256;
|
||||||
|
char buffer[SIZE];
|
||||||
|
|
||||||
|
mRecorder = new GonkRecorder();
|
||||||
|
CHECK_SETARG(mRecorder->init());
|
||||||
|
|
||||||
|
// set all the params
|
||||||
|
CHECK_SETARG(mRecorder->setCameraHandle((int32_t)mHwHandle));
|
||||||
|
CHECK_SETARG(mRecorder->setAudioSource(AUDIO_SOURCE_CAMCORDER));
|
||||||
|
CHECK_SETARG(mRecorder->setVideoSource(VIDEO_SOURCE_CAMERA));
|
||||||
|
CHECK_SETARG(mRecorder->setOutputFormat((output_format)mVideoFileFormat));
|
||||||
|
CHECK_SETARG(mRecorder->setVideoFrameRate(mVideoFrameRate));
|
||||||
|
CHECK_SETARG(mRecorder->setVideoSize(mVideoFrameWidth, mVideoFrameHeight));
|
||||||
|
snprintf(buffer, SIZE, "video-param-encoding-bitrate=%d", mVideoBitRate);
|
||||||
|
CHECK_SETARG(mRecorder->setParameters(String8(buffer)));
|
||||||
|
CHECK_SETARG(mRecorder->setVideoEncoder((video_encoder)mVideoCodec));
|
||||||
|
snprintf(buffer, SIZE, "audio-param-encoding-bitrate=%d", mAudioBitRate);
|
||||||
|
CHECK_SETARG(mRecorder->setParameters(String8(buffer)));
|
||||||
|
snprintf(buffer, SIZE, "audio-param-number-of-channels=%d", mAudioChannels);
|
||||||
|
CHECK_SETARG(mRecorder->setParameters(String8(buffer)));
|
||||||
|
snprintf(buffer, SIZE, "audio-param-sampling-rate=%d", mAudioSampleRate);
|
||||||
|
CHECK_SETARG(mRecorder->setParameters(String8(buffer)));
|
||||||
|
CHECK_SETARG(mRecorder->setAudioEncoder((audio_encoder)mAudioCodec));
|
||||||
|
// TODO: For now there is no limit on recording duration (See bug 795090)
|
||||||
|
CHECK_SETARG(mRecorder->setParameters(String8("max-duration=-1")));
|
||||||
|
// TODO: For now there is no limit on file size (See bug 795090)
|
||||||
|
CHECK_SETARG(mRecorder->setParameters(String8("max-filesize=-1")));
|
||||||
|
snprintf(buffer, SIZE, "video-param-rotation-angle-degrees=%d", mVideoRotation);
|
||||||
|
CHECK_SETARG(mRecorder->setParameters(String8(buffer)));
|
||||||
|
|
||||||
|
// recording API needs file descriptor of output file
|
||||||
|
CHECK_SETARG(mRecorder->setOutputFile(aFd, 0, 0));
|
||||||
|
CHECK_SETARG(mRecorder->prepare());
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsresult
|
||||||
|
nsGonkCameraControl::GetPreviewStreamVideoModeImpl(GetPreviewStreamVideoModeTask* aGetPreviewStreamVideoMode)
|
||||||
|
{
|
||||||
|
nsCOMPtr<GetPreviewStreamResult> getPreviewStreamResult = nullptr;
|
||||||
|
|
||||||
|
// stop any currently running preview
|
||||||
|
StopPreviewInternal(true /* forced */);
|
||||||
|
|
||||||
|
// copy the recording preview options
|
||||||
|
mVideoRotation = aGetPreviewStreamVideoMode->mOptions.rotation;
|
||||||
|
mVideoWidth = aGetPreviewStreamVideoMode->mOptions.width;
|
||||||
|
mVideoHeight = aGetPreviewStreamVideoMode->mOptions.height;
|
||||||
|
DOM_CAMERA_LOGI("recording preview format: %d x %d (w x h) (rotated %d degrees)\n", mVideoWidth, mVideoHeight, mVideoRotation);
|
||||||
|
|
||||||
|
// setup the video mode
|
||||||
|
nsresult rv = SetupVideoMode();
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
|
// create and return new preview stream object
|
||||||
|
getPreviewStreamResult = new GetPreviewStreamResult(this, mVideoWidth, mVideoHeight, mVideoFrameRate, aGetPreviewStreamVideoMode->mOnSuccessCb);
|
||||||
|
rv = NS_DispatchToMainThread(getPreviewStreamResult);
|
||||||
|
if (NS_FAILED(rv)) {
|
||||||
|
NS_WARNING("Failed to dispatch GetPreviewStreamVideoMode() onSuccess callback to main thread!");
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
// Gonk callback handlers.
|
// Gonk callback handlers.
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
|
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
#include "DOMCameraControl.h"
|
#include "DOMCameraControl.h"
|
||||||
#include "CameraControlImpl.h"
|
#include "CameraControlImpl.h"
|
||||||
#include "CameraCommon.h"
|
#include "CameraCommon.h"
|
||||||
|
#include "GonkRecorder.h"
|
||||||
|
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
|
|
||||||
@ -47,6 +48,9 @@ public:
|
|||||||
void SetParameter(uint32_t aKey, const nsTArray<dom::CameraRegion>& aRegions);
|
void SetParameter(uint32_t aKey, const nsTArray<dom::CameraRegion>& aRegions);
|
||||||
nsresult PushParameters();
|
nsresult PushParameters();
|
||||||
|
|
||||||
|
nsresult SetupRecording(int aFd);
|
||||||
|
nsresult SetupVideoMode();
|
||||||
|
|
||||||
void AutoFocusComplete(bool aSuccess);
|
void AutoFocusComplete(bool aSuccess);
|
||||||
void TakePictureComplete(uint8_t* aData, uint32_t aLength);
|
void TakePictureComplete(uint8_t* aData, uint32_t aLength);
|
||||||
|
|
||||||
@ -56,12 +60,14 @@ protected:
|
|||||||
nsresult GetPreviewStreamImpl(GetPreviewStreamTask* aGetPreviewStream);
|
nsresult GetPreviewStreamImpl(GetPreviewStreamTask* aGetPreviewStream);
|
||||||
nsresult StartPreviewImpl(StartPreviewTask* aStartPreview);
|
nsresult StartPreviewImpl(StartPreviewTask* aStartPreview);
|
||||||
nsresult StopPreviewImpl(StopPreviewTask* aStopPreview);
|
nsresult StopPreviewImpl(StopPreviewTask* aStopPreview);
|
||||||
|
nsresult StopPreviewInternal(bool aForced = false);
|
||||||
nsresult AutoFocusImpl(AutoFocusTask* aAutoFocus);
|
nsresult AutoFocusImpl(AutoFocusTask* aAutoFocus);
|
||||||
nsresult TakePictureImpl(TakePictureTask* aTakePicture);
|
nsresult TakePictureImpl(TakePictureTask* aTakePicture);
|
||||||
nsresult StartRecordingImpl(StartRecordingTask* aStartRecording);
|
nsresult StartRecordingImpl(StartRecordingTask* aStartRecording);
|
||||||
nsresult StopRecordingImpl(StopRecordingTask* aStopRecording);
|
nsresult StopRecordingImpl(StopRecordingTask* aStopRecording);
|
||||||
nsresult PushParametersImpl();
|
nsresult PushParametersImpl();
|
||||||
nsresult PullParametersImpl();
|
nsresult PullParametersImpl();
|
||||||
|
nsresult GetPreviewStreamVideoModeImpl(GetPreviewStreamVideoModeTask* aGetPreviewStreamVideoMode);
|
||||||
|
|
||||||
void SetPreviewSize(uint32_t aWidth, uint32_t aHeight);
|
void SetPreviewSize(uint32_t aWidth, uint32_t aHeight);
|
||||||
|
|
||||||
@ -84,6 +90,27 @@ protected:
|
|||||||
uint32_t mFps;
|
uint32_t mFps;
|
||||||
uint32_t mDiscardedFrameCount;
|
uint32_t mDiscardedFrameCount;
|
||||||
|
|
||||||
|
android::MediaProfiles* mMediaProfiles;
|
||||||
|
android::GonkRecorder* mRecorder;
|
||||||
|
|
||||||
|
PRUint32 mVideoRotation;
|
||||||
|
PRUint32 mVideoWidth;
|
||||||
|
PRUint32 mVideoHeight;
|
||||||
|
nsString mVideoFile;
|
||||||
|
|
||||||
|
// camcorder profile settings for the desired quality level
|
||||||
|
int mDuration; // max recording duration (ignored)
|
||||||
|
int mVideoFileFormat; // output file format
|
||||||
|
int mVideoCodec; // video encoder
|
||||||
|
int mVideoBitRate; // video bit rate
|
||||||
|
int mVideoFrameRate; // video frame rate
|
||||||
|
int mVideoFrameWidth; // video frame width
|
||||||
|
int mVideoFrameHeight;// video frame height
|
||||||
|
int mAudioCodec; // audio encoder
|
||||||
|
int mAudioBitRate; // audio bit rate
|
||||||
|
int mAudioSampleRate; // audio sample rate
|
||||||
|
int mAudioChannels; // number of audio channels
|
||||||
|
|
||||||
private:
|
private:
|
||||||
nsGonkCameraControl(const nsGonkCameraControl&) MOZ_DELETE;
|
nsGonkCameraControl(const nsGonkCameraControl&) MOZ_DELETE;
|
||||||
nsGonkCameraControl& operator=(const nsGonkCameraControl&) MOZ_DELETE;
|
nsGonkCameraControl& operator=(const nsGonkCameraControl&) MOZ_DELETE;
|
||||||
|
@ -143,6 +143,34 @@ GonkCameraHardware::NotifyCallback(int32_t aMsgType, int32_t ext1, int32_t ext2,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
GonkCameraHardware::DataCallbackTimestamp(nsecs_t aTimestamp, int32_t aMsgType, const sp<IMemory> &aDataPtr, void* aUser)
|
||||||
|
{
|
||||||
|
DOM_CAMERA_LOGI("%s",__func__);
|
||||||
|
GonkCameraHardware* hw = GetHardware((uint32_t)aUser);
|
||||||
|
if (!hw) {
|
||||||
|
DOM_CAMERA_LOGE("%s:aUser = %d resolved to no camera hw\n", __func__, (uint32_t)aUser);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (hw->mClosing) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
sp<GonkCameraListener> listener;
|
||||||
|
{
|
||||||
|
//TODO
|
||||||
|
//Mutex::Autolock _l(hw->mLock);
|
||||||
|
listener = hw->mListener;
|
||||||
|
}
|
||||||
|
if (listener.get()) {
|
||||||
|
DOM_CAMERA_LOGI("Listener registered, posting recording frame!");
|
||||||
|
listener->postDataTimestamp(aTimestamp, aMsgType, aDataPtr);
|
||||||
|
} else {
|
||||||
|
DOM_CAMERA_LOGW("No listener was set. Drop a recording frame.");
|
||||||
|
hw->mHardware->releaseRecordingFrame(aDataPtr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
GonkCameraHardware::Init()
|
GonkCameraHardware::Init()
|
||||||
{
|
{
|
||||||
@ -162,7 +190,7 @@ GonkCameraHardware::Init()
|
|||||||
if (sHwHandle == 0) {
|
if (sHwHandle == 0) {
|
||||||
sHwHandle = 1; // don't use 0
|
sHwHandle = 1; // don't use 0
|
||||||
}
|
}
|
||||||
mHardware->setCallbacks(GonkCameraHardware::NotifyCallback, GonkCameraHardware::DataCallback, NULL, (void*)sHwHandle);
|
mHardware->setCallbacks(GonkCameraHardware::NotifyCallback, GonkCameraHardware::DataCallback, GonkCameraHardware::DataCallbackTimestamp, (void*)sHwHandle);
|
||||||
mInitialized = true;
|
mInitialized = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -314,3 +342,81 @@ GonkCameraHardware::StopPreview(uint32_t aHwHandle)
|
|||||||
hw->mHardware->stopPreview();
|
hw->mHardware->stopPreview();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
GonkCameraHardware::StartRecording(uint32_t aHwHandle)
|
||||||
|
{
|
||||||
|
DOM_CAMERA_LOGI("%s: aHwHandle = %d\n", __func__, aHwHandle);
|
||||||
|
int rv = OK;
|
||||||
|
GonkCameraHardware* hw = GetHardware(aHwHandle);
|
||||||
|
if (!hw) {
|
||||||
|
return DEAD_OBJECT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hw->mHardware->recordingEnabled()) {
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!hw->mHardware->previewEnabled()) {
|
||||||
|
DOM_CAMERA_LOGW("Preview was not enabled, enabling now!\n");
|
||||||
|
rv = StartPreview(aHwHandle);
|
||||||
|
if (rv != OK) {
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// start recording mode
|
||||||
|
hw->mHardware->enableMsgType(CAMERA_MSG_VIDEO_FRAME);
|
||||||
|
DOM_CAMERA_LOGI("Calling hw->startRecording\n");
|
||||||
|
rv = hw->mHardware->startRecording();
|
||||||
|
if (rv != OK) {
|
||||||
|
DOM_CAMERA_LOGE("mHardware->startRecording() failed with status %d", rv);
|
||||||
|
}
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
GonkCameraHardware::StopRecording(uint32_t aHwHandle)
|
||||||
|
{
|
||||||
|
DOM_CAMERA_LOGI("%s: aHwHandle = %d\n", __func__, aHwHandle);
|
||||||
|
GonkCameraHardware* hw = GetHardware(aHwHandle);
|
||||||
|
if (!hw) {
|
||||||
|
return DEAD_OBJECT;
|
||||||
|
}
|
||||||
|
|
||||||
|
hw->mHardware->disableMsgType(CAMERA_MSG_VIDEO_FRAME);
|
||||||
|
hw->mHardware->stopRecording();
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
GonkCameraHardware::SetListener(uint32_t aHwHandle, const sp<GonkCameraListener>& aListener)
|
||||||
|
{
|
||||||
|
GonkCameraHardware* hw = GetHardware(aHwHandle);
|
||||||
|
if (!hw) {
|
||||||
|
return DEAD_OBJECT;
|
||||||
|
}
|
||||||
|
|
||||||
|
hw->mListener = aListener;
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
GonkCameraHardware::ReleaseRecordingFrame(uint32_t aHwHandle, const sp<IMemory>& aFrame)
|
||||||
|
{
|
||||||
|
GonkCameraHardware* hw = GetHardware(aHwHandle);
|
||||||
|
if (hw) {
|
||||||
|
hw->mHardware->releaseRecordingFrame(aFrame);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
GonkCameraHardware::StoreMetaDataInBuffers(uint32_t aHwHandle, bool aEnabled)
|
||||||
|
{
|
||||||
|
GonkCameraHardware* hw = GetHardware(aHwHandle);
|
||||||
|
if (!hw) {
|
||||||
|
return DEAD_OBJECT;
|
||||||
|
}
|
||||||
|
|
||||||
|
return hw->mHardware->storeMetaDataInBuffers(aEnabled);
|
||||||
|
}
|
||||||
|
@ -20,6 +20,8 @@
|
|||||||
#include "libcameraservice/CameraHardwareInterface.h"
|
#include "libcameraservice/CameraHardwareInterface.h"
|
||||||
#include "binder/IMemory.h"
|
#include "binder/IMemory.h"
|
||||||
#include "mozilla/ReentrantMonitor.h"
|
#include "mozilla/ReentrantMonitor.h"
|
||||||
|
#include "GonkCameraListener.h"
|
||||||
|
#include <utils/threads.h>
|
||||||
|
|
||||||
#include "GonkCameraControl.h"
|
#include "GonkCameraControl.h"
|
||||||
#include "CameraCommon.h"
|
#include "CameraCommon.h"
|
||||||
@ -46,6 +48,7 @@ protected:
|
|||||||
|
|
||||||
static void DataCallback(int32_t aMsgType, const sp<IMemory> &aDataPtr, camera_frame_metadata_t* aMetadata, void* aUser);
|
static void DataCallback(int32_t aMsgType, const sp<IMemory> &aDataPtr, camera_frame_metadata_t* aMetadata, void* aUser);
|
||||||
static void NotifyCallback(int32_t aMsgType, int32_t ext1, int32_t ext2, void* aUser);
|
static void NotifyCallback(int32_t aMsgType, int32_t ext1, int32_t ext2, void* aUser);
|
||||||
|
static void DataCallbackTimestamp(nsecs_t aTimestamp, int32_t aMsgType, const sp<IMemory>& aDataPtr, void* aUser);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual void OnNewFrame() MOZ_OVERRIDE;
|
virtual void OnNewFrame() MOZ_OVERRIDE;
|
||||||
@ -60,6 +63,11 @@ public:
|
|||||||
static void StopPreview(uint32_t aHwHandle);
|
static void StopPreview(uint32_t aHwHandle);
|
||||||
static int PushParameters(uint32_t aHwHandle, const CameraParameters& aParams);
|
static int PushParameters(uint32_t aHwHandle, const CameraParameters& aParams);
|
||||||
static void PullParameters(uint32_t aHwHandle, CameraParameters& aParams);
|
static void PullParameters(uint32_t aHwHandle, CameraParameters& aParams);
|
||||||
|
static int StartRecording(uint32_t aHwHandle);
|
||||||
|
static int StopRecording(uint32_t aHwHandle);
|
||||||
|
static int SetListener(uint32_t aHwHandle, const sp<GonkCameraListener>& aListener);
|
||||||
|
static void ReleaseRecordingFrame(uint32_t aHwHandle, const sp<IMemory>& aFrame);
|
||||||
|
static int StoreMetaDataInBuffers(uint32_t aHwHandle, bool aEnabled);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
static GonkCameraHardware* sHw;
|
static GonkCameraHardware* sHw;
|
||||||
@ -93,6 +101,7 @@ protected:
|
|||||||
struct timespec mStart;
|
struct timespec mStart;
|
||||||
struct timespec mAutoFocusStart;
|
struct timespec mAutoFocusStart;
|
||||||
#endif
|
#endif
|
||||||
|
sp<GonkCameraListener> mListener;
|
||||||
bool mInitialized;
|
bool mInitialized;
|
||||||
|
|
||||||
bool IsInitialized()
|
bool IsInitialized()
|
||||||
|
37
dom/camera/GonkCameraListener.h
Normal file
37
dom/camera/GonkCameraListener.h
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2008 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef GONK_CAMERA_LISTENER_H
|
||||||
|
#define GONK_CAMERA_LISTENER_H
|
||||||
|
|
||||||
|
#include <utils/Timers.h>
|
||||||
|
#include "libcameraservice/CameraHardwareInterface.h"
|
||||||
|
|
||||||
|
namespace android {
|
||||||
|
|
||||||
|
// ref-counted object for callbacks
|
||||||
|
class GonkCameraListener: virtual public RefBase
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual void notify(int32_t msgType, int32_t ext1, int32_t ext2) = 0;
|
||||||
|
virtual void postData(int32_t msgType, const sp<IMemory>& dataPtr,
|
||||||
|
camera_frame_metadata_t *metadata) = 0;
|
||||||
|
virtual void postDataTimestamp(nsecs_t timestamp, int32_t msgType, const sp<IMemory>& dataPtr) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
}; // namespace android
|
||||||
|
|
||||||
|
#endif
|
733
dom/camera/GonkCameraSource.cpp
Normal file
733
dom/camera/GonkCameraSource.cpp
Normal file
@ -0,0 +1,733 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2009 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <base/basictypes.h>
|
||||||
|
#include "nsDebug.h"
|
||||||
|
#define DOM_CAMERA_LOG_LEVEL 3
|
||||||
|
#include "CameraCommon.h"
|
||||||
|
#define LOGD DOM_CAMERA_LOGA
|
||||||
|
#define LOGV DOM_CAMERA_LOGI
|
||||||
|
#define LOGI DOM_CAMERA_LOGI
|
||||||
|
#define LOGW DOM_CAMERA_LOGW
|
||||||
|
#define LOGE DOM_CAMERA_LOGE
|
||||||
|
|
||||||
|
#include <OMX_Component.h>
|
||||||
|
#include "GonkCameraSource.h"
|
||||||
|
#include "GonkCameraListener.h"
|
||||||
|
#include "GonkCameraHwMgr.h"
|
||||||
|
#include <media/stagefright/MediaDebug.h>
|
||||||
|
#include <media/stagefright/MediaDefs.h>
|
||||||
|
#include <media/stagefright/MediaErrors.h>
|
||||||
|
#include <media/stagefright/MetaData.h>
|
||||||
|
#include <utils/String8.h>
|
||||||
|
#include <cutils/properties.h>
|
||||||
|
|
||||||
|
using namespace mozilla;
|
||||||
|
namespace android {
|
||||||
|
|
||||||
|
static const int64_t CAMERA_SOURCE_TIMEOUT_NS = 3000000000LL;
|
||||||
|
|
||||||
|
struct GonkCameraSourceListener : public GonkCameraListener {
|
||||||
|
GonkCameraSourceListener(const sp<GonkCameraSource> &source);
|
||||||
|
|
||||||
|
virtual void notify(int32_t msgType, int32_t ext1, int32_t ext2);
|
||||||
|
virtual void postData(int32_t msgType, const sp<IMemory> &dataPtr,
|
||||||
|
camera_frame_metadata_t *metadata);
|
||||||
|
|
||||||
|
virtual void postDataTimestamp(
|
||||||
|
nsecs_t timestamp, int32_t msgType, const sp<IMemory>& dataPtr);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual ~GonkCameraSourceListener();
|
||||||
|
|
||||||
|
private:
|
||||||
|
wp<GonkCameraSource> mSource;
|
||||||
|
|
||||||
|
GonkCameraSourceListener(const GonkCameraSourceListener &);
|
||||||
|
GonkCameraSourceListener &operator=(const GonkCameraSourceListener &);
|
||||||
|
};
|
||||||
|
|
||||||
|
GonkCameraSourceListener::GonkCameraSourceListener(const sp<GonkCameraSource> &source)
|
||||||
|
: mSource(source) {
|
||||||
|
}
|
||||||
|
|
||||||
|
GonkCameraSourceListener::~GonkCameraSourceListener() {
|
||||||
|
}
|
||||||
|
|
||||||
|
void GonkCameraSourceListener::notify(int32_t msgType, int32_t ext1, int32_t ext2) {
|
||||||
|
LOGV("notify(%d, %d, %d)", msgType, ext1, ext2);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GonkCameraSourceListener::postData(int32_t msgType, const sp<IMemory> &dataPtr,
|
||||||
|
camera_frame_metadata_t *metadata) {
|
||||||
|
LOGV("postData(%d, ptr:%p, size:%d)",
|
||||||
|
msgType, dataPtr->pointer(), dataPtr->size());
|
||||||
|
|
||||||
|
sp<GonkCameraSource> source = mSource.promote();
|
||||||
|
if (source.get() != NULL) {
|
||||||
|
source->dataCallback(msgType, dataPtr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GonkCameraSourceListener::postDataTimestamp(
|
||||||
|
nsecs_t timestamp, int32_t msgType, const sp<IMemory>& dataPtr) {
|
||||||
|
|
||||||
|
sp<GonkCameraSource> source = mSource.promote();
|
||||||
|
if (source.get() != NULL) {
|
||||||
|
source->dataCallbackTimestamp(timestamp/1000, msgType, dataPtr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int32_t getColorFormat(const char* colorFormat) {
|
||||||
|
return OMX_COLOR_FormatYUV420SemiPlanar;
|
||||||
|
|
||||||
|
if (!strcmp(colorFormat, CameraParameters::PIXEL_FORMAT_YUV420P)) {
|
||||||
|
return OMX_COLOR_FormatYUV420Planar;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!strcmp(colorFormat, CameraParameters::PIXEL_FORMAT_YUV422SP)) {
|
||||||
|
return OMX_COLOR_FormatYUV422SemiPlanar;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!strcmp(colorFormat, CameraParameters::PIXEL_FORMAT_YUV420SP)) {
|
||||||
|
return OMX_COLOR_FormatYUV420SemiPlanar;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!strcmp(colorFormat, CameraParameters::PIXEL_FORMAT_YUV422I)) {
|
||||||
|
return OMX_COLOR_FormatYCbYCr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!strcmp(colorFormat, CameraParameters::PIXEL_FORMAT_RGB565)) {
|
||||||
|
return OMX_COLOR_Format16bitRGB565;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!strcmp(colorFormat, "OMX_TI_COLOR_FormatYUV420PackedSemiPlanar")) {
|
||||||
|
return OMX_TI_COLOR_FormatYUV420PackedSemiPlanar;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOGE("Uknown color format (%s), please add it to "
|
||||||
|
"GonkCameraSource::getColorFormat", colorFormat);
|
||||||
|
|
||||||
|
CHECK_EQ(0, "Unknown color format");
|
||||||
|
}
|
||||||
|
|
||||||
|
GonkCameraSource *GonkCameraSource::Create(
|
||||||
|
int32_t cameraHandle,
|
||||||
|
Size videoSize,
|
||||||
|
int32_t frameRate,
|
||||||
|
bool storeMetaDataInVideoBuffers) {
|
||||||
|
|
||||||
|
GonkCameraSource *source = new GonkCameraSource(cameraHandle,
|
||||||
|
videoSize, frameRate,
|
||||||
|
storeMetaDataInVideoBuffers);
|
||||||
|
return source;
|
||||||
|
}
|
||||||
|
|
||||||
|
GonkCameraSource::GonkCameraSource(
|
||||||
|
int32_t cameraHandle,
|
||||||
|
Size videoSize,
|
||||||
|
int32_t frameRate,
|
||||||
|
bool storeMetaDataInVideoBuffers)
|
||||||
|
: mCameraFlags(0),
|
||||||
|
mVideoFrameRate(-1),
|
||||||
|
mNumFramesReceived(0),
|
||||||
|
mLastFrameTimestampUs(0),
|
||||||
|
mStarted(false),
|
||||||
|
mNumFramesEncoded(0),
|
||||||
|
mTimeBetweenFrameCaptureUs(0),
|
||||||
|
mFirstFrameTimeUs(0),
|
||||||
|
mNumFramesDropped(0),
|
||||||
|
mNumGlitches(0),
|
||||||
|
mGlitchDurationThresholdUs(200000),
|
||||||
|
mCollectStats(false) {
|
||||||
|
mVideoSize.width = -1;
|
||||||
|
mVideoSize.height = -1;
|
||||||
|
|
||||||
|
mCameraHandle = cameraHandle;
|
||||||
|
|
||||||
|
mInitCheck = init(
|
||||||
|
videoSize, frameRate,
|
||||||
|
storeMetaDataInVideoBuffers);
|
||||||
|
if (mInitCheck != OK) releaseCamera();
|
||||||
|
}
|
||||||
|
|
||||||
|
status_t GonkCameraSource::initCheck() const {
|
||||||
|
return mInitCheck;
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO: Do we need to reimplement isCameraAvailable?
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check to see whether the requested video width and height is one
|
||||||
|
* of the supported sizes.
|
||||||
|
* @param width the video frame width in pixels
|
||||||
|
* @param height the video frame height in pixels
|
||||||
|
* @param suppportedSizes the vector of sizes that we check against
|
||||||
|
* @return true if the dimension (width and height) is supported.
|
||||||
|
*/
|
||||||
|
static bool isVideoSizeSupported(
|
||||||
|
int32_t width, int32_t height,
|
||||||
|
const Vector<Size>& supportedSizes) {
|
||||||
|
|
||||||
|
LOGV("isVideoSizeSupported");
|
||||||
|
for (size_t i = 0; i < supportedSizes.size(); ++i) {
|
||||||
|
if (width == supportedSizes[i].width &&
|
||||||
|
height == supportedSizes[i].height) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the preview and video output is separate, we only set the
|
||||||
|
* the video size, and applications should set the preview size
|
||||||
|
* to some proper value, and the recording framework will not
|
||||||
|
* change the preview size; otherwise, if the video and preview
|
||||||
|
* output is the same, we need to set the preview to be the same
|
||||||
|
* as the requested video size.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
* Query the camera to retrieve the supported video frame sizes
|
||||||
|
* and also to see whether CameraParameters::setVideoSize()
|
||||||
|
* is supported or not.
|
||||||
|
* @param params CameraParameters to retrieve the information
|
||||||
|
* @@param isSetVideoSizeSupported retunrs whether method
|
||||||
|
* CameraParameters::setVideoSize() is supported or not.
|
||||||
|
* @param sizes returns the vector of Size objects for the
|
||||||
|
* supported video frame sizes advertised by the camera.
|
||||||
|
*/
|
||||||
|
static void getSupportedVideoSizes(
|
||||||
|
const CameraParameters& params,
|
||||||
|
bool *isSetVideoSizeSupported,
|
||||||
|
Vector<Size>& sizes) {
|
||||||
|
|
||||||
|
*isSetVideoSizeSupported = true;
|
||||||
|
params.getSupportedVideoSizes(sizes);
|
||||||
|
if (sizes.size() == 0) {
|
||||||
|
LOGD("Camera does not support setVideoSize()");
|
||||||
|
params.getSupportedPreviewSizes(sizes);
|
||||||
|
*isSetVideoSizeSupported = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check whether the camera has the supported color format
|
||||||
|
* @param params CameraParameters to retrieve the information
|
||||||
|
* @return OK if no error.
|
||||||
|
*/
|
||||||
|
status_t GonkCameraSource::isCameraColorFormatSupported(
|
||||||
|
const CameraParameters& params) {
|
||||||
|
mColorFormat = getColorFormat(params.get(
|
||||||
|
CameraParameters::KEY_VIDEO_FRAME_FORMAT));
|
||||||
|
if (mColorFormat == -1) {
|
||||||
|
return BAD_VALUE;
|
||||||
|
}
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Configure the camera to use the requested video size
|
||||||
|
* (width and height) and/or frame rate. If both width and
|
||||||
|
* height are -1, configuration on the video size is skipped.
|
||||||
|
* if frameRate is -1, configuration on the frame rate
|
||||||
|
* is skipped. Skipping the configuration allows one to
|
||||||
|
* use the current camera setting without the need to
|
||||||
|
* actually know the specific values (see Create() method).
|
||||||
|
*
|
||||||
|
* @param params the CameraParameters to be configured
|
||||||
|
* @param width the target video frame width in pixels
|
||||||
|
* @param height the target video frame height in pixels
|
||||||
|
* @param frameRate the target frame rate in frames per second.
|
||||||
|
* @return OK if no error.
|
||||||
|
*/
|
||||||
|
status_t GonkCameraSource::configureCamera(
|
||||||
|
CameraParameters* params,
|
||||||
|
int32_t width, int32_t height,
|
||||||
|
int32_t frameRate) {
|
||||||
|
LOGV("configureCamera");
|
||||||
|
Vector<Size> sizes;
|
||||||
|
bool isSetVideoSizeSupportedByCamera = true;
|
||||||
|
getSupportedVideoSizes(*params, &isSetVideoSizeSupportedByCamera, sizes);
|
||||||
|
bool isCameraParamChanged = false;
|
||||||
|
if (width != -1 && height != -1) {
|
||||||
|
if (!isVideoSizeSupported(width, height, sizes)) {
|
||||||
|
LOGE("Video dimension (%dx%d) is unsupported", width, height);
|
||||||
|
return BAD_VALUE;
|
||||||
|
}
|
||||||
|
if (isSetVideoSizeSupportedByCamera) {
|
||||||
|
params->setVideoSize(width, height);
|
||||||
|
} else {
|
||||||
|
params->setPreviewSize(width, height);
|
||||||
|
}
|
||||||
|
isCameraParamChanged = true;
|
||||||
|
} else if ((width == -1 && height != -1) ||
|
||||||
|
(width != -1 && height == -1)) {
|
||||||
|
// If one and only one of the width and height is -1
|
||||||
|
// we reject such a request.
|
||||||
|
LOGE("Requested video size (%dx%d) is not supported", width, height);
|
||||||
|
return BAD_VALUE;
|
||||||
|
} else { // width == -1 && height == -1
|
||||||
|
// Do not configure the camera.
|
||||||
|
// Use the current width and height value setting from the camera.
|
||||||
|
}
|
||||||
|
|
||||||
|
if (frameRate != -1) {
|
||||||
|
CHECK(frameRate > 0 && frameRate <= 120);
|
||||||
|
const char* supportedFrameRates =
|
||||||
|
params->get(CameraParameters::KEY_SUPPORTED_PREVIEW_FRAME_RATES);
|
||||||
|
CHECK(supportedFrameRates != NULL);
|
||||||
|
LOGV("Supported frame rates: %s", supportedFrameRates);
|
||||||
|
char buf[4];
|
||||||
|
snprintf(buf, 4, "%d", frameRate);
|
||||||
|
if (strstr(supportedFrameRates, buf) == NULL) {
|
||||||
|
LOGE("Requested frame rate (%d) is not supported: %s",
|
||||||
|
frameRate, supportedFrameRates);
|
||||||
|
return BAD_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The frame rate is supported, set the camera to the requested value.
|
||||||
|
params->setPreviewFrameRate(frameRate);
|
||||||
|
isCameraParamChanged = true;
|
||||||
|
} else { // frameRate == -1
|
||||||
|
// Do not configure the camera.
|
||||||
|
// Use the current frame rate value setting from the camera
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isCameraParamChanged) {
|
||||||
|
// Either frame rate or frame size needs to be changed.
|
||||||
|
if (OK != GonkCameraHardware::PushParameters(mCameraHandle,*params)) {
|
||||||
|
LOGE("Could not change settings."
|
||||||
|
" Someone else is using camera ?");
|
||||||
|
return -EBUSY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check whether the requested video frame size
|
||||||
|
* has been successfully configured or not. If both width and height
|
||||||
|
* are -1, check on the current width and height value setting
|
||||||
|
* is performed.
|
||||||
|
*
|
||||||
|
* @param params CameraParameters to retrieve the information
|
||||||
|
* @param the target video frame width in pixels to check against
|
||||||
|
* @param the target video frame height in pixels to check against
|
||||||
|
* @return OK if no error
|
||||||
|
*/
|
||||||
|
status_t GonkCameraSource::checkVideoSize(
|
||||||
|
const CameraParameters& params,
|
||||||
|
int32_t width, int32_t height) {
|
||||||
|
|
||||||
|
LOGV("checkVideoSize");
|
||||||
|
// The actual video size is the same as the preview size
|
||||||
|
// if the camera hal does not support separate video and
|
||||||
|
// preview output. In this case, we retrieve the video
|
||||||
|
// size from preview.
|
||||||
|
int32_t frameWidthActual = -1;
|
||||||
|
int32_t frameHeightActual = -1;
|
||||||
|
Vector<Size> sizes;
|
||||||
|
params.getSupportedVideoSizes(sizes);
|
||||||
|
if (sizes.size() == 0) {
|
||||||
|
// video size is the same as preview size
|
||||||
|
params.getPreviewSize(&frameWidthActual, &frameHeightActual);
|
||||||
|
} else {
|
||||||
|
// video size may not be the same as preview
|
||||||
|
params.getVideoSize(&frameWidthActual, &frameHeightActual);
|
||||||
|
}
|
||||||
|
if (frameWidthActual < 0 || frameHeightActual < 0) {
|
||||||
|
LOGE("Failed to retrieve video frame size (%dx%d)",
|
||||||
|
frameWidthActual, frameHeightActual);
|
||||||
|
return UNKNOWN_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check the actual video frame size against the target/requested
|
||||||
|
// video frame size.
|
||||||
|
if (width != -1 && height != -1) {
|
||||||
|
if (frameWidthActual != width || frameHeightActual != height) {
|
||||||
|
LOGE("Failed to set video frame size to %dx%d. "
|
||||||
|
"The actual video size is %dx%d ", width, height,
|
||||||
|
frameWidthActual, frameHeightActual);
|
||||||
|
return UNKNOWN_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Good now.
|
||||||
|
mVideoSize.width = frameWidthActual;
|
||||||
|
mVideoSize.height = frameHeightActual;
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check the requested frame rate has been successfully configured or not.
|
||||||
|
* If the target frameRate is -1, check on the current frame rate value
|
||||||
|
* setting is performed.
|
||||||
|
*
|
||||||
|
* @param params CameraParameters to retrieve the information
|
||||||
|
* @param the target video frame rate to check against
|
||||||
|
* @return OK if no error.
|
||||||
|
*/
|
||||||
|
status_t GonkCameraSource::checkFrameRate(
|
||||||
|
const CameraParameters& params,
|
||||||
|
int32_t frameRate) {
|
||||||
|
|
||||||
|
LOGV("checkFrameRate");
|
||||||
|
int32_t frameRateActual = params.getPreviewFrameRate();
|
||||||
|
if (frameRateActual < 0) {
|
||||||
|
LOGE("Failed to retrieve preview frame rate (%d)", frameRateActual);
|
||||||
|
return UNKNOWN_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check the actual video frame rate against the target/requested
|
||||||
|
// video frame rate.
|
||||||
|
if (frameRate != -1 && (frameRateActual - frameRate) != 0) {
|
||||||
|
LOGE("Failed to set preview frame rate to %d fps. The actual "
|
||||||
|
"frame rate is %d", frameRate, frameRateActual);
|
||||||
|
return UNKNOWN_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Good now.
|
||||||
|
mVideoFrameRate = frameRateActual;
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialize the CameraSource to so that it becomes
|
||||||
|
* ready for providing the video input streams as requested.
|
||||||
|
* @param camera the camera object used for the video source
|
||||||
|
* @param cameraId if camera == 0, use camera with this id
|
||||||
|
* as the video source
|
||||||
|
* @param videoSize the target video frame size. If both
|
||||||
|
* width and height in videoSize is -1, use the current
|
||||||
|
* width and heigth settings by the camera
|
||||||
|
* @param frameRate the target frame rate in frames per second.
|
||||||
|
* if it is -1, use the current camera frame rate setting.
|
||||||
|
* @param storeMetaDataInVideoBuffers request to store meta
|
||||||
|
* data or real YUV data in video buffers. Request to
|
||||||
|
* store meta data in video buffers may not be honored
|
||||||
|
* if the source does not support this feature.
|
||||||
|
*
|
||||||
|
* @return OK if no error.
|
||||||
|
*/
|
||||||
|
status_t GonkCameraSource::init(
|
||||||
|
Size videoSize,
|
||||||
|
int32_t frameRate,
|
||||||
|
bool storeMetaDataInVideoBuffers) {
|
||||||
|
|
||||||
|
LOGV("init");
|
||||||
|
status_t err = OK;
|
||||||
|
//TODO: need to do something here to check the sanity of camera
|
||||||
|
|
||||||
|
CameraParameters params;
|
||||||
|
GonkCameraHardware::PullParameters(mCameraHandle, params);
|
||||||
|
if ((err = isCameraColorFormatSupported(params)) != OK) {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the camera to use the requested video frame size
|
||||||
|
// and/or frame rate.
|
||||||
|
if ((err = configureCamera(¶ms,
|
||||||
|
videoSize.width, videoSize.height,
|
||||||
|
frameRate))) {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check on video frame size and frame rate.
|
||||||
|
CameraParameters newCameraParams;
|
||||||
|
GonkCameraHardware::PullParameters(mCameraHandle, newCameraParams);
|
||||||
|
if ((err = checkVideoSize(newCameraParams,
|
||||||
|
videoSize.width, videoSize.height)) != OK) {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
if ((err = checkFrameRate(newCameraParams, frameRate)) != OK) {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
// By default, do not store metadata in video buffers
|
||||||
|
mIsMetaDataStoredInVideoBuffers = false;
|
||||||
|
GonkCameraHardware::StoreMetaDataInBuffers(mCameraHandle, false);
|
||||||
|
if (storeMetaDataInVideoBuffers) {
|
||||||
|
if (OK == GonkCameraHardware::StoreMetaDataInBuffers(mCameraHandle, true)) {
|
||||||
|
mIsMetaDataStoredInVideoBuffers = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *hfr_str = params.get("video-hfr");
|
||||||
|
int32_t hfr = -1;
|
||||||
|
if ( hfr_str != NULL ) {
|
||||||
|
hfr = atoi(hfr_str);
|
||||||
|
}
|
||||||
|
if(hfr < 0) {
|
||||||
|
LOGW("Invalid hfr value(%d) set from app. Disabling HFR.", hfr);
|
||||||
|
hfr = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t glitchDurationUs = (1000000LL / mVideoFrameRate);
|
||||||
|
if (glitchDurationUs > mGlitchDurationThresholdUs) {
|
||||||
|
mGlitchDurationThresholdUs = glitchDurationUs;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char * k3dFrameArrangement = "3d-frame-format";
|
||||||
|
const char * arrangement = params.get(k3dFrameArrangement);
|
||||||
|
// XXX: just assume left/right for now since that's all the camera supports
|
||||||
|
bool want3D = (arrangement != NULL && !strcmp("left-right", arrangement));
|
||||||
|
|
||||||
|
// XXX: query camera for the stride and slice height
|
||||||
|
// when the capability becomes available.
|
||||||
|
mMeta = new MetaData;
|
||||||
|
mMeta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_RAW);
|
||||||
|
mMeta->setInt32(kKeyColorFormat, mColorFormat);
|
||||||
|
mMeta->setInt32(kKeyWidth, mVideoSize.width);
|
||||||
|
mMeta->setInt32(kKeyHeight, mVideoSize.height);
|
||||||
|
mMeta->setInt32(kKeyStride, mVideoSize.width);
|
||||||
|
mMeta->setInt32(kKeySliceHeight, mVideoSize.height);
|
||||||
|
mMeta->setInt32(kKeyFrameRate, mVideoFrameRate);
|
||||||
|
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
GonkCameraSource::~GonkCameraSource() {
|
||||||
|
if (mStarted) {
|
||||||
|
stop();
|
||||||
|
} else if (mInitCheck == OK) {
|
||||||
|
// Camera is initialized but because start() is never called,
|
||||||
|
// the lock on Camera is never released(). This makes sure
|
||||||
|
// Camera's lock is released in this case.
|
||||||
|
// TODO: Don't think I need to do this
|
||||||
|
releaseCamera();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GonkCameraSource::startCameraRecording() {
|
||||||
|
LOGV("startCameraRecording");
|
||||||
|
CHECK_EQ(OK, GonkCameraHardware::StartRecording(mCameraHandle));
|
||||||
|
}
|
||||||
|
|
||||||
|
status_t GonkCameraSource::start(MetaData *meta) {
|
||||||
|
LOGV("start");
|
||||||
|
CHECK(!mStarted);
|
||||||
|
if (mInitCheck != OK) {
|
||||||
|
LOGE("GonkCameraSource is not initialized yet");
|
||||||
|
return mInitCheck;
|
||||||
|
}
|
||||||
|
|
||||||
|
char value[PROPERTY_VALUE_MAX];
|
||||||
|
if (property_get("media.stagefright.record-stats", value, NULL)
|
||||||
|
&& (!strcmp(value, "1") || !strcasecmp(value, "true"))) {
|
||||||
|
mCollectStats = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
mStartTimeUs = 0;
|
||||||
|
int64_t startTimeUs;
|
||||||
|
if (meta && meta->findInt64(kKeyTime, &startTimeUs)) {
|
||||||
|
LOGV("Metadata enabled, startime: %lld us", startTimeUs);
|
||||||
|
mStartTimeUs = startTimeUs;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Register a listener with GonkCameraHardware so that we can get callbacks
|
||||||
|
GonkCameraHardware::SetListener(mCameraHandle, new GonkCameraSourceListener(this));
|
||||||
|
|
||||||
|
startCameraRecording();
|
||||||
|
|
||||||
|
mStarted = true;
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GonkCameraSource::stopCameraRecording() {
|
||||||
|
LOGV("stopCameraRecording");
|
||||||
|
GonkCameraHardware::StopRecording(mCameraHandle);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GonkCameraSource::releaseCamera() {
|
||||||
|
LOGV("releaseCamera");
|
||||||
|
}
|
||||||
|
|
||||||
|
status_t GonkCameraSource::stop() {
|
||||||
|
LOGV("stop: E");
|
||||||
|
Mutex::Autolock autoLock(mLock);
|
||||||
|
mStarted = false;
|
||||||
|
mFrameAvailableCondition.signal();
|
||||||
|
|
||||||
|
releaseQueuedFrames();
|
||||||
|
while (!mFramesBeingEncoded.empty()) {
|
||||||
|
if (NO_ERROR !=
|
||||||
|
mFrameCompleteCondition.waitRelative(mLock,
|
||||||
|
mTimeBetweenFrameCaptureUs * 1000LL + CAMERA_SOURCE_TIMEOUT_NS)) {
|
||||||
|
LOGW("Timed out waiting for outstanding frames being encoded: %d",
|
||||||
|
mFramesBeingEncoded.size());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
LOGV("Calling stopCameraRecording");
|
||||||
|
stopCameraRecording();
|
||||||
|
releaseCamera();
|
||||||
|
|
||||||
|
if (mCollectStats) {
|
||||||
|
LOGI("Frames received/encoded/dropped: %d/%d/%d in %lld us",
|
||||||
|
mNumFramesReceived, mNumFramesEncoded, mNumFramesDropped,
|
||||||
|
mLastFrameTimestampUs - mFirstFrameTimeUs);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mNumGlitches > 0) {
|
||||||
|
LOGW("%d long delays between neighboring video frames", mNumGlitches);
|
||||||
|
}
|
||||||
|
|
||||||
|
CHECK_EQ(mNumFramesReceived, mNumFramesEncoded + mNumFramesDropped);
|
||||||
|
LOGV("stop: X");
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GonkCameraSource::releaseRecordingFrame(const sp<IMemory>& frame) {
|
||||||
|
LOGV("releaseRecordingFrame");
|
||||||
|
GonkCameraHardware::ReleaseRecordingFrame(mCameraHandle, frame);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GonkCameraSource::releaseQueuedFrames() {
|
||||||
|
List<sp<IMemory> >::iterator it;
|
||||||
|
while (!mFramesReceived.empty()) {
|
||||||
|
it = mFramesReceived.begin();
|
||||||
|
releaseRecordingFrame(*it);
|
||||||
|
mFramesReceived.erase(it);
|
||||||
|
++mNumFramesDropped;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sp<MetaData> GonkCameraSource::getFormat() {
|
||||||
|
return mMeta;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GonkCameraSource::releaseOneRecordingFrame(const sp<IMemory>& frame) {
|
||||||
|
releaseRecordingFrame(frame);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GonkCameraSource::signalBufferReturned(MediaBuffer *buffer) {
|
||||||
|
LOGV("signalBufferReturned: %p", buffer->data());
|
||||||
|
Mutex::Autolock autoLock(mLock);
|
||||||
|
for (List<sp<IMemory> >::iterator it = mFramesBeingEncoded.begin();
|
||||||
|
it != mFramesBeingEncoded.end(); ++it) {
|
||||||
|
if ((*it)->pointer() == buffer->data()) {
|
||||||
|
releaseOneRecordingFrame((*it));
|
||||||
|
mFramesBeingEncoded.erase(it);
|
||||||
|
++mNumFramesEncoded;
|
||||||
|
buffer->setObserver(0);
|
||||||
|
buffer->release();
|
||||||
|
mFrameCompleteCondition.signal();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CHECK_EQ(0, "signalBufferReturned: bogus buffer");
|
||||||
|
}
|
||||||
|
|
||||||
|
status_t GonkCameraSource::read(
|
||||||
|
MediaBuffer **buffer, const ReadOptions *options) {
|
||||||
|
LOGV("read");
|
||||||
|
|
||||||
|
*buffer = NULL;
|
||||||
|
|
||||||
|
int64_t seekTimeUs;
|
||||||
|
ReadOptions::SeekMode mode;
|
||||||
|
if (options && options->getSeekTo(&seekTimeUs, &mode)) {
|
||||||
|
return ERROR_UNSUPPORTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
sp<IMemory> frame;
|
||||||
|
int64_t frameTime;
|
||||||
|
|
||||||
|
{
|
||||||
|
Mutex::Autolock autoLock(mLock);
|
||||||
|
while (mStarted && mFramesReceived.empty()) {
|
||||||
|
if (NO_ERROR !=
|
||||||
|
mFrameAvailableCondition.waitRelative(mLock,
|
||||||
|
mTimeBetweenFrameCaptureUs * 1000LL + CAMERA_SOURCE_TIMEOUT_NS)) {
|
||||||
|
//TODO: check sanity of camera?
|
||||||
|
LOGW("Timed out waiting for incoming camera video frames: %lld us",
|
||||||
|
mLastFrameTimestampUs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!mStarted) {
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
frame = *mFramesReceived.begin();
|
||||||
|
mFramesReceived.erase(mFramesReceived.begin());
|
||||||
|
|
||||||
|
frameTime = *mFrameTimes.begin();
|
||||||
|
mFrameTimes.erase(mFrameTimes.begin());
|
||||||
|
mFramesBeingEncoded.push_back(frame);
|
||||||
|
*buffer = new MediaBuffer(frame->pointer(), frame->size());
|
||||||
|
(*buffer)->setObserver(this);
|
||||||
|
(*buffer)->add_ref();
|
||||||
|
(*buffer)->meta_data()->setInt64(kKeyTime, frameTime);
|
||||||
|
}
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GonkCameraSource::dataCallbackTimestamp(int64_t timestampUs,
|
||||||
|
int32_t msgType, const sp<IMemory> &data) {
|
||||||
|
LOGV("dataCallbackTimestamp: timestamp %lld us", timestampUs);
|
||||||
|
//LOGV("dataCallbackTimestamp: data %x size %d", data->pointer(), data->size());
|
||||||
|
Mutex::Autolock autoLock(mLock);
|
||||||
|
if (!mStarted || (mNumFramesReceived == 0 && timestampUs < mStartTimeUs)) {
|
||||||
|
LOGV("Drop frame at %lld/%lld us", timestampUs, mStartTimeUs);
|
||||||
|
releaseOneRecordingFrame(data);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mNumFramesReceived > 0) {
|
||||||
|
CHECK(timestampUs > mLastFrameTimestampUs);
|
||||||
|
if (timestampUs - mLastFrameTimestampUs > mGlitchDurationThresholdUs) {
|
||||||
|
++mNumGlitches;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// May need to skip frame or modify timestamp. Currently implemented
|
||||||
|
// by the subclass GonkCameraSourceTimeLapse.
|
||||||
|
if (skipCurrentFrame(timestampUs)) {
|
||||||
|
releaseOneRecordingFrame(data);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mLastFrameTimestampUs = timestampUs;
|
||||||
|
if (mNumFramesReceived == 0) {
|
||||||
|
mFirstFrameTimeUs = timestampUs;
|
||||||
|
// Initial delay
|
||||||
|
if (mStartTimeUs > 0) {
|
||||||
|
if (timestampUs < mStartTimeUs) {
|
||||||
|
// Frame was captured before recording was started
|
||||||
|
// Drop it without updating the statistical data.
|
||||||
|
releaseOneRecordingFrame(data);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mStartTimeUs = timestampUs - mStartTimeUs;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
++mNumFramesReceived;
|
||||||
|
|
||||||
|
CHECK(data != NULL && data->size() > 0);
|
||||||
|
mFramesReceived.push_back(data);
|
||||||
|
int64_t timeUs = mStartTimeUs + (timestampUs - mFirstFrameTimeUs);
|
||||||
|
mFrameTimes.push_back(timeUs);
|
||||||
|
LOGV("initial delay: %lld, current time stamp: %lld",
|
||||||
|
mStartTimeUs, timeUs);
|
||||||
|
mFrameAvailableCondition.signal();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GonkCameraSource::isMetaDataStoredInVideoBuffers() const {
|
||||||
|
LOGV("isMetaDataStoredInVideoBuffers");
|
||||||
|
return mIsMetaDataStoredInVideoBuffers;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace android
|
161
dom/camera/GonkCameraSource.h
Normal file
161
dom/camera/GonkCameraSource.h
Normal file
@ -0,0 +1,161 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2009 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef GONK_CAMERA_SOURCE_H_
|
||||||
|
|
||||||
|
#define GONK_CAMERA_SOURCE_H_
|
||||||
|
|
||||||
|
#include <media/stagefright/MediaBuffer.h>
|
||||||
|
#include <media/stagefright/MediaSource.h>
|
||||||
|
#include <camera/CameraParameters.h>
|
||||||
|
#include <utils/List.h>
|
||||||
|
#include <utils/RefBase.h>
|
||||||
|
#include <utils/threads.h>
|
||||||
|
|
||||||
|
namespace android {
|
||||||
|
|
||||||
|
class IMemory;
|
||||||
|
class GonkCameraSourceListener;
|
||||||
|
|
||||||
|
class GonkCameraSource : public MediaSource, public MediaBufferObserver {
|
||||||
|
public:
|
||||||
|
|
||||||
|
static GonkCameraSource *Create(int32_t cameraHandle,
|
||||||
|
Size videoSize,
|
||||||
|
int32_t frameRate,
|
||||||
|
bool storeMetaDataInVideoBuffers = false);
|
||||||
|
|
||||||
|
virtual ~GonkCameraSource();
|
||||||
|
|
||||||
|
virtual status_t start(MetaData *params = NULL);
|
||||||
|
virtual status_t stop();
|
||||||
|
virtual status_t read(
|
||||||
|
MediaBuffer **buffer, const ReadOptions *options = NULL);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check whether a GonkCameraSource object is properly initialized.
|
||||||
|
* Must call this method before stop().
|
||||||
|
* @return OK if initialization has successfully completed.
|
||||||
|
*/
|
||||||
|
virtual status_t initCheck() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the MetaData associated with the GonkCameraSource,
|
||||||
|
* including:
|
||||||
|
* kKeyColorFormat: YUV color format of the video frames
|
||||||
|
* kKeyWidth, kKeyHeight: dimension (in pixels) of the video frames
|
||||||
|
* kKeySampleRate: frame rate in frames per second
|
||||||
|
* kKeyMIMEType: always fixed to be MEDIA_MIMETYPE_VIDEO_RAW
|
||||||
|
*/
|
||||||
|
virtual sp<MetaData> getFormat();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tell whether this camera source stores meta data or real YUV
|
||||||
|
* frame data in video buffers.
|
||||||
|
*
|
||||||
|
* @return true if meta data is stored in the video
|
||||||
|
* buffers; false if real YUV data is stored in
|
||||||
|
* the video buffers.
|
||||||
|
*/
|
||||||
|
bool isMetaDataStoredInVideoBuffers() const;
|
||||||
|
|
||||||
|
virtual void signalBufferReturned(MediaBuffer* buffer);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
enum CameraFlags {
|
||||||
|
FLAGS_SET_CAMERA = 1L << 0,
|
||||||
|
FLAGS_HOT_CAMERA = 1L << 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
int32_t mCameraFlags;
|
||||||
|
Size mVideoSize;
|
||||||
|
int32_t mVideoFrameRate;
|
||||||
|
int32_t mColorFormat;
|
||||||
|
status_t mInitCheck;
|
||||||
|
|
||||||
|
sp<MetaData> mMeta;
|
||||||
|
|
||||||
|
int64_t mStartTimeUs;
|
||||||
|
int32_t mNumFramesReceived;
|
||||||
|
int64_t mLastFrameTimestampUs;
|
||||||
|
bool mStarted;
|
||||||
|
int32_t mNumFramesEncoded;
|
||||||
|
|
||||||
|
// Time between capture of two frames.
|
||||||
|
int64_t mTimeBetweenFrameCaptureUs;
|
||||||
|
|
||||||
|
GonkCameraSource(int32_t cameraHandle,
|
||||||
|
Size videoSize, int32_t frameRate,
|
||||||
|
bool storeMetaDataInVideoBuffers = false);
|
||||||
|
|
||||||
|
virtual void startCameraRecording();
|
||||||
|
virtual void stopCameraRecording();
|
||||||
|
virtual void releaseRecordingFrame(const sp<IMemory>& frame);
|
||||||
|
|
||||||
|
// Returns true if need to skip the current frame.
|
||||||
|
// Called from dataCallbackTimestamp.
|
||||||
|
virtual bool skipCurrentFrame(int64_t timestampUs) {return false;}
|
||||||
|
|
||||||
|
friend class GonkCameraSourceListener;
|
||||||
|
// Callback called when still camera raw data is available.
|
||||||
|
virtual void dataCallback(int32_t msgType, const sp<IMemory> &data) {}
|
||||||
|
|
||||||
|
virtual void dataCallbackTimestamp(int64_t timestampUs, int32_t msgType,
|
||||||
|
const sp<IMemory> &data);
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
Mutex mLock;
|
||||||
|
Condition mFrameAvailableCondition;
|
||||||
|
Condition mFrameCompleteCondition;
|
||||||
|
List<sp<IMemory> > mFramesReceived;
|
||||||
|
List<sp<IMemory> > mFramesBeingEncoded;
|
||||||
|
List<int64_t> mFrameTimes;
|
||||||
|
|
||||||
|
int64_t mFirstFrameTimeUs;
|
||||||
|
int32_t mNumFramesDropped;
|
||||||
|
int32_t mNumGlitches;
|
||||||
|
int64_t mGlitchDurationThresholdUs;
|
||||||
|
bool mCollectStats;
|
||||||
|
bool mIsMetaDataStoredInVideoBuffers;
|
||||||
|
int32_t mCameraHandle;
|
||||||
|
|
||||||
|
void releaseQueuedFrames();
|
||||||
|
void releaseOneRecordingFrame(const sp<IMemory>& frame);
|
||||||
|
|
||||||
|
status_t init(Size videoSize, int32_t frameRate,
|
||||||
|
bool storeMetaDataInVideoBuffers);
|
||||||
|
status_t isCameraColorFormatSupported(const CameraParameters& params);
|
||||||
|
status_t configureCamera(CameraParameters* params,
|
||||||
|
int32_t width, int32_t height,
|
||||||
|
int32_t frameRate);
|
||||||
|
|
||||||
|
status_t checkVideoSize(const CameraParameters& params,
|
||||||
|
int32_t width, int32_t height);
|
||||||
|
|
||||||
|
status_t checkFrameRate(const CameraParameters& params,
|
||||||
|
int32_t frameRate);
|
||||||
|
|
||||||
|
void releaseCamera();
|
||||||
|
|
||||||
|
GonkCameraSource(const GonkCameraSource &);
|
||||||
|
GonkCameraSource &operator=(const GonkCameraSource &);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace android
|
||||||
|
|
||||||
|
#endif // GONK_CAMERA_SOURCE_H_
|
1629
dom/camera/GonkRecorder.cpp
Normal file
1629
dom/camera/GonkRecorder.cpp
Normal file
File diff suppressed because it is too large
Load Diff
174
dom/camera/GonkRecorder.h
Normal file
174
dom/camera/GonkRecorder.h
Normal file
@ -0,0 +1,174 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2009 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef GONK_RECORDER_H_
|
||||||
|
|
||||||
|
#define GONK_RECORDER_H_
|
||||||
|
|
||||||
|
#include <media/mediarecorder.h>
|
||||||
|
#include <camera/CameraParameters.h>
|
||||||
|
#include <utils/String8.h>
|
||||||
|
|
||||||
|
#include <system/audio.h>
|
||||||
|
|
||||||
|
namespace android {
|
||||||
|
|
||||||
|
class GonkCameraSource;
|
||||||
|
struct MediaSource;
|
||||||
|
struct MediaWriter;
|
||||||
|
class MetaData;
|
||||||
|
struct AudioSource;
|
||||||
|
class MediaProfiles;
|
||||||
|
|
||||||
|
struct GonkRecorder {
|
||||||
|
GonkRecorder();
|
||||||
|
virtual ~GonkRecorder();
|
||||||
|
|
||||||
|
virtual status_t init();
|
||||||
|
virtual status_t setAudioSource(audio_source_t as);
|
||||||
|
virtual status_t setVideoSource(video_source vs);
|
||||||
|
virtual status_t setOutputFormat(output_format of);
|
||||||
|
virtual status_t setAudioEncoder(audio_encoder ae);
|
||||||
|
virtual status_t setVideoEncoder(video_encoder ve);
|
||||||
|
virtual status_t setVideoSize(int width, int height);
|
||||||
|
virtual status_t setVideoFrameRate(int frames_per_second);
|
||||||
|
virtual status_t setOutputFile(const char *path);
|
||||||
|
virtual status_t setOutputFile(int fd, int64_t offset, int64_t length);
|
||||||
|
virtual status_t setParameters(const String8& params);
|
||||||
|
virtual status_t setCameraHandle(int32_t handle);
|
||||||
|
virtual status_t setListener(const sp<IMediaRecorderClient>& listener);
|
||||||
|
virtual status_t prepare();
|
||||||
|
virtual status_t start();
|
||||||
|
virtual status_t pause();
|
||||||
|
virtual status_t stop();
|
||||||
|
virtual status_t close();
|
||||||
|
virtual status_t reset();
|
||||||
|
virtual status_t getMaxAmplitude(int *max);
|
||||||
|
virtual status_t dump(int fd, const Vector<String16>& args) const;
|
||||||
|
// Querying a SurfaceMediaSourcer
|
||||||
|
|
||||||
|
private:
|
||||||
|
sp<IMediaRecorderClient> mListener;
|
||||||
|
sp<MediaWriter> mWriter;
|
||||||
|
int mOutputFd;
|
||||||
|
sp<AudioSource> mAudioSourceNode;
|
||||||
|
|
||||||
|
audio_source_t mAudioSource;
|
||||||
|
video_source mVideoSource;
|
||||||
|
output_format mOutputFormat;
|
||||||
|
audio_encoder mAudioEncoder;
|
||||||
|
video_encoder mVideoEncoder;
|
||||||
|
bool mUse64BitFileOffset;
|
||||||
|
int32_t mVideoWidth, mVideoHeight;
|
||||||
|
int32_t mFrameRate;
|
||||||
|
int32_t mVideoBitRate;
|
||||||
|
int32_t mAudioBitRate;
|
||||||
|
int32_t mAudioChannels;
|
||||||
|
int32_t mSampleRate;
|
||||||
|
int32_t mInterleaveDurationUs;
|
||||||
|
int32_t mIFramesIntervalSec;
|
||||||
|
int32_t mCameraId;
|
||||||
|
int32_t mVideoEncoderProfile;
|
||||||
|
int32_t mVideoEncoderLevel;
|
||||||
|
int32_t mMovieTimeScale;
|
||||||
|
int32_t mVideoTimeScale;
|
||||||
|
int32_t mAudioTimeScale;
|
||||||
|
int64_t mMaxFileSizeBytes;
|
||||||
|
int64_t mMaxFileDurationUs;
|
||||||
|
int64_t mTrackEveryTimeDurationUs;
|
||||||
|
int32_t mRotationDegrees; // Clockwise
|
||||||
|
int32_t mLatitudex10000;
|
||||||
|
int32_t mLongitudex10000;
|
||||||
|
int32_t mStartTimeOffsetMs;
|
||||||
|
|
||||||
|
String8 mParams;
|
||||||
|
|
||||||
|
bool mIsMetaDataStoredInVideoBuffers;
|
||||||
|
MediaProfiles *mEncoderProfiles;
|
||||||
|
|
||||||
|
bool mStarted;
|
||||||
|
// Needed when GLFrames are encoded.
|
||||||
|
// An <ISurfaceTexture> pointer
|
||||||
|
// will be sent to the client side using which the
|
||||||
|
// frame buffers will be queued and dequeued
|
||||||
|
bool mDisableAudio;
|
||||||
|
int32_t mCameraHandle;
|
||||||
|
|
||||||
|
status_t setupMPEG4Recording(
|
||||||
|
int outputFd,
|
||||||
|
int32_t videoWidth, int32_t videoHeight,
|
||||||
|
int32_t videoBitRate,
|
||||||
|
int32_t *totalBitRate,
|
||||||
|
sp<MediaWriter> *mediaWriter);
|
||||||
|
void setupMPEG4MetaData(int64_t startTimeUs, int32_t totalBitRate,
|
||||||
|
sp<MetaData> *meta);
|
||||||
|
status_t startMPEG4Recording();
|
||||||
|
status_t startAMRRecording();
|
||||||
|
status_t startRawAudioRecording();
|
||||||
|
status_t startMPEG2TSRecording();
|
||||||
|
sp<MediaSource> createAudioSource();
|
||||||
|
status_t checkVideoEncoderCapabilities();
|
||||||
|
status_t checkAudioEncoderCapabilities();
|
||||||
|
// Generic MediaSource set-up. Returns the appropriate
|
||||||
|
// source (CameraSource or SurfaceMediaSource)
|
||||||
|
// depending on the videosource type
|
||||||
|
status_t setupMediaSource(sp<MediaSource> *mediaSource);
|
||||||
|
status_t setupCameraSource(sp<GonkCameraSource> *cameraSource);
|
||||||
|
// setup the surfacemediasource for the encoder
|
||||||
|
|
||||||
|
status_t setupAudioEncoder(const sp<MediaWriter>& writer);
|
||||||
|
status_t setupVideoEncoder(
|
||||||
|
sp<MediaSource> cameraSource,
|
||||||
|
int32_t videoBitRate,
|
||||||
|
sp<MediaSource> *source);
|
||||||
|
|
||||||
|
// Encoding parameter handling utilities
|
||||||
|
status_t setParameter(const String8 &key, const String8 &value);
|
||||||
|
status_t setParamAudioEncodingBitRate(int32_t bitRate);
|
||||||
|
status_t setParamAudioNumberOfChannels(int32_t channles);
|
||||||
|
status_t setParamAudioSamplingRate(int32_t sampleRate);
|
||||||
|
status_t setParamAudioTimeScale(int32_t timeScale);
|
||||||
|
status_t setParamVideoEncodingBitRate(int32_t bitRate);
|
||||||
|
status_t setParamVideoIFramesInterval(int32_t seconds);
|
||||||
|
status_t setParamVideoEncoderProfile(int32_t profile);
|
||||||
|
status_t setParamVideoEncoderLevel(int32_t level);
|
||||||
|
status_t setParamVideoCameraId(int32_t cameraId);
|
||||||
|
status_t setParamVideoTimeScale(int32_t timeScale);
|
||||||
|
status_t setParamVideoRotation(int32_t degrees);
|
||||||
|
status_t setParamTrackTimeStatus(int64_t timeDurationUs);
|
||||||
|
status_t setParamInterleaveDuration(int32_t durationUs);
|
||||||
|
status_t setParam64BitFileOffset(bool use64BitFileOffset);
|
||||||
|
status_t setParamMaxFileDurationUs(int64_t timeUs);
|
||||||
|
status_t setParamMaxFileSizeBytes(int64_t bytes);
|
||||||
|
status_t setParamMovieTimeScale(int32_t timeScale);
|
||||||
|
status_t setParamGeoDataLongitude(int64_t longitudex10000);
|
||||||
|
status_t setParamGeoDataLatitude(int64_t latitudex10000);
|
||||||
|
void clipVideoBitRate();
|
||||||
|
void clipVideoFrameRate();
|
||||||
|
void clipVideoFrameWidth();
|
||||||
|
void clipVideoFrameHeight();
|
||||||
|
void clipAudioBitRate();
|
||||||
|
void clipAudioSampleRate();
|
||||||
|
void clipNumberOfAudioChannels();
|
||||||
|
void setDefaultProfileIfNecessary();
|
||||||
|
|
||||||
|
GonkRecorder(const GonkRecorder &);
|
||||||
|
GonkRecorder &operator=(const GonkRecorder &);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace android
|
||||||
|
|
||||||
|
#endif // GONK_RECORDER_H_
|
@ -6,6 +6,7 @@
|
|||||||
#define DOM_CAMERA_ICAMERACONTROL_H
|
#define DOM_CAMERA_ICAMERACONTROL_H
|
||||||
|
|
||||||
#include "jsapi.h"
|
#include "jsapi.h"
|
||||||
|
#include "nsIDOMDeviceStorage.h"
|
||||||
#include "nsIDOMCameraManager.h"
|
#include "nsIDOMCameraManager.h"
|
||||||
#include "DictionaryHelpers.h"
|
#include "DictionaryHelpers.h"
|
||||||
#include "CameraCommon.h"
|
#include "CameraCommon.h"
|
||||||
@ -26,8 +27,9 @@ public:
|
|||||||
virtual void StopPreview() = 0;
|
virtual void StopPreview() = 0;
|
||||||
virtual nsresult AutoFocus(nsICameraAutoFocusCallback* onSuccess, nsICameraErrorCallback* onError) = 0;
|
virtual nsresult AutoFocus(nsICameraAutoFocusCallback* onSuccess, nsICameraErrorCallback* onError) = 0;
|
||||||
virtual nsresult TakePicture(CameraSize aSize, int32_t aRotation, const nsAString& aFileFormat, CameraPosition aPosition, nsICameraTakePictureCallback* onSuccess, nsICameraErrorCallback* onError) = 0;
|
virtual nsresult TakePicture(CameraSize aSize, int32_t aRotation, const nsAString& aFileFormat, CameraPosition aPosition, nsICameraTakePictureCallback* onSuccess, nsICameraErrorCallback* onError) = 0;
|
||||||
virtual nsresult StartRecording(CameraSize aSize, nsICameraStartRecordingCallback* onSuccess, nsICameraErrorCallback* onError) = 0;
|
virtual nsresult StartRecording(nsIDOMDeviceStorage* aStorageArea, const nsAString& aFilename, nsICameraStartRecordingCallback* onSuccess, nsICameraErrorCallback* onError) = 0;
|
||||||
virtual nsresult StopRecording() = 0;
|
virtual nsresult StopRecording() = 0;
|
||||||
|
virtual nsresult GetPreviewStreamVideoMode(CameraRecordingOptions* aOptions, nsICameraPreviewStreamCallback* onSuccess, nsICameraErrorCallback* onError) = 0;
|
||||||
|
|
||||||
virtual nsresult Set(uint32_t aKey, const nsAString& aValue) = 0;
|
virtual nsresult Set(uint32_t aKey, const nsAString& aValue) = 0;
|
||||||
virtual nsresult Get(uint32_t aKey, nsAString& aValue) = 0;
|
virtual nsresult Get(uint32_t aKey, nsAString& aValue) = 0;
|
||||||
|
@ -32,6 +32,9 @@ CPPSRCS += \
|
|||||||
GonkCameraControl.cpp \
|
GonkCameraControl.cpp \
|
||||||
GonkCameraHwMgr.cpp \
|
GonkCameraHwMgr.cpp \
|
||||||
GonkNativeWindow.cpp \
|
GonkNativeWindow.cpp \
|
||||||
|
GonkRecorder.cpp \
|
||||||
|
GonkCameraSource.cpp \
|
||||||
|
AudioParameter.cpp \
|
||||||
$(NULL)
|
$(NULL)
|
||||||
else ifeq (gonk,$(MOZ_WIDGET_TOOLKIT))
|
else ifeq (gonk,$(MOZ_WIDGET_TOOLKIT))
|
||||||
CPPSRCS += \
|
CPPSRCS += \
|
||||||
|
28
dom/camera/README
Normal file
28
dom/camera/README
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
This README file details from where some of the camcorder source files were derived from and how to apply the provided patch file to get the updated files for B2G.
|
||||||
|
---------------------------------
|
||||||
|
|
||||||
|
Following is the list of B2G files which were derived from an android ics_chocolate build. It also shows the corresponding locations where the original source files can be found:
|
||||||
|
|
||||||
|
GonkRecoder.cpp:
|
||||||
|
https://www.codeaurora.org/gitweb/quic/la/?p=platform/frameworks/base.git;a=blob;f=media/libmediaplayerservice/StagefrightRecorder.cpp;hb=ef1672482a9c2b88d8017927df68144fee42626c
|
||||||
|
|
||||||
|
GonkRecorder.h:
|
||||||
|
https://www.codeaurora.org/gitweb/quic/la/?p=platform/frameworks/base.git;a=blob;f=media/libmediaplayerservice/StagefrightRecorder.h;hb=e3682213bcd3fe43b059e00f0fe4dbebc3f3c35d
|
||||||
|
|
||||||
|
GonkCameraSource.cpp:
|
||||||
|
https://www.codeaurora.org/gitweb/quic/la/?p=platform/frameworks/base.git;a=blob;f=media/libstagefright/CameraSource.cpp;hb=7fa677babfee9c241a131b22c9c1c5ab512ef2d2
|
||||||
|
|
||||||
|
GonkCameraSource.h:
|
||||||
|
https://www.codeaurora.org/gitweb/quic/la/?p=platform/frameworks/base.git;a=blob;f=include/media/stagefright/CameraSource.h;hb=96af14d9b013496accf40a85a66fefcba3ac0111
|
||||||
|
|
||||||
|
AudioParameter.cpp:
|
||||||
|
https://www.codeaurora.org/gitweb/quic/la/?p=platform/frameworks/base.git;a=blob;f=media/libmedia/AudioParameter.cpp;hb=4dc22e77cfd2a1c3671e5646ee87c5e4c15596a0
|
||||||
|
|
||||||
|
GonkCameraListener.h:
|
||||||
|
https://www.codeaurora.org/gitweb/quic/la/?p=platform/frameworks/base.git;a=blob;f=include/camera/Camera.h;hb=796f35e408d9dca386f90d8fbde80471ac011fa6
|
||||||
|
|
||||||
|
There were quite a few changes done to the above listed sources to support camcorder on B2G platform.
|
||||||
|
update.patch lists the changes on top of the original files.
|
||||||
|
update.sh shell script copies the files from an android tree and applies the patch to get updated files for B2G.
|
||||||
|
|
||||||
|
|
@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
|
|
||||||
interface nsIDOMBlob;
|
interface nsIDOMBlob;
|
||||||
|
interface nsIDOMDeviceStorage;
|
||||||
|
|
||||||
/* Used to set the dimensions of a captured picture,
|
/* Used to set the dimensions of a captured picture,
|
||||||
a preview stream, a video capture stream, etc. */
|
a preview stream, a video capture stream, etc. */
|
||||||
@ -108,10 +109,8 @@ interface nsICameraCapabilities : nsISupports
|
|||||||
readonly attribute jsval videoSizes;
|
readonly attribute jsval videoSizes;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/* These properties only affect the captured image;
|
||||||
These properties only affect the captured image;
|
invalid property settings are ignored. */
|
||||||
invalid property settings are ignored.
|
|
||||||
*/
|
|
||||||
dictionary CameraPictureOptions
|
dictionary CameraPictureOptions
|
||||||
{
|
{
|
||||||
/* an object with a combination of 'height' and 'width' properties
|
/* an object with a combination of 'height' and 'width' properties
|
||||||
@ -147,6 +146,14 @@ dictionary CameraPictureOptions
|
|||||||
jsval position;
|
jsval position;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* These properties affect video recording. */
|
||||||
|
dictionary CameraRecordingOptions
|
||||||
|
{
|
||||||
|
long width;
|
||||||
|
long height;
|
||||||
|
long rotation;
|
||||||
|
};
|
||||||
|
|
||||||
[scriptable, function, uuid(0444a687-4bc9-462c-8246-5423f0fe46a4)]
|
[scriptable, function, uuid(0444a687-4bc9-462c-8246-5423f0fe46a4)]
|
||||||
interface nsICameraPreviewStreamCallback : nsISupports
|
interface nsICameraPreviewStreamCallback : nsISupports
|
||||||
{
|
{
|
||||||
@ -165,10 +172,10 @@ interface nsICameraTakePictureCallback : nsISupports
|
|||||||
void handleEvent(in nsIDOMBlob picture);
|
void handleEvent(in nsIDOMBlob picture);
|
||||||
};
|
};
|
||||||
|
|
||||||
[scriptable, function, uuid(ac43f123-529c-48d3-84dd-ad206b7aca9b)]
|
[scriptable, function, uuid(89a762f8-581b-410a-ad86-e2bd2113ad82)]
|
||||||
interface nsICameraStartRecordingCallback : nsISupports
|
interface nsICameraStartRecordingCallback : nsISupports
|
||||||
{
|
{
|
||||||
void handleEvent(in nsIDOMMediaStream stream);
|
void handleEvent();
|
||||||
};
|
};
|
||||||
|
|
||||||
[scriptable, function, uuid(fb80db71-e315-42f0-9ea9-dd3dd312ed70)]
|
[scriptable, function, uuid(fb80db71-e315-42f0-9ea9-dd3dd312ed70)]
|
||||||
@ -187,7 +194,7 @@ interface nsICameraErrorCallback : nsISupports
|
|||||||
attributes here affect the preview, any pictures taken, and/or
|
attributes here affect the preview, any pictures taken, and/or
|
||||||
any video recorded by the camera.
|
any video recorded by the camera.
|
||||||
*/
|
*/
|
||||||
[scriptable, uuid(b8949e5c-55b0-49dd-99a9-68d11342915a)]
|
[scriptable, uuid(469e0462-59e4-4ed5-afa9-aecd1256ee30)]
|
||||||
interface nsICameraControl : nsISupports
|
interface nsICameraControl : nsISupports
|
||||||
{
|
{
|
||||||
readonly attribute nsICameraCapabilities capabilities;
|
readonly attribute nsICameraCapabilities capabilities;
|
||||||
@ -290,15 +297,21 @@ interface nsICameraControl : nsISupports
|
|||||||
[implicit_jscontext]
|
[implicit_jscontext]
|
||||||
void takePicture(in jsval aOptions, in nsICameraTakePictureCallback onSuccess, [optional] in nsICameraErrorCallback onError);
|
void takePicture(in jsval aOptions, in nsICameraTakePictureCallback onSuccess, [optional] in nsICameraErrorCallback onError);
|
||||||
|
|
||||||
/* start recording video; 'aOptions' define the frame size of to
|
/* get a media stream to be used as a camera viewfinder in video mode; 'aOptions'
|
||||||
capture, chosen from capabilities.videoSizes, e.g.:
|
define the frame size of the video capture, chosen from capabilities.videoSizes, e.g.:
|
||||||
{
|
{
|
||||||
width: 640,
|
width: 640,
|
||||||
height: 480
|
height: 480,
|
||||||
|
rotation: 90
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
[implicit_jscontext]
|
[implicit_jscontext]
|
||||||
void startRecording(in jsval aOptions, in nsICameraStartRecordingCallback onSuccess, [optional] in nsICameraErrorCallback onError);
|
void getPreviewStreamVideoMode(in jsval aOptions, in nsICameraPreviewStreamCallback onSuccess, [optional] in nsICameraErrorCallback onError);
|
||||||
|
|
||||||
|
/* start recording video;
|
||||||
|
*/
|
||||||
|
[implicit_jscontext]
|
||||||
|
void startRecording(in nsIDOMDeviceStorage storageArea, in DOMString filename, in nsICameraStartRecordingCallback onSuccess, [optional] in nsICameraErrorCallback onError);
|
||||||
|
|
||||||
/* stop precording video. */
|
/* stop precording video. */
|
||||||
void stopRecording();
|
void stopRecording();
|
||||||
|
2296
dom/camera/update.patch
Normal file
2296
dom/camera/update.patch
Normal file
File diff suppressed because it is too large
Load Diff
14
dom/camera/update.sh
Normal file
14
dom/camera/update.sh
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
# Usage: ./update.sh <android_ics_os_src_directory>
|
||||||
|
#
|
||||||
|
# Copies the needed files from the directory containing the original
|
||||||
|
# Android ICS OS source and applies the B2G specific changes for the
|
||||||
|
# camcorder functionality in B2G.
|
||||||
|
cp $1/frameworks/base/media/libmediaplayerservice/StagefrightRecorder.cpp ./GonkRecorder.cpp
|
||||||
|
cp $1/frameworks/base/media/libmediaplayerservice/StagefrightRecorder.h ./GonkRecorder.h
|
||||||
|
cp $1/frameworks/base/media/libstagefright/CameraSource.cpp ./GonkCameraSource.cpp
|
||||||
|
cp $1/frameworks/base/include/media/stagefright/CameraSource.h ./GonkCameraSource.h
|
||||||
|
cp $1/frameworks/base/media/libmedia/AudioParameter.cpp ./AudioParameter.cpp
|
||||||
|
cp $1/frameworks/base/include/camera/Camera.h ./GonkCameraListener.h
|
||||||
|
patch -p1 <update.patch
|
||||||
|
# If you import CAF sources, you also need to apply update2.patch
|
||||||
|
patch -p1 <update2.patch
|
163
dom/camera/update2.patch
Normal file
163
dom/camera/update2.patch
Normal file
@ -0,0 +1,163 @@
|
|||||||
|
diff --git a/dom/camera/GonkCameraSource.cpp b/dom/camera/GonkCameraSource.cpp
|
||||||
|
--- a/dom/camera/GonkCameraSource.cpp
|
||||||
|
+++ b/dom/camera/GonkCameraSource.cpp
|
||||||
|
@@ -492,21 +492,17 @@ status_t GonkCameraSource::init(
|
||||||
|
mMeta = new MetaData;
|
||||||
|
mMeta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_RAW);
|
||||||
|
mMeta->setInt32(kKeyColorFormat, mColorFormat);
|
||||||
|
mMeta->setInt32(kKeyWidth, mVideoSize.width);
|
||||||
|
mMeta->setInt32(kKeyHeight, mVideoSize.height);
|
||||||
|
mMeta->setInt32(kKeyStride, mVideoSize.width);
|
||||||
|
mMeta->setInt32(kKeySliceHeight, mVideoSize.height);
|
||||||
|
mMeta->setInt32(kKeyFrameRate, mVideoFrameRate);
|
||||||
|
- mMeta->setInt32(kKeyHFR, hfr);
|
||||||
|
|
||||||
|
- if (want3D) {
|
||||||
|
- mMeta->setInt32(kKey3D, !0);
|
||||||
|
- }
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
GonkCameraSource::~GonkCameraSource() {
|
||||||
|
if (mStarted) {
|
||||||
|
stop();
|
||||||
|
} else if (mInitCheck == OK) {
|
||||||
|
// Camera is initialized but because start() is never called,
|
||||||
|
diff --git a/dom/camera/GonkRecorder.cpp b/dom/camera/GonkRecorder.cpp
|
||||||
|
--- a/dom/camera/GonkRecorder.cpp
|
||||||
|
+++ b/dom/camera/GonkRecorder.cpp
|
||||||
|
@@ -716,56 +716,16 @@ status_t GonkRecorder::start() {
|
||||||
|
mStarted = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
sp<MediaSource> GonkRecorder::createAudioSource() {
|
||||||
|
|
||||||
|
- bool tunneledSource = false;
|
||||||
|
- const char *tunnelMime;
|
||||||
|
- {
|
||||||
|
- AudioParameter param;
|
||||||
|
- String8 key("tunneled-input-formats");
|
||||||
|
- param.add( key, String8("get") );
|
||||||
|
- String8 valueStr = AudioSystem::getParameters( 0, param.toString());
|
||||||
|
- AudioParameter result(valueStr);
|
||||||
|
- int value;
|
||||||
|
- if ( mAudioEncoder == AUDIO_ENCODER_AMR_NB &&
|
||||||
|
- result.getInt(String8("AMR"),value) == NO_ERROR ) {
|
||||||
|
- tunneledSource = true;
|
||||||
|
- tunnelMime = MEDIA_MIMETYPE_AUDIO_AMR_NB;
|
||||||
|
- }
|
||||||
|
- else if ( mAudioEncoder == AUDIO_ENCODER_QCELP &&
|
||||||
|
- result.getInt(String8("QCELP"),value) == NO_ERROR ) {
|
||||||
|
- tunneledSource = true;
|
||||||
|
- tunnelMime = MEDIA_MIMETYPE_AUDIO_QCELP;
|
||||||
|
- }
|
||||||
|
- else if ( mAudioEncoder == AUDIO_ENCODER_EVRC &&
|
||||||
|
- result.getInt(String8("EVRC"),value) == NO_ERROR ) {
|
||||||
|
- tunneledSource = true;
|
||||||
|
- tunnelMime = MEDIA_MIMETYPE_AUDIO_EVRC;
|
||||||
|
- }
|
||||||
|
- }
|
||||||
|
-
|
||||||
|
- if ( tunneledSource ) {
|
||||||
|
- sp<AudioSource> audioSource = NULL;
|
||||||
|
- sp<MetaData> meta = new MetaData;
|
||||||
|
- meta->setInt32(kKeyChannelCount, mAudioChannels);
|
||||||
|
- meta->setInt32(kKeySampleRate, mSampleRate);
|
||||||
|
- meta->setInt32(kKeyBitRate, mAudioBitRate);
|
||||||
|
- if (mAudioTimeScale > 0) {
|
||||||
|
- meta->setInt32(kKeyTimeScale, mAudioTimeScale);
|
||||||
|
- }
|
||||||
|
- meta->setCString( kKeyMIMEType, tunnelMime );
|
||||||
|
- audioSource = new AudioSource( mAudioSource, meta);
|
||||||
|
- return audioSource->initCheck( ) == OK ? audioSource : NULL;
|
||||||
|
- }
|
||||||
|
-
|
||||||
|
sp<AudioSource> audioSource =
|
||||||
|
new AudioSource(
|
||||||
|
mAudioSource,
|
||||||
|
mSampleRate,
|
||||||
|
mAudioChannels);
|
||||||
|
|
||||||
|
status_t err = audioSource->initCheck();
|
||||||
|
|
||||||
|
@@ -1226,56 +1186,33 @@ status_t GonkRecorder::setupVideoEncoder
|
||||||
|
|
||||||
|
default:
|
||||||
|
CHECK(!"Should not be here, unsupported video encoding.");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
sp<MetaData> meta = cameraSource->getFormat();
|
||||||
|
|
||||||
|
- int32_t width, height, stride, sliceHeight, colorFormat, hfr, is3D;
|
||||||
|
+ int32_t width, height, stride, sliceHeight, colorFormat;
|
||||||
|
CHECK(meta->findInt32(kKeyWidth, &width));
|
||||||
|
CHECK(meta->findInt32(kKeyHeight, &height));
|
||||||
|
CHECK(meta->findInt32(kKeyStride, &stride));
|
||||||
|
CHECK(meta->findInt32(kKeySliceHeight, &sliceHeight));
|
||||||
|
CHECK(meta->findInt32(kKeyColorFormat, &colorFormat));
|
||||||
|
- CHECK(meta->findInt32(kKeyHFR, &hfr));
|
||||||
|
-
|
||||||
|
- if(hfr) {
|
||||||
|
- mMaxFileDurationUs = mMaxFileDurationUs * (hfr/mFrameRate);
|
||||||
|
- }
|
||||||
|
-
|
||||||
|
|
||||||
|
enc_meta->setInt32(kKeyWidth, width);
|
||||||
|
enc_meta->setInt32(kKeyHeight, height);
|
||||||
|
enc_meta->setInt32(kKeyIFramesInterval, mIFramesIntervalSec);
|
||||||
|
enc_meta->setInt32(kKeyStride, stride);
|
||||||
|
enc_meta->setInt32(kKeySliceHeight, sliceHeight);
|
||||||
|
enc_meta->setInt32(kKeyColorFormat, colorFormat);
|
||||||
|
- enc_meta->setInt32(kKeyHFR, hfr);
|
||||||
|
if (mVideoTimeScale > 0) {
|
||||||
|
enc_meta->setInt32(kKeyTimeScale, mVideoTimeScale);
|
||||||
|
}
|
||||||
|
|
||||||
|
- char mDeviceName[100];
|
||||||
|
- property_get("ro.board.platform",mDeviceName,"0");
|
||||||
|
- if(!strncmp(mDeviceName, "msm7627a", 8)) {
|
||||||
|
- if(hfr && (width * height > 432*240)) {
|
||||||
|
- LOGE("HFR mode is supported only upto WQVGA resolution");
|
||||||
|
- return INVALID_OPERATION;
|
||||||
|
- }
|
||||||
|
- }
|
||||||
|
- else {
|
||||||
|
- if(hfr && ((mVideoEncoder != VIDEO_ENCODER_H264) || (width * height > 800*480))) {
|
||||||
|
- LOGE("HFR mode is supported only upto WVGA and H264 codec.");
|
||||||
|
- return INVALID_OPERATION;
|
||||||
|
- }
|
||||||
|
- }
|
||||||
|
-
|
||||||
|
-
|
||||||
|
/*
|
||||||
|
* can set profile from the app as a parameter.
|
||||||
|
* For the mean time, set from shell
|
||||||
|
*/
|
||||||
|
|
||||||
|
char value[PROPERTY_VALUE_MAX];
|
||||||
|
bool customProfile = false;
|
||||||
|
|
||||||
|
@@ -1322,19 +1259,16 @@ status_t GonkRecorder::setupVideoEncoder
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mVideoEncoderProfile != -1) {
|
||||||
|
enc_meta->setInt32(kKeyVideoProfile, mVideoEncoderProfile);
|
||||||
|
}
|
||||||
|
if (mVideoEncoderLevel != -1) {
|
||||||
|
enc_meta->setInt32(kKeyVideoLevel, mVideoEncoderLevel);
|
||||||
|
}
|
||||||
|
- if (meta->findInt32(kKey3D, &is3D)) {
|
||||||
|
- enc_meta->setInt32(kKey3D, is3D);
|
||||||
|
- }
|
||||||
|
|
||||||
|
uint32_t encoder_flags = 0;
|
||||||
|
if (mIsMetaDataStoredInVideoBuffers) {
|
||||||
|
LOGW("Camera source supports metadata mode, create OMXCodec for metadata");
|
||||||
|
encoder_flags |= OMXCodec::kHardwareCodecsOnly;
|
||||||
|
encoder_flags |= OMXCodec::kStoreMetaDataInVideoBuffers;
|
||||||
|
encoder_flags |= OMXCodec::kOnlySubmitOneInputBufferAtOneTime;
|
||||||
|
}
|
@ -55,7 +55,8 @@ DeviceStorageRequestChild::Recv__delete__(const DeviceStorageResponseValue& aVal
|
|||||||
BlobChild* actor = static_cast<BlobChild*>(r.blobChild());
|
BlobChild* actor = static_cast<BlobChild*>(r.blobChild());
|
||||||
nsCOMPtr<nsIDOMBlob> blob = actor->GetBlob();
|
nsCOMPtr<nsIDOMBlob> blob = actor->GetBlob();
|
||||||
|
|
||||||
jsval result = InterfaceToJsval(mRequest->GetOwner(), blob, &NS_GET_IID(nsIDOMBlob));
|
nsCOMPtr<nsIDOMFile> file = do_QueryInterface(blob);
|
||||||
|
jsval result = InterfaceToJsval(mRequest->GetOwner(), file, &NS_GET_IID(nsIDOMFile));
|
||||||
mRequest->FireSuccess(result);
|
mRequest->FireSuccess(result);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -1913,6 +1913,17 @@ nsDOMDeviceStorage::Stat(nsIDOMDOMRequest** aRetval)
|
|||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
nsDOMDeviceStorage::GetRootDirectory(nsIFile** aRootDirectory)
|
||||||
|
{
|
||||||
|
if (!mRootDirectory) {
|
||||||
|
return NS_ERROR_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsCOMPtr<nsIFile> file;
|
||||||
|
return mRootDirectory->Clone(aRootDirectory);
|
||||||
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
nsDOMDeviceStorage::Enumerate(const JS::Value & aName,
|
nsDOMDeviceStorage::Enumerate(const JS::Value & aName,
|
||||||
const JS::Value & aOptions,
|
const JS::Value & aOptions,
|
||||||
|
@ -255,6 +255,94 @@ dictionary MozStkSetUpEventList
|
|||||||
jsval eventList; // unsigned short []
|
jsval eventList; // unsigned short []
|
||||||
};
|
};
|
||||||
|
|
||||||
|
dictionary MozStkLocationInfo
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Mobile Country Code (MCC) of the current serving operator.
|
||||||
|
*/
|
||||||
|
unsigned short mcc;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mobile Network Code (MNC) of the current serving operator.
|
||||||
|
*/
|
||||||
|
unsigned short mnc;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mobile Location Area Code (LAC) for the current serving operator.
|
||||||
|
*/
|
||||||
|
unsigned short gsmLocationAreaCode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mobile Cell ID for the current serving operator.
|
||||||
|
*/
|
||||||
|
unsigned long gsmCellId;
|
||||||
|
};
|
||||||
|
|
||||||
|
dictionary MozStkDuration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Time unit used, should be one of STK_TIME_UNIT_*.
|
||||||
|
*/
|
||||||
|
unsigned short timeUnit;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The length of time required, expressed in timeUnit.
|
||||||
|
*/
|
||||||
|
octet timeInterval;
|
||||||
|
};
|
||||||
|
|
||||||
|
dictionary MozStkPlayTone
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Text String.
|
||||||
|
*/
|
||||||
|
DOMString text;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* One of STK_TONE_TYPE_*.
|
||||||
|
*/
|
||||||
|
unsigned short tone;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The length of time for which the ME shall generate the tone.
|
||||||
|
*
|
||||||
|
* @see MozStkDuration
|
||||||
|
*/
|
||||||
|
jsval duration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Need to vibrate or not.
|
||||||
|
* true: vibrate alert, if available, with the tone.
|
||||||
|
* false: use of vibrate alert is up to the ME.
|
||||||
|
*/
|
||||||
|
boolean isVibrate;
|
||||||
|
};
|
||||||
|
|
||||||
|
dictionary MozStkLocationEvent
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The type of this event.
|
||||||
|
* It shall be nsIDOMMozIccManager.STK_EVENT_TYPE_LOCATION_STATUS;
|
||||||
|
*/
|
||||||
|
unsigned short eventType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicate current service state of the MS with one of the values listed
|
||||||
|
* below:
|
||||||
|
* - nsIDOMMozIccManager.STK_SERVICE_STATE_NORMAL
|
||||||
|
* - nsIDOMMozIccManager.STK_SERVICE_STATE_LIMITED
|
||||||
|
* - nsIDOMMozIccManager.STK_SERVICE_STATE_UNAVAILABLE
|
||||||
|
*/
|
||||||
|
unsigned short locationStatus;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* See MozStkLocationInfo.
|
||||||
|
* This value shall only be provided if the locationStatus indicates
|
||||||
|
* 'STK_SERVICE_STATE_NORMAL'.
|
||||||
|
*/
|
||||||
|
jsval locationInfo;
|
||||||
|
};
|
||||||
|
|
||||||
dictionary MozStkCommand
|
dictionary MozStkCommand
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
@ -306,6 +394,22 @@ dictionary MozStkCommand
|
|||||||
* When typeOfCommand is
|
* When typeOfCommand is
|
||||||
* - STK_CMD_SET_UP_EVENT_LIST
|
* - STK_CMD_SET_UP_EVENT_LIST
|
||||||
* options is MozStkSetUpEventList.
|
* options is MozStkSetUpEventList.
|
||||||
|
*
|
||||||
|
* When typeOfCommand is
|
||||||
|
* - STK_CMD_PLAY_TONE
|
||||||
|
* options is MozStkPlayTone.
|
||||||
|
*
|
||||||
|
* When typeOfCommand is
|
||||||
|
* - STK_CMD_POLL_INTERVAL
|
||||||
|
* options is MozStkDuration.
|
||||||
|
*
|
||||||
|
* When typeOfCommand is
|
||||||
|
* - STK_CMD_POLL_OFF
|
||||||
|
* options is null.
|
||||||
|
*
|
||||||
|
* When typeOfCommand is
|
||||||
|
* - STK_CMD_REFRESH
|
||||||
|
* options is null.
|
||||||
*/
|
*/
|
||||||
jsval options;
|
jsval options;
|
||||||
};
|
};
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
interface nsIDOMEventListener;
|
interface nsIDOMEventListener;
|
||||||
|
|
||||||
[scriptable, builtinclass, uuid(2eace3f9-6aa4-491b-820e-7d69ce7b3f02)]
|
[scriptable, builtinclass, uuid(9d898c66-3485-4cd5-ab8d-92ef2988887b)]
|
||||||
interface nsIDOMMozIccManager : nsIDOMEventTarget
|
interface nsIDOMMozIccManager : nsIDOMEventTarget
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
@ -30,6 +30,8 @@ interface nsIDOMMozIccManager : nsIDOMEventTarget
|
|||||||
* @see TS 11.14, clause 13.4
|
* @see TS 11.14, clause 13.4
|
||||||
*/
|
*/
|
||||||
const unsigned short STK_CMD_REFRESH = 0x01;
|
const unsigned short STK_CMD_REFRESH = 0x01;
|
||||||
|
const unsigned short STK_CMD_POLL_INTERVAL = 0x03;
|
||||||
|
const unsigned short STK_CMD_POLL_OFF = 0x04;
|
||||||
const unsigned short STK_CMD_SET_UP_EVENT_LIST = 0x05;
|
const unsigned short STK_CMD_SET_UP_EVENT_LIST = 0x05;
|
||||||
const unsigned short STK_CMD_SET_UP_CALL = 0x10;
|
const unsigned short STK_CMD_SET_UP_CALL = 0x10;
|
||||||
const unsigned short STK_CMD_SEND_SS = 0x11;
|
const unsigned short STK_CMD_SEND_SS = 0x11;
|
||||||
@ -37,6 +39,7 @@ interface nsIDOMMozIccManager : nsIDOMEventTarget
|
|||||||
const unsigned short STK_CMD_SEND_SMS = 0x13;
|
const unsigned short STK_CMD_SEND_SMS = 0x13;
|
||||||
const unsigned short STK_CMD_SEND_DTMF = 0x14;
|
const unsigned short STK_CMD_SEND_DTMF = 0x14;
|
||||||
const unsigned short STK_CMD_LAUNCH_BROWSER = 0x15;
|
const unsigned short STK_CMD_LAUNCH_BROWSER = 0x15;
|
||||||
|
const unsigned short STK_CMD_PLAY_TONE = 0x20;
|
||||||
const unsigned short STK_CMD_DISPLAY_TEXT = 0x21;
|
const unsigned short STK_CMD_DISPLAY_TEXT = 0x21;
|
||||||
const unsigned short STK_CMD_GET_INKEY = 0x22;
|
const unsigned short STK_CMD_GET_INKEY = 0x22;
|
||||||
const unsigned short STK_CMD_GET_INPUT = 0x23;
|
const unsigned short STK_CMD_GET_INPUT = 0x23;
|
||||||
@ -162,6 +165,35 @@ interface nsIDOMMozIccManager : nsIDOMEventTarget
|
|||||||
const unsigned short STK_EVENT_TYPE_BROWSING_STATUS = 0x0f;
|
const unsigned short STK_EVENT_TYPE_BROWSING_STATUS = 0x0f;
|
||||||
const unsigned short STK_EVENT_TYPE_FRAMES_INFORMATION_CHANGED = 0x10;
|
const unsigned short STK_EVENT_TYPE_FRAMES_INFORMATION_CHANGED = 0x10;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The service state of STK Location Status.
|
||||||
|
*/
|
||||||
|
const unsigned short STK_SERVICE_STATE_NORMAL = 0x00;
|
||||||
|
const unsigned short STK_SERVICE_STATE_LIMITED = 0x01;
|
||||||
|
const unsigned short STK_SERVICE_STATE_UNAVAILABLE = 0x02;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tone type.
|
||||||
|
*/
|
||||||
|
const unsigned short STK_TONE_TYPE_DIAL_TONE = 0x01;
|
||||||
|
const unsigned short STK_TONE_TYPE_CALLED_SUBSCRIBER_BUSY = 0x02;
|
||||||
|
const unsigned short STK_TONE_TYPE_CONGESTION = 0x03;
|
||||||
|
const unsigned short STK_TONE_TYPE_RADIO_PATH_ACK = 0x04;
|
||||||
|
const unsigned short STK_TONE_TYPE_RADIO_PATH_NOT_AVAILABLE = 0x05;
|
||||||
|
const unsigned short STK_TONE_TYPE_ERROR = 0x06;
|
||||||
|
const unsigned short STK_TONE_TYPE_CALL_WAITING_TONE = 0x07;
|
||||||
|
const unsigned short STK_TONE_TYPE_RINGING_TONE = 0x08;
|
||||||
|
const unsigned short STK_TONE_TYPE_GENERAL_BEEP = 0x10;
|
||||||
|
const unsigned short STK_TONE_TYPE_POSITIVE_ACK_TONE = 0x11;
|
||||||
|
const unsigned short STK_TONE_TYPE_NEGATIVE_ACK_TONE = 0x12;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Time unit
|
||||||
|
*/
|
||||||
|
const unsigned short STK_TIME_UNIT_MINUTE = 0x00;
|
||||||
|
const unsigned short STK_TIME_UNIT_SECOND = 0x01;
|
||||||
|
const unsigned short STK_TIME_UNIT_TENTH_SECOND = 0x02;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Send the response back to ICC after an attempt to execute STK Proactive
|
* Send the response back to ICC after an attempt to execute STK Proactive
|
||||||
* Command.
|
* Command.
|
||||||
@ -185,6 +217,16 @@ interface nsIDOMMozIccManager : nsIDOMEventTarget
|
|||||||
void sendStkMenuSelection(in unsigned short itemIdentifier,
|
void sendStkMenuSelection(in unsigned short itemIdentifier,
|
||||||
in boolean helpRequested);
|
in boolean helpRequested);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send "Event Download" Envelope command to ICC.
|
||||||
|
* ICC will not respond with any data for this command.
|
||||||
|
*
|
||||||
|
* @param event
|
||||||
|
* one of events below:
|
||||||
|
* - MozStkLocationEvent
|
||||||
|
*/
|
||||||
|
void sendStkEventDownload(in jsval event);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The 'stkcommand' event is notified whenever STK Proactive Command is
|
* The 'stkcommand' event is notified whenever STK Proactive Command is
|
||||||
* issued from ICC.
|
* issued from ICC.
|
||||||
|
@ -137,6 +137,17 @@ IccManager::SendStkMenuSelection(uint16_t aItemIdentifier, bool aHelpRequested)
|
|||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
IccManager::SendStkEventDownload(const JS::Value& aEvent)
|
||||||
|
{
|
||||||
|
if (!mProvider) {
|
||||||
|
return NS_ERROR_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
mProvider->SendStkEventDownload(GetOwner(), aEvent);
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
IccManager::InternalDispatchEvent(const nsAString& aType)
|
IccManager::InternalDispatchEvent(const nsAString& aType)
|
||||||
{
|
{
|
||||||
|
@ -9,13 +9,14 @@ interface nsIDOMDOMRequest;
|
|||||||
interface nsIDOMDeviceStorageCursor;
|
interface nsIDOMDeviceStorageCursor;
|
||||||
interface nsIDOMDeviceStorageChangeEvent;
|
interface nsIDOMDeviceStorageChangeEvent;
|
||||||
interface nsIDOMEventListener;
|
interface nsIDOMEventListener;
|
||||||
|
interface nsIFile;
|
||||||
|
|
||||||
dictionary DeviceStorageEnumerationParameters
|
dictionary DeviceStorageEnumerationParameters
|
||||||
{
|
{
|
||||||
jsval since;
|
jsval since;
|
||||||
};
|
};
|
||||||
|
|
||||||
[scriptable, uuid(7efbe025-3a8a-4151-9257-3e8c941dc099), builtinclass]
|
[scriptable, uuid(7f69936f-2948-4733-ba41-c7e1d657a88b), builtinclass]
|
||||||
interface nsIDOMDeviceStorage : nsIDOMEventTarget
|
interface nsIDOMDeviceStorage : nsIDOMEventTarget
|
||||||
{
|
{
|
||||||
[implicit_jscontext] attribute jsval onchange;
|
[implicit_jscontext] attribute jsval onchange;
|
||||||
@ -38,4 +39,6 @@ interface nsIDOMDeviceStorage : nsIDOMEventTarget
|
|||||||
nsIDOMDeviceStorageCursor enumerateEditable([optional] in jsval aName, /* DeviceStorageEnumerationParameters */ [optional] in jsval options);
|
nsIDOMDeviceStorageCursor enumerateEditable([optional] in jsval aName, /* DeviceStorageEnumerationParameters */ [optional] in jsval options);
|
||||||
|
|
||||||
nsIDOMDOMRequest stat();
|
nsIDOMDOMRequest stat();
|
||||||
|
|
||||||
|
[noscript] readonly attribute nsIFile rootDirectory;
|
||||||
};
|
};
|
||||||
|
@ -266,6 +266,12 @@ parent:
|
|||||||
*/
|
*/
|
||||||
ContentReceivedTouch(bool aPreventDefault);
|
ContentReceivedTouch(bool aPreventDefault);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates any zoom constraints on the parent and anything tied to it. This
|
||||||
|
* is useful for control logic that resides outside of the remote browser.
|
||||||
|
*/
|
||||||
|
UpdateZoomConstraints(bool aAllowZoom, float aMinZoom, float aMaxZoom);
|
||||||
|
|
||||||
__delete__();
|
__delete__();
|
||||||
|
|
||||||
child:
|
child:
|
||||||
@ -282,9 +288,9 @@ child:
|
|||||||
|
|
||||||
LoadURL(nsCString uri);
|
LoadURL(nsCString uri);
|
||||||
|
|
||||||
UpdateDimensions(nsRect rect, nsIntSize size);
|
UpdateDimensions(nsRect rect, nsIntSize size) compress;
|
||||||
|
|
||||||
UpdateFrame(FrameMetrics frame);
|
UpdateFrame(FrameMetrics frame) compress;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Requests handling of a double tap. |point| is in CSS pixels, relative to
|
* Requests handling of a double tap. |point| is in CSS pixels, relative to
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
#include "mozilla/dom/PContentChild.h"
|
#include "mozilla/dom/PContentChild.h"
|
||||||
#include "mozilla/dom/PContentDialogChild.h"
|
#include "mozilla/dom/PContentDialogChild.h"
|
||||||
#include "mozilla/ipc/DocumentRendererChild.h"
|
#include "mozilla/ipc/DocumentRendererChild.h"
|
||||||
|
#include "mozilla/layers/AsyncPanZoomController.h"
|
||||||
#include "mozilla/layers/CompositorChild.h"
|
#include "mozilla/layers/CompositorChild.h"
|
||||||
#include "mozilla/layers/PLayersChild.h"
|
#include "mozilla/layers/PLayersChild.h"
|
||||||
#include "mozilla/layout/RenderFrameChild.h"
|
#include "mozilla/layout/RenderFrameChild.h"
|
||||||
@ -29,10 +30,12 @@
|
|||||||
#include "nsContentUtils.h"
|
#include "nsContentUtils.h"
|
||||||
#include "nsEmbedCID.h"
|
#include "nsEmbedCID.h"
|
||||||
#include "nsEventListenerManager.h"
|
#include "nsEventListenerManager.h"
|
||||||
|
#include "nsGenericElement.h"
|
||||||
#include "nsIAppsService.h"
|
#include "nsIAppsService.h"
|
||||||
#include "nsIBaseWindow.h"
|
#include "nsIBaseWindow.h"
|
||||||
#include "nsIComponentManager.h"
|
#include "nsIComponentManager.h"
|
||||||
#include "nsIDOMClassInfo.h"
|
#include "nsIDOMClassInfo.h"
|
||||||
|
#include "nsIDOMElement.h"
|
||||||
#include "nsIDOMEvent.h"
|
#include "nsIDOMEvent.h"
|
||||||
#include "nsIDOMWindow.h"
|
#include "nsIDOMWindow.h"
|
||||||
#include "nsIDOMWindowUtils.h"
|
#include "nsIDOMWindowUtils.h"
|
||||||
@ -50,6 +53,8 @@
|
|||||||
#include "nsIServiceManager.h"
|
#include "nsIServiceManager.h"
|
||||||
#include "nsISupportsImpl.h"
|
#include "nsISupportsImpl.h"
|
||||||
#include "nsIURI.h"
|
#include "nsIURI.h"
|
||||||
|
#include "nsIURIFixup.h"
|
||||||
|
#include "nsCDefaultURIFixup.h"
|
||||||
#include "nsIView.h"
|
#include "nsIView.h"
|
||||||
#include "nsIWebBrowser.h"
|
#include "nsIWebBrowser.h"
|
||||||
#include "nsIWebBrowserFocus.h"
|
#include "nsIWebBrowserFocus.h"
|
||||||
@ -85,6 +90,12 @@ using namespace mozilla::widget;
|
|||||||
|
|
||||||
NS_IMPL_ISUPPORTS1(ContentListener, nsIDOMEventListener)
|
NS_IMPL_ISUPPORTS1(ContentListener, nsIDOMEventListener)
|
||||||
|
|
||||||
|
static const nsIntSize kDefaultViewportSize(980, 480);
|
||||||
|
|
||||||
|
static const char CANCEL_DEFAULT_PAN_ZOOM[] = "cancel-default-pan-zoom";
|
||||||
|
static const char BROWSER_ZOOM_TO_RECT[] = "browser-zoom-to-rect";
|
||||||
|
static const char BEFORE_FIRST_PAINT[] = "before-first-paint";
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
ContentListener::HandleEvent(nsIDOMEvent* aEvent)
|
ContentListener::HandleEvent(nsIDOMEvent* aEvent)
|
||||||
{
|
{
|
||||||
@ -151,28 +162,45 @@ TabChild::TabChild(uint32_t aChromeFlags, bool aIsBrowserElement,
|
|||||||
, mTabChildGlobal(nullptr)
|
, mTabChildGlobal(nullptr)
|
||||||
, mChromeFlags(aChromeFlags)
|
, mChromeFlags(aChromeFlags)
|
||||||
, mOuterRect(0, 0, 0, 0)
|
, mOuterRect(0, 0, 0, 0)
|
||||||
|
, mInnerSize(0, 0)
|
||||||
|
, mOldViewportWidth(0.0f)
|
||||||
, mLastBackgroundColor(NS_RGB(255, 255, 255))
|
, mLastBackgroundColor(NS_RGB(255, 255, 255))
|
||||||
, mAppId(aAppId)
|
, mAppId(aAppId)
|
||||||
, mDidFakeShow(false)
|
, mDidFakeShow(false)
|
||||||
, mIsBrowserElement(aIsBrowserElement)
|
, mIsBrowserElement(aIsBrowserElement)
|
||||||
, mNotified(false)
|
, mNotified(false)
|
||||||
|
, mContentDocumentIsDisplayed(false)
|
||||||
, mTriedBrowserInit(false)
|
, mTriedBrowserInit(false)
|
||||||
{
|
{
|
||||||
printf("creating %d!\n", NS_IsMainThread());
|
printf("creating %d!\n", NS_IsMainThread());
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult
|
NS_IMETHODIMP
|
||||||
|
TabChild::HandleEvent(nsIDOMEvent* aEvent)
|
||||||
|
{
|
||||||
|
nsAutoString eventType;
|
||||||
|
aEvent->GetType(eventType);
|
||||||
|
if (eventType.EqualsLiteral("DOMMetaAdded")) {
|
||||||
|
// This meta data may or may not have been a meta viewport tag. If it was,
|
||||||
|
// we should handle it immediately.
|
||||||
|
HandlePossibleMetaViewportChange();
|
||||||
|
}
|
||||||
|
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
TabChild::Observe(nsISupports *aSubject,
|
TabChild::Observe(nsISupports *aSubject,
|
||||||
const char *aTopic,
|
const char *aTopic,
|
||||||
const PRUnichar *aData)
|
const PRUnichar *aData)
|
||||||
{
|
{
|
||||||
if (!strcmp(aTopic, "cancel-default-pan-zoom")) {
|
if (!strcmp(aTopic, CANCEL_DEFAULT_PAN_ZOOM)) {
|
||||||
nsCOMPtr<nsIDocShell> docShell(do_QueryInterface(aSubject));
|
nsCOMPtr<nsIDocShell> docShell(do_QueryInterface(aSubject));
|
||||||
nsCOMPtr<nsITabChild> tabChild(GetTabChildFrom(docShell));
|
nsCOMPtr<nsITabChild> tabChild(GetTabChildFrom(docShell));
|
||||||
if (tabChild == this) {
|
if (tabChild == this) {
|
||||||
mRemoteFrame->CancelDefaultPanZoom();
|
mRemoteFrame->CancelDefaultPanZoom();
|
||||||
}
|
}
|
||||||
} else if (!strcmp(aTopic, "browser-zoom-to-rect")) {
|
} else if (!strcmp(aTopic, BROWSER_ZOOM_TO_RECT)) {
|
||||||
nsCOMPtr<nsIDocShell> docShell(do_QueryInterface(aSubject));
|
nsCOMPtr<nsIDocShell> docShell(do_QueryInterface(aSubject));
|
||||||
nsCOMPtr<nsITabChild> tabChild(GetTabChildFrom(docShell));
|
nsCOMPtr<nsITabChild> tabChild(GetTabChildFrom(docShell));
|
||||||
if (tabChild == this) {
|
if (tabChild == this) {
|
||||||
@ -182,11 +210,264 @@ TabChild::Observe(nsISupports *aSubject,
|
|||||||
&rect.x, &rect.y, &rect.width, &rect.height);
|
&rect.x, &rect.y, &rect.width, &rect.height);
|
||||||
SendZoomToRect(rect);
|
SendZoomToRect(rect);
|
||||||
}
|
}
|
||||||
|
} else if (!strcmp(aTopic, BEFORE_FIRST_PAINT)) {
|
||||||
|
if (IsAsyncPanZoomEnabled()) {
|
||||||
|
nsCOMPtr<nsIDocument> subject(do_QueryInterface(aSubject));
|
||||||
|
nsCOMPtr<nsIDOMDocument> domDoc;
|
||||||
|
mWebNav->GetDocument(getter_AddRefs(domDoc));
|
||||||
|
nsCOMPtr<nsIDocument> doc(do_QueryInterface(domDoc));
|
||||||
|
|
||||||
|
if (SameCOMIdentity(subject, doc)) {
|
||||||
|
nsCOMPtr<nsIDOMWindowUtils> utils(GetDOMWindowUtils());
|
||||||
|
|
||||||
|
mContentDocumentIsDisplayed = true;
|
||||||
|
|
||||||
|
// Reset CSS viewport and zoom to default on new page, then calculate them
|
||||||
|
// properly using the actual metadata from the page.
|
||||||
|
SetCSSViewport(kDefaultViewportSize.width, kDefaultViewportSize.height);
|
||||||
|
|
||||||
|
// Calculate a really simple resolution that we probably won't be
|
||||||
|
// keeping, as well as putting the scroll offset back to the top-left of
|
||||||
|
// the page.
|
||||||
|
float resolution = float(mInnerSize.width) / float(kDefaultViewportSize.width);
|
||||||
|
mLastMetrics.mZoom.width = mLastMetrics.mZoom.height =
|
||||||
|
mLastMetrics.mResolution.width = mLastMetrics.mResolution.height =
|
||||||
|
resolution;
|
||||||
|
mLastMetrics.mScrollOffset = gfx::Point(0, 0);
|
||||||
|
utils->SetResolution(resolution, resolution);
|
||||||
|
|
||||||
|
HandlePossibleMetaViewportChange();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
TabChild::OnStateChange(nsIWebProgress* aWebProgress,
|
||||||
|
nsIRequest* aRequest,
|
||||||
|
uint32_t aStateFlags,
|
||||||
|
nsresult aStatus)
|
||||||
|
{
|
||||||
|
NS_NOTREACHED("not implemented in TabChild");
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
TabChild::OnProgressChange(nsIWebProgress* aWebProgress,
|
||||||
|
nsIRequest* aRequest,
|
||||||
|
int32_t aCurSelfProgress,
|
||||||
|
int32_t aMaxSelfProgress,
|
||||||
|
int32_t aCurTotalProgress,
|
||||||
|
int32_t aMaxTotalProgress)
|
||||||
|
{
|
||||||
|
NS_NOTREACHED("not implemented in TabChild");
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
TabChild::OnLocationChange(nsIWebProgress* aWebProgress,
|
||||||
|
nsIRequest* aRequest,
|
||||||
|
nsIURI *aLocation,
|
||||||
|
uint32_t aFlags)
|
||||||
|
{
|
||||||
|
if (!IsAsyncPanZoomEnabled()) {
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsCOMPtr<nsIDOMWindow> window;
|
||||||
|
aWebProgress->GetDOMWindow(getter_AddRefs(window));
|
||||||
|
if (!window) {
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsCOMPtr<nsIDOMDocument> progressDoc;
|
||||||
|
window->GetDocument(getter_AddRefs(progressDoc));
|
||||||
|
if (!progressDoc) {
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsCOMPtr<nsIDOMDocument> domDoc;
|
||||||
|
mWebNav->GetDocument(getter_AddRefs(domDoc));
|
||||||
|
if (!domDoc || !SameCOMIdentity(domDoc, progressDoc)) {
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsCOMPtr<nsIURIFixup> urifixup(do_GetService(NS_URIFIXUP_CONTRACTID));
|
||||||
|
if (!urifixup) {
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsCOMPtr<nsIURI> exposableURI;
|
||||||
|
urifixup->CreateExposableURI(aLocation, getter_AddRefs(exposableURI));
|
||||||
|
if (!exposableURI) {
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(aFlags & nsIWebProgressListener::LOCATION_CHANGE_SAME_DOCUMENT)) {
|
||||||
|
mContentDocumentIsDisplayed = false;
|
||||||
|
} else if (mLastURI != nullptr) {
|
||||||
|
bool exposableEqualsLast, exposableEqualsNew;
|
||||||
|
exposableURI->Equals(mLastURI.get(), &exposableEqualsLast);
|
||||||
|
exposableURI->Equals(aLocation, &exposableEqualsNew);
|
||||||
|
if (exposableEqualsLast && !exposableEqualsNew) {
|
||||||
|
mContentDocumentIsDisplayed = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
TabChild::OnStatusChange(nsIWebProgress* aWebProgress,
|
||||||
|
nsIRequest* aRequest,
|
||||||
|
nsresult aStatus,
|
||||||
|
const PRUnichar* aMessage)
|
||||||
|
{
|
||||||
|
NS_NOTREACHED("not implemented in TabChild");
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
TabChild::OnSecurityChange(nsIWebProgress* aWebProgress,
|
||||||
|
nsIRequest* aRequest,
|
||||||
|
uint32_t aState)
|
||||||
|
{
|
||||||
|
NS_NOTREACHED("not implemented in TabChild");
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
TabChild::SetCSSViewport(float aWidth, float aHeight)
|
||||||
|
{
|
||||||
|
mOldViewportWidth = aWidth;
|
||||||
|
|
||||||
|
if (mContentDocumentIsDisplayed) {
|
||||||
|
nsCOMPtr<nsIDOMWindowUtils> utils(GetDOMWindowUtils());
|
||||||
|
utils->SetCSSViewport(aWidth, aHeight);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
TabChild::HandlePossibleMetaViewportChange()
|
||||||
|
{
|
||||||
|
if (!IsAsyncPanZoomEnabled()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsCOMPtr<nsIDOMDocument> domDoc;
|
||||||
|
mWebNav->GetDocument(getter_AddRefs(domDoc));
|
||||||
|
nsCOMPtr<nsIDocument> document(do_QueryInterface(domDoc));
|
||||||
|
|
||||||
|
nsCOMPtr<nsIDOMWindowUtils> utils(GetDOMWindowUtils());
|
||||||
|
|
||||||
|
ViewportInfo viewportMetaData =
|
||||||
|
nsContentUtils::GetViewportInfo(document, mInnerSize.width, mInnerSize.height);
|
||||||
|
SendUpdateZoomConstraints(viewportMetaData.allowZoom,
|
||||||
|
viewportMetaData.minZoom,
|
||||||
|
viewportMetaData.maxZoom);
|
||||||
|
|
||||||
|
float screenW = mInnerSize.width;
|
||||||
|
float screenH = mInnerSize.height;
|
||||||
|
float viewportW = viewportMetaData.width;
|
||||||
|
float viewportH = viewportMetaData.height;
|
||||||
|
|
||||||
|
// We're not being displayed in any way; don't bother doing anything because
|
||||||
|
// that will just confuse future adjustments.
|
||||||
|
if (!screenW || !screenH) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure the viewport height is not shorter than the window when the page
|
||||||
|
// is zoomed out to show its full width. Note that before we set the viewport
|
||||||
|
// width, the "full width" of the page isn't properly defined, so that's why
|
||||||
|
// we have to call SetCSSViewport twice - once to set the width, and the
|
||||||
|
// second time to figure out the height based on the layout at that width.
|
||||||
|
float oldBrowserWidth = mOldViewportWidth;
|
||||||
|
mLastMetrics.mViewport.width = viewportMetaData.width;
|
||||||
|
mLastMetrics.mViewport.height = viewportMetaData.height;
|
||||||
|
if (!oldBrowserWidth) {
|
||||||
|
oldBrowserWidth = kDefaultViewportSize.width;
|
||||||
|
}
|
||||||
|
SetCSSViewport(viewportW, viewportH);
|
||||||
|
|
||||||
|
// If this page has not been painted yet, then this must be getting run
|
||||||
|
// because a meta-viewport element was added (via the DOMMetaAdded handler).
|
||||||
|
// in this case, we should not do anything that forces a reflow (see bug
|
||||||
|
// 759678) such as requesting the page size or sending a viewport update. this
|
||||||
|
// code will get run again in the before-first-paint handler and that point we
|
||||||
|
// will run though all of it. the reason we even bother executing up to this
|
||||||
|
// point on the DOMMetaAdded handler is so that scripts that use
|
||||||
|
// window.innerWidth before they are painted have a correct value (bug
|
||||||
|
// 771575).
|
||||||
|
if (!mContentDocumentIsDisplayed) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
float minScale = 1.0f;
|
||||||
|
|
||||||
|
nsCOMPtr<nsIDOMElement> htmlDOMElement = do_QueryInterface(document->GetHtmlElement());
|
||||||
|
nsCOMPtr<nsIDOMElement> bodyDOMElement = do_QueryInterface(document->GetBodyElement());
|
||||||
|
|
||||||
|
PRInt32 htmlWidth = 0, htmlHeight = 0;
|
||||||
|
if (htmlDOMElement) {
|
||||||
|
htmlDOMElement->GetScrollWidth(&htmlWidth);
|
||||||
|
htmlDOMElement->GetScrollHeight(&htmlHeight);
|
||||||
|
}
|
||||||
|
PRInt32 bodyWidth = 0, bodyHeight = 0;
|
||||||
|
if (bodyDOMElement) {
|
||||||
|
bodyDOMElement->GetScrollWidth(&bodyWidth);
|
||||||
|
bodyDOMElement->GetScrollHeight(&bodyHeight);
|
||||||
|
}
|
||||||
|
|
||||||
|
float pageWidth = NS_MAX(htmlWidth, bodyWidth);
|
||||||
|
float pageHeight = NS_MAX(htmlHeight, bodyHeight);
|
||||||
|
|
||||||
|
minScale = mInnerSize.width / pageWidth;
|
||||||
|
minScale = clamped((double)minScale, viewportMetaData.minZoom, viewportMetaData.maxZoom);
|
||||||
|
|
||||||
|
viewportH = NS_MAX(viewportH, screenH / minScale);
|
||||||
|
SetCSSViewport(viewportW, viewportH);
|
||||||
|
|
||||||
|
// This change to the zoom accounts for all types of changes I can conceive:
|
||||||
|
// 1. screen size changes, CSS viewport does not (pages with no meta viewport
|
||||||
|
// or a fixed size viewport)
|
||||||
|
// 2. screen size changes, CSS viewport also does (pages with a device-width
|
||||||
|
// viewport)
|
||||||
|
// 3. screen size remains constant, but CSS viewport changes (meta viewport
|
||||||
|
// tag is added or removed)
|
||||||
|
// 4. neither screen size nor CSS viewport changes
|
||||||
|
//
|
||||||
|
// In all of these cases, we maintain how much actual content is visible
|
||||||
|
// within the screen width. Note that "actual content" may be different with
|
||||||
|
// respect to CSS pixels because of the CSS viewport size changing.
|
||||||
|
int32_t oldScreenWidth = mLastMetrics.mCompositionBounds.width;
|
||||||
|
if (!oldScreenWidth) {
|
||||||
|
oldScreenWidth = mInnerSize.width;
|
||||||
|
}
|
||||||
|
float zoomScale = (screenW * oldBrowserWidth) / (oldScreenWidth * viewportW);
|
||||||
|
|
||||||
|
float zoom = clamped(double(mLastMetrics.mZoom.width * zoomScale),
|
||||||
|
viewportMetaData.minZoom, viewportMetaData.maxZoom);
|
||||||
|
utils->SetResolution(zoom, zoom);
|
||||||
|
|
||||||
|
FrameMetrics metrics(mLastMetrics);
|
||||||
|
metrics.mViewport = gfx::Rect(0.0f, 0.0f, viewportW, viewportH);
|
||||||
|
metrics.mScrollableRect = gfx::Rect(0.0f, 0.0f, pageWidth, pageHeight);
|
||||||
|
metrics.mCompositionBounds = nsIntRect(0, 0, mInnerSize.width, mInnerSize.height);
|
||||||
|
metrics.mZoom.width = metrics.mZoom.height =
|
||||||
|
metrics.mResolution.width = metrics.mResolution.height = zoom;
|
||||||
|
metrics.mDisplayPort = AsyncPanZoomController::CalculatePendingDisplayPort(
|
||||||
|
// The page must have been refreshed in some way such as a new document or
|
||||||
|
// new CSS viewport, so we know that there's no velocity, acceleration, and
|
||||||
|
// we have no idea how long painting will take.
|
||||||
|
metrics, gfx::Point(0.0f, 0.0f), gfx::Point(0.0f, 0.0f), 0.0);
|
||||||
|
// Force a repaint with these metrics. This, among other things, sets the
|
||||||
|
// displayport, so we start with async painting.
|
||||||
|
RecvUpdateFrame(metrics);
|
||||||
|
}
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
TabChild::Init()
|
TabChild::Init()
|
||||||
{
|
{
|
||||||
@ -238,6 +519,12 @@ TabChild::Init()
|
|||||||
"DNS prefetching enable step.");
|
"DNS prefetching enable step.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nsCOMPtr<nsIDocShell> docShell = do_GetInterface(mWebNav);
|
||||||
|
MOZ_ASSERT(docShell);
|
||||||
|
nsCOMPtr<nsIWebProgress> webProgress = do_GetInterface(docShell);
|
||||||
|
NS_ENSURE_TRUE(webProgress, NS_ERROR_FAILURE);
|
||||||
|
webProgress->AddProgressListener(this, nsIWebProgress::NOTIFY_LOCATION);
|
||||||
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -266,8 +553,11 @@ NS_INTERFACE_MAP_BEGIN(TabChild)
|
|||||||
NS_INTERFACE_MAP_ENTRY(nsIWebBrowserChromeFocus)
|
NS_INTERFACE_MAP_ENTRY(nsIWebBrowserChromeFocus)
|
||||||
NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)
|
NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)
|
||||||
NS_INTERFACE_MAP_ENTRY(nsIWindowProvider)
|
NS_INTERFACE_MAP_ENTRY(nsIWindowProvider)
|
||||||
|
NS_INTERFACE_MAP_ENTRY(nsIDOMEventListener)
|
||||||
|
NS_INTERFACE_MAP_ENTRY(nsIWebProgressListener)
|
||||||
NS_INTERFACE_MAP_ENTRY(nsITabChild)
|
NS_INTERFACE_MAP_ENTRY(nsITabChild)
|
||||||
NS_INTERFACE_MAP_ENTRY(nsIDialogCreator)
|
NS_INTERFACE_MAP_ENTRY(nsIDialogCreator)
|
||||||
|
NS_INTERFACE_MAP_ENTRY(nsIObserver)
|
||||||
NS_INTERFACE_MAP_ENTRY(nsSupportsWeakReference)
|
NS_INTERFACE_MAP_ENTRY(nsSupportsWeakReference)
|
||||||
NS_INTERFACE_MAP_END
|
NS_INTERFACE_MAP_END
|
||||||
|
|
||||||
@ -799,6 +1089,7 @@ TabChild::RecvUpdateDimensions(const nsRect& rect, const nsIntSize& size)
|
|||||||
mOuterRect.width = rect.width;
|
mOuterRect.width = rect.width;
|
||||||
mOuterRect.height = rect.height;
|
mOuterRect.height = rect.height;
|
||||||
|
|
||||||
|
mInnerSize = size;
|
||||||
mWidget->Resize(0, 0, size.width, size.height,
|
mWidget->Resize(0, 0, size.width, size.height,
|
||||||
true);
|
true);
|
||||||
|
|
||||||
@ -806,6 +1097,8 @@ TabChild::RecvUpdateDimensions(const nsRect& rect, const nsIntSize& size)
|
|||||||
baseWin->SetPositionAndSize(0, 0, size.width, size.height,
|
baseWin->SetPositionAndSize(0, 0, size.width, size.height,
|
||||||
true);
|
true);
|
||||||
|
|
||||||
|
HandlePossibleMetaViewportChange();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -842,33 +1135,63 @@ TabChild::RecvUpdateFrame(const FrameMetrics& aFrameMetrics)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The BrowserElementScrolling helper must know about these updated metrics
|
||||||
|
// for other functions it performs, such as double tap handling.
|
||||||
nsCString data;
|
nsCString data;
|
||||||
data += nsPrintfCString("{ \"x\" : %d", NS_lround(aFrameMetrics.mViewportScrollOffset.x));
|
data += nsPrintfCString("{ \"x\" : %d", NS_lround(aFrameMetrics.mScrollOffset.x));
|
||||||
data += nsPrintfCString(", \"y\" : %d", NS_lround(aFrameMetrics.mViewportScrollOffset.y));
|
data += nsPrintfCString(", \"y\" : %d", NS_lround(aFrameMetrics.mScrollOffset.y));
|
||||||
// We don't treat the x and y scales any differently for this
|
// We don't treat the x and y scales any differently for this
|
||||||
// semi-platform-specific code.
|
// semi-platform-specific code.
|
||||||
data += nsPrintfCString(", \"zoom\" : %f", aFrameMetrics.mResolution.width);
|
data += nsPrintfCString(", \"zoom\" : %f", aFrameMetrics.mZoom.width);
|
||||||
data += nsPrintfCString(", \"displayPort\" : ");
|
data += nsPrintfCString(", \"displayPort\" : ");
|
||||||
data += nsPrintfCString("{ \"left\" : %d", aFrameMetrics.mDisplayPort.X());
|
data += nsPrintfCString("{ \"x\" : %f", aFrameMetrics.mDisplayPort.x);
|
||||||
data += nsPrintfCString(", \"top\" : %d", aFrameMetrics.mDisplayPort.Y());
|
data += nsPrintfCString(", \"y\" : %f", aFrameMetrics.mDisplayPort.y);
|
||||||
data += nsPrintfCString(", \"width\" : %d", aFrameMetrics.mDisplayPort.Width());
|
data += nsPrintfCString(", \"width\" : %f", aFrameMetrics.mDisplayPort.width);
|
||||||
data += nsPrintfCString(", \"height\" : %d", aFrameMetrics.mDisplayPort.Height());
|
data += nsPrintfCString(", \"height\" : %f", aFrameMetrics.mDisplayPort.height);
|
||||||
data += nsPrintfCString(", \"resolution\" : %f", aFrameMetrics.mResolution.width);
|
data += nsPrintfCString(", \"resolution\" : %f", aFrameMetrics.mResolution.width);
|
||||||
data += nsPrintfCString(" }");
|
data += nsPrintfCString(" }");
|
||||||
data += nsPrintfCString(", \"screenSize\" : ");
|
data += nsPrintfCString(", \"compositionBounds\" : ");
|
||||||
data += nsPrintfCString("{ \"width\" : %d", aFrameMetrics.mViewport.width);
|
data += nsPrintfCString("{ \"x\" : %d", aFrameMetrics.mCompositionBounds.x);
|
||||||
data += nsPrintfCString(", \"height\" : %d", aFrameMetrics.mViewport.height);
|
data += nsPrintfCString(", \"y\" : %d", aFrameMetrics.mCompositionBounds.y);
|
||||||
|
data += nsPrintfCString(", \"width\" : %d", aFrameMetrics.mCompositionBounds.width);
|
||||||
|
data += nsPrintfCString(", \"height\" : %d", aFrameMetrics.mCompositionBounds.height);
|
||||||
data += nsPrintfCString(" }");
|
data += nsPrintfCString(" }");
|
||||||
data += nsPrintfCString(", \"cssPageRect\" : ");
|
data += nsPrintfCString(", \"cssPageRect\" : ");
|
||||||
data += nsPrintfCString("{ \"x\" : %f", aFrameMetrics.mCSSContentRect.x);
|
data += nsPrintfCString("{ \"x\" : %f", aFrameMetrics.mScrollableRect.x);
|
||||||
data += nsPrintfCString(", \"y\" : %f", aFrameMetrics.mCSSContentRect.y);
|
data += nsPrintfCString(", \"y\" : %f", aFrameMetrics.mScrollableRect.y);
|
||||||
data += nsPrintfCString(", \"width\" : %f", aFrameMetrics.mCSSContentRect.width);
|
data += nsPrintfCString(", \"width\" : %f", aFrameMetrics.mScrollableRect.width);
|
||||||
data += nsPrintfCString(", \"height\" : %f", aFrameMetrics.mCSSContentRect.height);
|
data += nsPrintfCString(", \"height\" : %f", aFrameMetrics.mScrollableRect.height);
|
||||||
data += nsPrintfCString(" }");
|
data += nsPrintfCString(" }");
|
||||||
data += nsPrintfCString(" }");
|
data += nsPrintfCString(" }");
|
||||||
|
|
||||||
DispatchMessageManagerMessage(NS_LITERAL_STRING("Viewport:Change"), data);
|
DispatchMessageManagerMessage(NS_LITERAL_STRING("Viewport:Change"), data);
|
||||||
|
|
||||||
|
nsCOMPtr<nsIDOMWindowUtils> utils(GetDOMWindowUtils());
|
||||||
|
nsCOMPtr<nsIDOMWindow> window = do_GetInterface(mWebNav);
|
||||||
|
|
||||||
|
utils->SetScrollPositionClampingScrollPortSize(
|
||||||
|
aFrameMetrics.mCompositionBounds.width / aFrameMetrics.mZoom.width,
|
||||||
|
aFrameMetrics.mCompositionBounds.height / aFrameMetrics.mZoom.width);
|
||||||
|
window->ScrollTo(aFrameMetrics.mScrollOffset.x,
|
||||||
|
aFrameMetrics.mScrollOffset.y);
|
||||||
|
utils->SetResolution(aFrameMetrics.mResolution.width,
|
||||||
|
aFrameMetrics.mResolution.width);
|
||||||
|
|
||||||
|
nsCOMPtr<nsIDOMDocument> domDoc;
|
||||||
|
nsCOMPtr<nsIDOMElement> docElement;
|
||||||
|
mWebNav->GetDocument(getter_AddRefs(domDoc));
|
||||||
|
if (domDoc) {
|
||||||
|
domDoc->GetDocumentElement(getter_AddRefs(docElement));
|
||||||
|
if (docElement) {
|
||||||
|
utils->SetDisplayPortForElement(
|
||||||
|
aFrameMetrics.mDisplayPort.x, aFrameMetrics.mDisplayPort.y,
|
||||||
|
aFrameMetrics.mDisplayPort.width, aFrameMetrics.mDisplayPort.height,
|
||||||
|
docElement);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mLastMetrics = aFrameMetrics;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -926,8 +1249,7 @@ TabChild::RecvMouseEvent(const nsString& aType,
|
|||||||
const int32_t& aModifiers,
|
const int32_t& aModifiers,
|
||||||
const bool& aIgnoreRootScrollFrame)
|
const bool& aIgnoreRootScrollFrame)
|
||||||
{
|
{
|
||||||
nsCOMPtr<nsPIDOMWindow> window = do_GetInterface(mWebNav);
|
nsCOMPtr<nsIDOMWindowUtils> utils(GetDOMWindowUtils());
|
||||||
nsCOMPtr<nsIDOMWindowUtils> utils = do_GetInterface(window);
|
|
||||||
NS_ENSURE_TRUE(utils, true);
|
NS_ENSURE_TRUE(utils, true);
|
||||||
utils->SendMouseEvent(aType, aX, aY, aButton, aClickCount, aModifiers,
|
utils->SendMouseEvent(aType, aX, aY, aButton, aClickCount, aModifiers,
|
||||||
aIgnoreRootScrollFrame, 0, 0);
|
aIgnoreRootScrollFrame, 0, 0);
|
||||||
@ -1028,8 +1350,7 @@ TabChild::RecvKeyEvent(const nsString& aType,
|
|||||||
const int32_t& aModifiers,
|
const int32_t& aModifiers,
|
||||||
const bool& aPreventDefault)
|
const bool& aPreventDefault)
|
||||||
{
|
{
|
||||||
nsCOMPtr<nsPIDOMWindow> window = do_GetInterface(mWebNav);
|
nsCOMPtr<nsIDOMWindowUtils> utils(GetDOMWindowUtils());
|
||||||
nsCOMPtr<nsIDOMWindowUtils> utils = do_GetInterface(window);
|
|
||||||
NS_ENSURE_TRUE(utils, true);
|
NS_ENSURE_TRUE(utils, true);
|
||||||
bool ignored = false;
|
bool ignored = false;
|
||||||
utils->SendKeyEvent(aType, aKeyCode, aCharCode,
|
utils->SendKeyEvent(aType, aKeyCode, aCharCode,
|
||||||
@ -1279,6 +1600,13 @@ TabChild::RecvDestroy()
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nsCOMPtr<nsIObserverService> observerService =
|
||||||
|
do_GetService(NS_OBSERVERSERVICE_CONTRACTID);
|
||||||
|
|
||||||
|
observerService->RemoveObserver(this, CANCEL_DEFAULT_PAN_ZOOM);
|
||||||
|
observerService->RemoveObserver(this, BROWSER_ZOOM_TO_RECT);
|
||||||
|
observerService->RemoveObserver(this, BEFORE_FIRST_PAINT);
|
||||||
|
|
||||||
// XXX what other code in ~TabChild() should we be running here?
|
// XXX what other code in ~TabChild() should we be running here?
|
||||||
DestroyWindow();
|
DestroyWindow();
|
||||||
|
|
||||||
@ -1317,7 +1645,7 @@ TabChild::InitTabChildGlobal(FrameScriptLoading aScriptLoading)
|
|||||||
mTabChildGlobal = scope;
|
mTabChildGlobal = scope;
|
||||||
|
|
||||||
nsISupports* scopeSupports = NS_ISUPPORTS_CAST(nsIDOMEventTarget*, scope);
|
nsISupports* scopeSupports = NS_ISUPPORTS_CAST(nsIDOMEventTarget*, scope);
|
||||||
|
|
||||||
NS_ENSURE_TRUE(InitTabChildGlobalInternal(scopeSupports), false);
|
NS_ENSURE_TRUE(InitTabChildGlobalInternal(scopeSupports), false);
|
||||||
|
|
||||||
scope->Init();
|
scope->Init();
|
||||||
@ -1325,6 +1653,8 @@ TabChild::InitTabChildGlobal(FrameScriptLoading aScriptLoading)
|
|||||||
nsCOMPtr<nsPIWindowRoot> root = do_QueryInterface(chromeHandler);
|
nsCOMPtr<nsPIWindowRoot> root = do_QueryInterface(chromeHandler);
|
||||||
NS_ENSURE_TRUE(root, false);
|
NS_ENSURE_TRUE(root, false);
|
||||||
root->SetParentTarget(scope);
|
root->SetParentTarget(scope);
|
||||||
|
|
||||||
|
chromeHandler->AddEventListener(NS_LITERAL_STRING("DOMMetaAdded"), this, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (aScriptLoading != DONT_LOAD_SCRIPTS && !mTriedBrowserInit) {
|
if (aScriptLoading != DONT_LOAD_SCRIPTS && !mTriedBrowserInit) {
|
||||||
@ -1389,10 +1719,13 @@ TabChild::InitRenderingState()
|
|||||||
|
|
||||||
if (observerService) {
|
if (observerService) {
|
||||||
observerService->AddObserver(this,
|
observerService->AddObserver(this,
|
||||||
"cancel-default-pan-zoom",
|
CANCEL_DEFAULT_PAN_ZOOM,
|
||||||
false);
|
false);
|
||||||
observerService->AddObserver(this,
|
observerService->AddObserver(this,
|
||||||
"browser-zoom-to-rect",
|
BROWSER_ZOOM_TO_RECT,
|
||||||
|
false);
|
||||||
|
observerService->AddObserver(this,
|
||||||
|
BEFORE_FIRST_PAINT,
|
||||||
false);
|
false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,9 +36,11 @@
|
|||||||
#include "nsNetUtil.h"
|
#include "nsNetUtil.h"
|
||||||
#include "nsFrameMessageManager.h"
|
#include "nsFrameMessageManager.h"
|
||||||
#include "nsIScriptContext.h"
|
#include "nsIScriptContext.h"
|
||||||
|
#include "nsIWebProgressListener.h"
|
||||||
#include "nsDOMEventTargetHelper.h"
|
#include "nsDOMEventTargetHelper.h"
|
||||||
#include "nsIDialogCreator.h"
|
#include "nsIDialogCreator.h"
|
||||||
#include "nsIDialogParamBlock.h"
|
#include "nsIDialogParamBlock.h"
|
||||||
|
#include "nsIDOMWindowUtils.h"
|
||||||
#include "nsIPresShell.h"
|
#include "nsIPresShell.h"
|
||||||
#include "nsIPrincipal.h"
|
#include "nsIPrincipal.h"
|
||||||
#include "nsIScriptObjectPrincipal.h"
|
#include "nsIScriptObjectPrincipal.h"
|
||||||
@ -141,6 +143,8 @@ class TabChild : public PBrowserChild,
|
|||||||
public nsIWebBrowserChromeFocus,
|
public nsIWebBrowserChromeFocus,
|
||||||
public nsIInterfaceRequestor,
|
public nsIInterfaceRequestor,
|
||||||
public nsIWindowProvider,
|
public nsIWindowProvider,
|
||||||
|
public nsIDOMEventListener,
|
||||||
|
public nsIWebProgressListener,
|
||||||
public nsSupportsWeakReference,
|
public nsSupportsWeakReference,
|
||||||
public nsIDialogCreator,
|
public nsIDialogCreator,
|
||||||
public nsITabChild,
|
public nsITabChild,
|
||||||
@ -175,6 +179,8 @@ public:
|
|||||||
NS_DECL_NSIWEBBROWSERCHROMEFOCUS
|
NS_DECL_NSIWEBBROWSERCHROMEFOCUS
|
||||||
NS_DECL_NSIINTERFACEREQUESTOR
|
NS_DECL_NSIINTERFACEREQUESTOR
|
||||||
NS_DECL_NSIWINDOWPROVIDER
|
NS_DECL_NSIWINDOWPROVIDER
|
||||||
|
NS_DECL_NSIDOMEVENTLISTENER
|
||||||
|
NS_DECL_NSIWEBPROGRESSLISTENER
|
||||||
NS_DECL_NSIDIALOGCREATOR
|
NS_DECL_NSIDIALOGCREATOR
|
||||||
NS_DECL_NSITABCHILD
|
NS_DECL_NSITABCHILD
|
||||||
NS_DECL_NSIOBSERVER
|
NS_DECL_NSIOBSERVER
|
||||||
@ -328,6 +334,16 @@ private:
|
|||||||
// Call RecvShow(nsIntSize(0, 0)) and block future calls to RecvShow().
|
// Call RecvShow(nsIntSize(0, 0)) and block future calls to RecvShow().
|
||||||
void DoFakeShow();
|
void DoFakeShow();
|
||||||
|
|
||||||
|
// Wrapper for nsIDOMWindowUtils.setCSSViewport(). This updates some state
|
||||||
|
// variables local to this class before setting it.
|
||||||
|
void SetCSSViewport(float aX, float aY);
|
||||||
|
|
||||||
|
// Recalculates the display state, including the CSS viewport. This should
|
||||||
|
// be called whenever we believe the meta viewport data on a document may
|
||||||
|
// have changed. If it didn't change, this function doesn't do anything.
|
||||||
|
// However, it should not be called all the time as it is fairly expensive.
|
||||||
|
void HandlePossibleMetaViewportChange();
|
||||||
|
|
||||||
// Wraps up a JSON object as a structured clone and sends it to the browser
|
// Wraps up a JSON object as a structured clone and sends it to the browser
|
||||||
// chrome script.
|
// chrome script.
|
||||||
//
|
//
|
||||||
@ -347,18 +363,30 @@ private:
|
|||||||
bool* aWindowIsNew,
|
bool* aWindowIsNew,
|
||||||
nsIDOMWindow** aReturn);
|
nsIDOMWindow** aReturn);
|
||||||
|
|
||||||
|
nsIDOMWindowUtils* GetDOMWindowUtils()
|
||||||
|
{
|
||||||
|
nsCOMPtr<nsPIDOMWindow> window = do_GetInterface(mWebNav);
|
||||||
|
nsCOMPtr<nsIDOMWindowUtils> utils = do_GetInterface(window);
|
||||||
|
return utils;
|
||||||
|
}
|
||||||
|
|
||||||
nsCOMPtr<nsIWebNavigation> mWebNav;
|
nsCOMPtr<nsIWebNavigation> mWebNav;
|
||||||
nsCOMPtr<nsIWidget> mWidget;
|
nsCOMPtr<nsIWidget> mWidget;
|
||||||
|
nsCOMPtr<nsIURI> mLastURI;
|
||||||
|
FrameMetrics mLastMetrics;
|
||||||
RenderFrameChild* mRemoteFrame;
|
RenderFrameChild* mRemoteFrame;
|
||||||
nsRefPtr<TabChildGlobal> mTabChildGlobal;
|
nsRefPtr<TabChildGlobal> mTabChildGlobal;
|
||||||
uint32_t mChromeFlags;
|
uint32_t mChromeFlags;
|
||||||
nsIntRect mOuterRect;
|
nsIntRect mOuterRect;
|
||||||
|
nsIntSize mInnerSize;
|
||||||
|
float mOldViewportWidth;
|
||||||
nscolor mLastBackgroundColor;
|
nscolor mLastBackgroundColor;
|
||||||
ScrollingBehavior mScrolling;
|
ScrollingBehavior mScrolling;
|
||||||
uint32_t mAppId;
|
uint32_t mAppId;
|
||||||
bool mDidFakeShow;
|
bool mDidFakeShow;
|
||||||
bool mIsBrowserElement;
|
bool mIsBrowserElement;
|
||||||
bool mNotified;
|
bool mNotified;
|
||||||
|
bool mContentDocumentIsDisplayed;
|
||||||
bool mTriedBrowserInit;
|
bool mTriedBrowserInit;
|
||||||
|
|
||||||
DISALLOW_EVIL_CONSTRUCTORS(TabChild);
|
DISALLOW_EVIL_CONSTRUCTORS(TabChild);
|
||||||
|
@ -83,6 +83,7 @@ TabParent::TabParent(mozIApplication* aApp, bool aIsBrowserElement)
|
|||||||
, mIMECompositionStart(0)
|
, mIMECompositionStart(0)
|
||||||
, mIMESeqno(0)
|
, mIMESeqno(0)
|
||||||
, mEventCaptureDepth(0)
|
, mEventCaptureDepth(0)
|
||||||
|
, mDimensions(0, 0)
|
||||||
, mDPI(0)
|
, mDPI(0)
|
||||||
, mIsBrowserElement(aIsBrowserElement)
|
, mIsBrowserElement(aIsBrowserElement)
|
||||||
, mShown(false)
|
, mShown(false)
|
||||||
@ -229,6 +230,7 @@ TabParent::Show(const nsIntSize& size)
|
|||||||
{
|
{
|
||||||
// sigh
|
// sigh
|
||||||
mShown = true;
|
mShown = true;
|
||||||
|
mDimensions = size;
|
||||||
unused << SendShow(size);
|
unused << SendShow(size);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -239,6 +241,7 @@ TabParent::UpdateDimensions(const nsRect& rect, const nsIntSize& size)
|
|||||||
if (RenderFrameParent* rfp = GetRenderFrame()) {
|
if (RenderFrameParent* rfp = GetRenderFrame()) {
|
||||||
rfp->NotifyDimensionsChanged(size.width, size.height);
|
rfp->NotifyDimensionsChanged(size.width, size.height);
|
||||||
}
|
}
|
||||||
|
mDimensions = size;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -1172,6 +1175,21 @@ TabParent::RecvBrowserFrameOpenWindow(PBrowserParent* aOpener,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
TabParent::RecvPRenderFrameConstructor(PRenderFrameParent* actor,
|
||||||
|
ScrollingBehavior* scrolling,
|
||||||
|
LayersBackend* backend,
|
||||||
|
int32_t* maxTextureSize,
|
||||||
|
uint64_t* layersId)
|
||||||
|
{
|
||||||
|
RenderFrameParent* rfp = GetRenderFrame();
|
||||||
|
if (mDimensions != nsIntSize() && rfp) {
|
||||||
|
rfp->NotifyDimensionsChanged(mDimensions.width, mDimensions.height);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
TabParent::RecvZoomToRect(const gfxRect& aRect)
|
TabParent::RecvZoomToRect(const gfxRect& aRect)
|
||||||
{
|
{
|
||||||
@ -1181,6 +1199,17 @@ TabParent::RecvZoomToRect(const gfxRect& aRect)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
TabParent::RecvUpdateZoomConstraints(const bool& aAllowZoom,
|
||||||
|
const float& aMinZoom,
|
||||||
|
const float& aMaxZoom)
|
||||||
|
{
|
||||||
|
if (RenderFrameParent* rfp = GetRenderFrame()) {
|
||||||
|
rfp->UpdateZoomConstraints(aAllowZoom, aMinZoom, aMaxZoom);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
TabParent::RecvContentReceivedTouch(const bool& aPreventDefault)
|
TabParent::RecvContentReceivedTouch(const bool& aPreventDefault)
|
||||||
{
|
{
|
||||||
|
@ -94,6 +94,11 @@ public:
|
|||||||
|
|
||||||
virtual bool RecvMoveFocus(const bool& aForward);
|
virtual bool RecvMoveFocus(const bool& aForward);
|
||||||
virtual bool RecvEvent(const RemoteDOMEvent& aEvent);
|
virtual bool RecvEvent(const RemoteDOMEvent& aEvent);
|
||||||
|
virtual bool RecvPRenderFrameConstructor(PRenderFrameParent* actor,
|
||||||
|
ScrollingBehavior* scrolling,
|
||||||
|
LayersBackend* backend,
|
||||||
|
int32_t* maxTextureSize,
|
||||||
|
uint64_t* layersId);
|
||||||
virtual bool RecvBrowserFrameOpenWindow(PBrowserParent* aOpener,
|
virtual bool RecvBrowserFrameOpenWindow(PBrowserParent* aOpener,
|
||||||
const nsString& aURL,
|
const nsString& aURL,
|
||||||
const nsString& aName,
|
const nsString& aName,
|
||||||
@ -131,6 +136,9 @@ public:
|
|||||||
virtual bool RecvGetDPI(float* aValue);
|
virtual bool RecvGetDPI(float* aValue);
|
||||||
virtual bool RecvGetWidgetNativeData(WindowsHandle* aValue);
|
virtual bool RecvGetWidgetNativeData(WindowsHandle* aValue);
|
||||||
virtual bool RecvZoomToRect(const gfxRect& aRect);
|
virtual bool RecvZoomToRect(const gfxRect& aRect);
|
||||||
|
virtual bool RecvUpdateZoomConstraints(const bool& aAllowZoom,
|
||||||
|
const float& aMinZoom,
|
||||||
|
const float& aMaxZoom);
|
||||||
virtual bool RecvContentReceivedTouch(const bool& aPreventDefault);
|
virtual bool RecvContentReceivedTouch(const bool& aPreventDefault);
|
||||||
virtual PContentDialogParent* AllocPContentDialog(const uint32_t& aType,
|
virtual PContentDialogParent* AllocPContentDialog(const uint32_t& aType,
|
||||||
const nsCString& aName,
|
const nsCString& aName,
|
||||||
@ -269,6 +277,7 @@ protected:
|
|||||||
// The number of event series we're currently capturing.
|
// The number of event series we're currently capturing.
|
||||||
int32_t mEventCaptureDepth;
|
int32_t mEventCaptureDepth;
|
||||||
|
|
||||||
|
nsIntSize mDimensions;
|
||||||
float mDPI;
|
float mDPI;
|
||||||
bool mIsBrowserElement;
|
bool mIsBrowserElement;
|
||||||
bool mShown;
|
bool mShown;
|
||||||
|
@ -14,7 +14,7 @@ interface nsIDOMWindow;
|
|||||||
* XPCOM component (in the content process) that provides the mobile
|
* XPCOM component (in the content process) that provides the mobile
|
||||||
* network information.
|
* network information.
|
||||||
*/
|
*/
|
||||||
[scriptable, uuid(63787ba1-5091-450b-8810-d321a8b4f77a)]
|
[scriptable, uuid(bc1a82aa-2a1f-4a27-a5e7-614d06b72e0a)]
|
||||||
interface nsIMobileConnectionProvider : nsISupports
|
interface nsIMobileConnectionProvider : nsISupports
|
||||||
{
|
{
|
||||||
readonly attribute DOMString cardState;
|
readonly attribute DOMString cardState;
|
||||||
@ -40,4 +40,6 @@ interface nsIMobileConnectionProvider : nsISupports
|
|||||||
void sendStkMenuSelection(in nsIDOMWindow window,
|
void sendStkMenuSelection(in nsIDOMWindow window,
|
||||||
in unsigned short itemIdentifier,
|
in unsigned short itemIdentifier,
|
||||||
in boolean helpRequested);
|
in boolean helpRequested);
|
||||||
|
void sendStkEventDownload(in nsIDOMWindow window,
|
||||||
|
in jsval event);
|
||||||
};
|
};
|
||||||
|
@ -453,6 +453,15 @@ RILContentHelper.prototype = {
|
|||||||
helpRequested: helpRequested});
|
helpRequested: helpRequested});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
sendStkEventDownload: function sendStkEventDownload(window,
|
||||||
|
event) {
|
||||||
|
if (window == null) {
|
||||||
|
throw Components.Exception("Can't get window object",
|
||||||
|
Cr.NS_ERROR_UNEXPECTED);
|
||||||
|
}
|
||||||
|
cpmm.sendAsyncMessage("RIL:SendStkEventDownload", {event: event});
|
||||||
|
},
|
||||||
|
|
||||||
_telephonyCallbacks: null,
|
_telephonyCallbacks: null,
|
||||||
_voicemailCallbacks: null,
|
_voicemailCallbacks: null,
|
||||||
_enumerateTelephonyCallbacks: null,
|
_enumerateTelephonyCallbacks: null,
|
||||||
|
@ -73,6 +73,7 @@ const RIL_IPC_MOBILECONNECTION_MSG_NAMES = [
|
|||||||
"RIL:CancelUSSD",
|
"RIL:CancelUSSD",
|
||||||
"RIL:SendStkResponse",
|
"RIL:SendStkResponse",
|
||||||
"RIL:SendStkMenuSelection",
|
"RIL:SendStkMenuSelection",
|
||||||
|
"RIL:SendStkEventDownload",
|
||||||
];
|
];
|
||||||
|
|
||||||
XPCOMUtils.defineLazyServiceGetter(this, "gSmsService",
|
XPCOMUtils.defineLazyServiceGetter(this, "gSmsService",
|
||||||
@ -384,6 +385,9 @@ RadioInterfaceLayer.prototype = {
|
|||||||
case "RIL:SendStkMenuSelection":
|
case "RIL:SendStkMenuSelection":
|
||||||
this.sendStkMenuSelection(msg.json);
|
this.sendStkMenuSelection(msg.json);
|
||||||
break;
|
break;
|
||||||
|
case "RIL:SendStkEventDownload":
|
||||||
|
this.sendStkEventDownload(msg.json);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -1530,6 +1534,11 @@ RadioInterfaceLayer.prototype = {
|
|||||||
this.worker.postMessage(message);
|
this.worker.postMessage(message);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
sendStkEventDownload: function sendStkEventDownload(message) {
|
||||||
|
message.rilMessageType = "sendStkEventDownload";
|
||||||
|
this.worker.postMessage(message);
|
||||||
|
},
|
||||||
|
|
||||||
get microphoneMuted() {
|
get microphoneMuted() {
|
||||||
return gAudioManager.microphoneMuted;
|
return gAudioManager.microphoneMuted;
|
||||||
},
|
},
|
||||||
|
@ -537,11 +537,15 @@ const COMPREHENSIONTLV_TAG_ALPHA_ID = 0x05;
|
|||||||
const COMPREHENSIONTLV_TAG_ADDRESS = 0x06;
|
const COMPREHENSIONTLV_TAG_ADDRESS = 0x06;
|
||||||
const COMPREHENSIONTLV_TAG_SMS_TPDU = 0x0b;
|
const COMPREHENSIONTLV_TAG_SMS_TPDU = 0x0b;
|
||||||
const COMPREHENSIONTLV_TAG_TEXT_STRING = 0x0d;
|
const COMPREHENSIONTLV_TAG_TEXT_STRING = 0x0d;
|
||||||
|
const COMPREHENSIONTLV_TAG_TONE = 0x0e;
|
||||||
const COMPREHENSIONTLV_TAG_ITEM = 0x0f;
|
const COMPREHENSIONTLV_TAG_ITEM = 0x0f;
|
||||||
const COMPREHENSIONTLV_TAG_ITEM_ID = 0x10;
|
const COMPREHENSIONTLV_TAG_ITEM_ID = 0x10;
|
||||||
const COMPREHENSIONTLV_TAG_RESPONSE_LENGTH = 0x11;
|
const COMPREHENSIONTLV_TAG_RESPONSE_LENGTH = 0x11;
|
||||||
|
const COMPREHENSIONTLV_TAG_FILE_LIST = 0x12;
|
||||||
|
const COMPREHENSIONTLV_TAG_LOCATION_INFO = 0x13;
|
||||||
const COMPREHENSIONTLV_TAG_HELP_REQUEST = 0x15;
|
const COMPREHENSIONTLV_TAG_HELP_REQUEST = 0x15;
|
||||||
const COMPREHENSIONTLV_TAG_DEFAULT_TEXT = 0x17;
|
const COMPREHENSIONTLV_TAG_DEFAULT_TEXT = 0x17;
|
||||||
|
const COMPREHENSIONTLV_TAG_LOCATION_STATUS = 0x1b;
|
||||||
const COMPREHENSIONTLV_TAG_EVENT_LIST = 0x19;
|
const COMPREHENSIONTLV_TAG_EVENT_LIST = 0x19;
|
||||||
const COMPREHENSIONTLV_TAG_ICON_ID = 0x1e;
|
const COMPREHENSIONTLV_TAG_ICON_ID = 0x1e;
|
||||||
const COMPREHENSIONTLV_TAG_ICON_ID_LIST = 0x1f;
|
const COMPREHENSIONTLV_TAG_ICON_ID_LIST = 0x1f;
|
||||||
@ -558,6 +562,8 @@ const STK_DEVICE_ID_NETWORK = 0x83;
|
|||||||
|
|
||||||
// STK Proactive commands.
|
// STK Proactive commands.
|
||||||
const STK_CMD_REFRESH = 0x01;
|
const STK_CMD_REFRESH = 0x01;
|
||||||
|
const STK_CMD_POLL_INTERVAL = 0x03;
|
||||||
|
const STK_CMD_POLL_OFF = 0x04;
|
||||||
const STK_CMD_SET_UP_EVENT_LIST = 0x05;
|
const STK_CMD_SET_UP_EVENT_LIST = 0x05;
|
||||||
const STK_CMD_SET_UP_CALL = 0x10;
|
const STK_CMD_SET_UP_CALL = 0x10;
|
||||||
const STK_CMD_SEND_SS = 0x11;
|
const STK_CMD_SEND_SS = 0x11;
|
||||||
@ -565,6 +571,7 @@ const STK_CMD_SEND_USSD = 0x12;
|
|||||||
const STK_CMD_SEND_SMS = 0x13;
|
const STK_CMD_SEND_SMS = 0x13;
|
||||||
const STK_CMD_SEND_DTMF = 0x14;
|
const STK_CMD_SEND_DTMF = 0x14;
|
||||||
const STK_CMD_LAUNCH_BROWSER = 0x15;
|
const STK_CMD_LAUNCH_BROWSER = 0x15;
|
||||||
|
const STK_CMD_PLAY_TONE = 0x20;
|
||||||
const STK_CMD_DISPLAY_TEXT = 0x21;
|
const STK_CMD_DISPLAY_TEXT = 0x21;
|
||||||
const STK_CMD_GET_INKEY = 0x22;
|
const STK_CMD_GET_INKEY = 0x22;
|
||||||
const STK_CMD_GET_INPUT = 0x23;
|
const STK_CMD_GET_INPUT = 0x23;
|
||||||
@ -725,6 +732,36 @@ const STK_EVENT_TYPE_LOCAL_CONNECTION = 0x0d;
|
|||||||
const STK_EVENT_TYPE_NETWORK_SEARCH_MODE_CHANGED = 0x0e;
|
const STK_EVENT_TYPE_NETWORK_SEARCH_MODE_CHANGED = 0x0e;
|
||||||
const STK_EVENT_TYPE_BROWSING_STATUS = 0x0f;
|
const STK_EVENT_TYPE_BROWSING_STATUS = 0x0f;
|
||||||
|
|
||||||
|
// STK Service state of Location Status.
|
||||||
|
const STK_SERVICE_STATE_NORMAL = 0x00;
|
||||||
|
const STK_SERVICE_STATE_LIMITED = 0x01;
|
||||||
|
const STK_SERVICE_STATE_UNAVAILABLE = 0x02;
|
||||||
|
|
||||||
|
// Refresh mode.
|
||||||
|
const STK_REFRESH_NAA_INIT_AND_FULL_FILE_CHANGE = 0x00;
|
||||||
|
const STK_REFRESH_FILE_CHANGE = 0x01;
|
||||||
|
const STK_REFRESH_NAA_INIT_AND_FILE_CHANGE = 0x02;
|
||||||
|
const STK_REFRESH_NAA_INIT = 0x03;
|
||||||
|
const STK_REFRESH_UICC_RESET = 0x04;
|
||||||
|
|
||||||
|
// Tone type.
|
||||||
|
const STK_TONE_TYPE_DIAL_TONE = 0x01;
|
||||||
|
const STK_TONE_TYPE_CALLED_SUBSCRIBER_BUSY = 0x02;
|
||||||
|
const STK_TONE_TYPE_CONGESTION = 0x03;
|
||||||
|
const STK_TONE_TYPE_RADIO_PATH_ACK = 0x04;
|
||||||
|
const STK_TONE_TYPE_RADIO_PATH_NOT_AVAILABLE = 0x05;
|
||||||
|
const STK_TONE_TYPE_ERROR = 0x06;
|
||||||
|
const STK_TONE_TYPE_CALL_WAITING_TONE = 0x07;
|
||||||
|
const STK_TONE_TYPE_RINGING_TONE = 0x08;
|
||||||
|
const STK_TONE_TYPE_GENERAL_BEEP = 0x10;
|
||||||
|
const STK_TONE_TYPE_POSITIVE_ACK_TONE = 0x11;
|
||||||
|
const STK_TONE_TYPE_NEGATIVE_ACK_TONE = 0x12;
|
||||||
|
|
||||||
|
// Time unit.
|
||||||
|
const STK_TIME_UNIT_MINUTE = 0x00;
|
||||||
|
const STK_TIME_UNIT_SECOND = 0x01;
|
||||||
|
const STK_TIME_UNIT_TENTH_SECOND = 0x02;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* (U)SIM Services.
|
* (U)SIM Services.
|
||||||
*
|
*
|
||||||
|
@ -51,6 +51,16 @@ const PARCEL_SIZE_SIZE = UINT32_SIZE;
|
|||||||
|
|
||||||
const PDU_HEX_OCTET_SIZE = 4;
|
const PDU_HEX_OCTET_SIZE = 4;
|
||||||
|
|
||||||
|
const TLV_COMMAND_DETAILS_SIZE = 5;
|
||||||
|
const TLV_DEVICE_ID_SIZE = 4;
|
||||||
|
const TLV_RESULT_SIZE = 3;
|
||||||
|
const TLV_ITEM_ID_SIZE = 3;
|
||||||
|
const TLV_HELP_REQUESTED_SIZE = 2;
|
||||||
|
const TLV_EVENT_LIST_SIZE = 3;
|
||||||
|
const TLV_LOCATION_STATUS_SIZE = 3;
|
||||||
|
const TLV_LOCATION_INFO_GSM_SIZE = 9;
|
||||||
|
const TLV_LOCATION_INFO_UMTS_SIZE = 11;
|
||||||
|
|
||||||
const DEFAULT_EMERGENCY_NUMBERS = ["112", "911"];
|
const DEFAULT_EMERGENCY_NUMBERS = ["112", "911"];
|
||||||
|
|
||||||
let RILQUIRKS_CALLSTATE_EXTRA_UINT32 = libcutils.property_get("ro.moz.ril.callstate_extra_int");
|
let RILQUIRKS_CALLSTATE_EXTRA_UINT32 = libcutils.property_get("ro.moz.ril.callstate_extra_int");
|
||||||
@ -2257,10 +2267,10 @@ let RIL = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 1 octets = 2 chars.
|
// 1 octets = 2 chars.
|
||||||
let size = (5 + /* Size of Command Details TLV */
|
let size = (TLV_COMMAND_DETAILS_SIZE +
|
||||||
4 + /* Size of Device Identifier TLV */
|
TLV_DEVICE_ID_SIZE +
|
||||||
3 + /* Size of Result */
|
TLV_RESULT_SIZE +
|
||||||
(response.itemIdentifier ? 3 : 0) +
|
(response.itemIdentifier ? TLV_ITEM_ID_SIZE : 0) +
|
||||||
(textLen ? textLen + 3 : 0)) * 2;
|
(textLen ? textLen + 3 : 0)) * 2;
|
||||||
Buf.writeUint32(size);
|
Buf.writeUint32(size);
|
||||||
|
|
||||||
@ -2365,6 +2375,29 @@ let RIL = {
|
|||||||
this.sendICCEnvelopeCommand(command);
|
this.sendICCEnvelopeCommand(command);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send STK Envelope(Event Download) command.
|
||||||
|
* @param event
|
||||||
|
*/
|
||||||
|
sendStkEventDownload: function sendStkEventDownload(command) {
|
||||||
|
command.tag = BER_EVENT_DOWNLOAD_TAG;
|
||||||
|
command.eventList = command.event.eventType;
|
||||||
|
switch (command.eventList) {
|
||||||
|
case STK_EVENT_TYPE_LOCATION_STATUS:
|
||||||
|
command.deviceId = {
|
||||||
|
sourceId :STK_DEVICE_ID_ME,
|
||||||
|
destinationId: STK_DEVICE_ID_SIM
|
||||||
|
};
|
||||||
|
command.locationStatus = command.event.locationStatus;
|
||||||
|
// Location info should only be provided when locationStatus is normal.
|
||||||
|
if (command.locationStatus == STK_SERVICE_STATE_NORMAL) {
|
||||||
|
command.locationInfo = command.event.locationInfo;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
this.sendICCEnvelopeCommand(command);
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Send REQUEST_STK_SEND_ENVELOPE_COMMAND to ICC.
|
* Send REQUEST_STK_SEND_ENVELOPE_COMMAND to ICC.
|
||||||
*
|
*
|
||||||
@ -2372,12 +2405,25 @@ let RIL = {
|
|||||||
* @patam deviceId
|
* @patam deviceId
|
||||||
* @param [optioanl] itemIdentifier
|
* @param [optioanl] itemIdentifier
|
||||||
* @param [optional] helpRequested
|
* @param [optional] helpRequested
|
||||||
|
* @param [optional] eventList
|
||||||
|
* @param [optional] locationStatus
|
||||||
|
* @param [optional] locationInfo
|
||||||
*/
|
*/
|
||||||
sendICCEnvelopeCommand: function sendICCEnvelopeCommand(options) {
|
sendICCEnvelopeCommand: function sendICCEnvelopeCommand(options) {
|
||||||
|
if (DEBUG) {
|
||||||
|
debug("Stk Envelope " + JSON.stringify(options));
|
||||||
|
}
|
||||||
let token = Buf.newParcel(REQUEST_STK_SEND_ENVELOPE_COMMAND);
|
let token = Buf.newParcel(REQUEST_STK_SEND_ENVELOPE_COMMAND);
|
||||||
let berLen = 4 + /* Size of Device Identifier TLV */
|
let berLen = TLV_DEVICE_ID_SIZE + /* Size of Device Identifier TLV */
|
||||||
(options.itemIdentifier ? 3 : 0) +
|
(options.itemIdentifier ? TLV_ITEM_ID_SIZE : 0) +
|
||||||
(options.helpRequested ? 2 : 0);
|
(options.helpRequested ? TLV_HELP_REQUESTED_SIZE : 0) +
|
||||||
|
(options.eventList ? TLV_EVENT_LIST_SIZE : 0) +
|
||||||
|
(options.locationStatus ? TLV_LOCATION_STATUS_SIZE : 0) +
|
||||||
|
(options.locationInfo ?
|
||||||
|
(options.locationInfo.gsmCellId > 0xffff ?
|
||||||
|
TLV_LOCATION_INFO_UMTS_SIZE :
|
||||||
|
TLV_LOCATION_INFO_GSM_SIZE) :
|
||||||
|
0);
|
||||||
let size = (2 + berLen) * 2;
|
let size = (2 + berLen) * 2;
|
||||||
|
|
||||||
Buf.writeUint32(size);
|
Buf.writeUint32(size);
|
||||||
@ -2409,6 +2455,28 @@ let RIL = {
|
|||||||
// Help Request doesn't have value
|
// Help Request doesn't have value
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Event List
|
||||||
|
if (options.eventList) {
|
||||||
|
GsmPDUHelper.writeHexOctet(COMPREHENSIONTLV_TAG_EVENT_LIST |
|
||||||
|
COMPREHENSIONTLV_FLAG_CR);
|
||||||
|
GsmPDUHelper.writeHexOctet(1);
|
||||||
|
GsmPDUHelper.writeHexOctet(options.eventList);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Location Status
|
||||||
|
if (options.locationStatus) {
|
||||||
|
let len = options.locationStatus.length;
|
||||||
|
GsmPDUHelper.writeHexOctet(COMPREHENSIONTLV_TAG_LOCATION_STATUS |
|
||||||
|
COMPREHENSIONTLV_FLAG_CR);
|
||||||
|
GsmPDUHelper.writeHexOctet(1);
|
||||||
|
GsmPDUHelper.writeHexOctet(options.locationStatus);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Location Info
|
||||||
|
if (options.locationInfo) {
|
||||||
|
ComprehensionTlvHelper.writeLocationInfoTlv(options.locationInfo);
|
||||||
|
}
|
||||||
|
|
||||||
Buf.writeUint32(0);
|
Buf.writeUint32(0);
|
||||||
Buf.sendParcel();
|
Buf.sendParcel();
|
||||||
},
|
},
|
||||||
@ -6006,6 +6074,15 @@ let StkCommandParamsFactory = {
|
|||||||
createParam: function createParam(cmdDetails, ctlvs) {
|
createParam: function createParam(cmdDetails, ctlvs) {
|
||||||
let param;
|
let param;
|
||||||
switch (cmdDetails.typeOfCommand) {
|
switch (cmdDetails.typeOfCommand) {
|
||||||
|
case STK_CMD_REFRESH:
|
||||||
|
param = this.processRefresh(cmdDetails, ctlvs);
|
||||||
|
break;
|
||||||
|
case STK_CMD_POLL_INTERVAL:
|
||||||
|
param = this.processPollInterval(cmdDetails, ctlvs);
|
||||||
|
break;
|
||||||
|
case STK_CMD_POLL_OFF:
|
||||||
|
param = this.processPollOff(cmdDetails, ctlvs);
|
||||||
|
break;
|
||||||
case STK_CMD_SET_UP_EVENT_LIST:
|
case STK_CMD_SET_UP_EVENT_LIST:
|
||||||
param = this.processSetUpEventList(cmdDetails, ctlvs);
|
param = this.processSetUpEventList(cmdDetails, ctlvs);
|
||||||
break;
|
break;
|
||||||
@ -6034,9 +6111,12 @@ let StkCommandParamsFactory = {
|
|||||||
case STK_CMD_SET_UP_CALL:
|
case STK_CMD_SET_UP_CALL:
|
||||||
param = this.processSetupCall(cmdDetails, ctlvs);
|
param = this.processSetupCall(cmdDetails, ctlvs);
|
||||||
break;
|
break;
|
||||||
case STK_LAUNCH_BROWSER:
|
case STK_CMD_LAUNCH_BROWSER:
|
||||||
param = this.processLaunchBrowser(cmdDetails, ctlvs);
|
param = this.processLaunchBrowser(cmdDetails, ctlvs);
|
||||||
break;
|
break;
|
||||||
|
case STK_CMD_PLAY_TONE:
|
||||||
|
param = this.processPlayTone(cmdDetails, ctlvs);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
debug("unknown proactive command");
|
debug("unknown proactive command");
|
||||||
break;
|
break;
|
||||||
@ -6044,6 +6124,66 @@ let StkCommandParamsFactory = {
|
|||||||
return param;
|
return param;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct a param for Refresh.
|
||||||
|
*
|
||||||
|
* @param cmdDetails
|
||||||
|
* The value object of CommandDetails TLV.
|
||||||
|
* @param ctlvs
|
||||||
|
* The all TLVs in this proactive command.
|
||||||
|
*/
|
||||||
|
processRefresh: function processRefresh(cmdDetails, ctlvs) {
|
||||||
|
let refreshType = cmdDetails.commandQualifier;
|
||||||
|
switch (refreshType) {
|
||||||
|
case STK_REFRESH_FILE_CHANGE:
|
||||||
|
case STK_REFRESH_NAA_INIT_AND_FILE_CHANGE:
|
||||||
|
let ctlv = StkProactiveCmdHelper.searchForTag(
|
||||||
|
COMPREHENSIONTLV_FILE_LIST, ctlvs);
|
||||||
|
if (ctlv) {
|
||||||
|
let list = ctlv.value.fileList;
|
||||||
|
if (DEBUG) {
|
||||||
|
debug("Refresh, list = " + list);
|
||||||
|
}
|
||||||
|
RIL.fetchICCRecords();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct a param for Poll Interval.
|
||||||
|
*
|
||||||
|
* @param cmdDetails
|
||||||
|
* The value object of CommandDetails TLV.
|
||||||
|
* @param ctlvs
|
||||||
|
* The all TLVs in this proactive command.
|
||||||
|
*/
|
||||||
|
processPollInterval: function processPollInterval(cmdDetails, ctlvs) {
|
||||||
|
let ctlv = StkProactiveCmdHelper.searchForTag(
|
||||||
|
COMPREHENSIONTLV_TAG_DURATION, ctlvs);
|
||||||
|
if (!ctlv) {
|
||||||
|
RIL.sendStkTerminalResponse({
|
||||||
|
command: cmdDetails,
|
||||||
|
resultCode: STK_RESULT_REQUIRED_VALUES_MISSING});
|
||||||
|
throw new Error("Stk Poll Interval: Required value missing : Duration");
|
||||||
|
}
|
||||||
|
|
||||||
|
return ctlv.value;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct a param for Poll Off.
|
||||||
|
*
|
||||||
|
* @param cmdDetails
|
||||||
|
* The value object of CommandDetails TLV.
|
||||||
|
* @param ctlvs
|
||||||
|
* The all TLVs in this proactive command.
|
||||||
|
*/
|
||||||
|
processPollOff: function processPollOff(cmdDetails, ctlvs) {
|
||||||
|
return {};
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct a param for Set Up Event list.
|
* Construct a param for Set Up Event list.
|
||||||
*
|
*
|
||||||
@ -6309,6 +6449,32 @@ let StkCommandParamsFactory = {
|
|||||||
browser.mode = cmdDetails.commandQualifier & 0x03;
|
browser.mode = cmdDetails.commandQualifier & 0x03;
|
||||||
|
|
||||||
return browser;
|
return browser;
|
||||||
|
},
|
||||||
|
|
||||||
|
processPlayTone: function processPlayTone(cmdDetails, ctlvs) {
|
||||||
|
let playTone = {};
|
||||||
|
|
||||||
|
let ctlv = StkProactiveCmdHelper.searchForTag(
|
||||||
|
COMPREHENSIONTLV_TAG_ALPHA_ID, ctlvs);
|
||||||
|
if (ctlv) {
|
||||||
|
playTone.text = ctlv.value.identifier;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctlv = StkProactiveCmdHelper.searchForTag(COMPREHENSIONTLV_TAG_TONE, ctlvs);
|
||||||
|
if (ctlv) {
|
||||||
|
playTone.tone = ctlv.value.tone;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctlv = StkProactiveCmdHelper.searchForTag(
|
||||||
|
COMPREHENSIONTLV_TAG_DURATION, ctlvs);
|
||||||
|
if (ctlv) {
|
||||||
|
playTone.duration = ctlv.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
// vibrate is only defined in TS 102.223
|
||||||
|
playTone.isVibrate = (cmdDetails.commandQualifier & 0x01) != 0x00;
|
||||||
|
|
||||||
|
return playTone;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -6321,16 +6487,22 @@ let StkProactiveCmdHelper = {
|
|||||||
return this.retrieveDeviceId(length);
|
return this.retrieveDeviceId(length);
|
||||||
case COMPREHENSIONTLV_TAG_ALPHA_ID:
|
case COMPREHENSIONTLV_TAG_ALPHA_ID:
|
||||||
return this.retrieveAlphaId(length);
|
return this.retrieveAlphaId(length);
|
||||||
|
case COMPREHENSIONTLV_TAG_DURATION:
|
||||||
|
return this.retrieveDuration(length);
|
||||||
case COMPREHENSIONTLV_TAG_ADDRESS:
|
case COMPREHENSIONTLV_TAG_ADDRESS:
|
||||||
return this.retrieveAddress(length);
|
return this.retrieveAddress(length);
|
||||||
case COMPREHENSIONTLV_TAG_TEXT_STRING:
|
case COMPREHENSIONTLV_TAG_TEXT_STRING:
|
||||||
return this.retrieveTextString(length);
|
return this.retrieveTextString(length);
|
||||||
|
case COMPREHENSIONTLV_TAG_TONE:
|
||||||
|
return this.retrieveTone(length);
|
||||||
case COMPREHENSIONTLV_TAG_ITEM:
|
case COMPREHENSIONTLV_TAG_ITEM:
|
||||||
return this.retrieveItem(length);
|
return this.retrieveItem(length);
|
||||||
case COMPREHENSIONTLV_TAG_ITEM_ID:
|
case COMPREHENSIONTLV_TAG_ITEM_ID:
|
||||||
return this.retrieveItemId(length);
|
return this.retrieveItemId(length);
|
||||||
case COMPREHENSIONTLV_TAG_RESPONSE_LENGTH:
|
case COMPREHENSIONTLV_TAG_RESPONSE_LENGTH:
|
||||||
return this.retrieveResponseLength(length);
|
return this.retrieveResponseLength(length);
|
||||||
|
case COMPREHENSIONTLV_TAG_FILE_LIST:
|
||||||
|
return this.retrieveFileList(length);
|
||||||
case COMPREHENSIONTLV_TAG_DEFAULT_TEXT:
|
case COMPREHENSIONTLV_TAG_DEFAULT_TEXT:
|
||||||
return this.retrieveDefaultText(length);
|
return this.retrieveDefaultText(length);
|
||||||
case COMPREHENSIONTLV_TAG_EVENT_LIST:
|
case COMPREHENSIONTLV_TAG_EVENT_LIST:
|
||||||
@ -6398,6 +6570,23 @@ let StkProactiveCmdHelper = {
|
|||||||
return alphaId;
|
return alphaId;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Duration.
|
||||||
|
*
|
||||||
|
* | Byte | Description | Length |
|
||||||
|
* | 1 | Response Length Tag | 1 |
|
||||||
|
* | 2 | Lenth = 02 | 1 |
|
||||||
|
* | 3 | Time unit | 1 |
|
||||||
|
* | 4 | Time interval | 1 |
|
||||||
|
*/
|
||||||
|
retrieveDuration: function retrieveDuration(length) {
|
||||||
|
let duration = {
|
||||||
|
timeUnit: GsmPDUHelper.readHexOctet(),
|
||||||
|
timeInterval: GsmPDUHelper.readHexOctet(),
|
||||||
|
};
|
||||||
|
return duration;
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Address.
|
* Address.
|
||||||
*
|
*
|
||||||
@ -6450,6 +6639,21 @@ let StkProactiveCmdHelper = {
|
|||||||
return text;
|
return text;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tone.
|
||||||
|
*
|
||||||
|
* | Byte | Description | Length |
|
||||||
|
* | 1 | Tone Tag | 1 |
|
||||||
|
* | 2 | Lenth = 01 | 1 |
|
||||||
|
* | 3 | Tone | 1 |
|
||||||
|
*/
|
||||||
|
retrieveTone: function retrieveTone(length) {
|
||||||
|
let tone = {
|
||||||
|
tone: GsmPDUHelper.readHexOctet(),
|
||||||
|
};
|
||||||
|
return tone;
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Item.
|
* Item.
|
||||||
*
|
*
|
||||||
@ -6500,6 +6704,30 @@ let StkProactiveCmdHelper = {
|
|||||||
return rspLength;
|
return rspLength;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* File List.
|
||||||
|
*
|
||||||
|
* | Byte | Description | Length |
|
||||||
|
* | 1 | File List Tag | 1 |
|
||||||
|
* | 2 ~ (Y-1)+2 | Length (X) | Y |
|
||||||
|
* | (Y-1)+3 | Number of files | 1 |
|
||||||
|
* | (Y-1)+4 ~ | Files | X |
|
||||||
|
* | (Y-1)+X+2 | | |
|
||||||
|
*/
|
||||||
|
retrieveFileList: function retrieveFileList(length) {
|
||||||
|
let num = GsmPDUHelper.readHexOctet();
|
||||||
|
let fileList = "";
|
||||||
|
length--; // -1 for the num octet.
|
||||||
|
for (let i = 0; i < 2 * length; i++) {
|
||||||
|
// Didn't use readHexOctet here,
|
||||||
|
// otherwise 0x00 will be "0", not "00"
|
||||||
|
fileList += String.fromCharCode(Buf.readUint16());
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
fileList: fileList
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Default Text.
|
* Default Text.
|
||||||
*
|
*
|
||||||
@ -6669,7 +6897,68 @@ let ComprehensionTlvHelper = {
|
|||||||
index += tlv.hlen;
|
index += tlv.hlen;
|
||||||
}
|
}
|
||||||
return chunks;
|
return chunks;
|
||||||
}
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write Location Info Comprehension TLV.
|
||||||
|
*
|
||||||
|
* @param loc location Information.
|
||||||
|
*/
|
||||||
|
writeLocationInfoTlv: function writeLocationInfoTlv(loc) {
|
||||||
|
GsmPDUHelper.writeHexOctet(COMPREHENSIONTLV_TAG_LOCATION_INFO |
|
||||||
|
COMPREHENSIONTLV_FLAG_CR);
|
||||||
|
GsmPDUHelper.writeHexOctet(loc.gsmCellId > 0xffff ? 9 : 7);
|
||||||
|
// From TS 11.14, clause 12.19
|
||||||
|
// "The mobile country code (MCC), the mobile network code (MNC),
|
||||||
|
// the location area code (LAC) and the cell ID are
|
||||||
|
// coded as in TS 04.08."
|
||||||
|
// And from TS 04.08 and TS 24.008,
|
||||||
|
// the format is as follows:
|
||||||
|
//
|
||||||
|
// MCC = MCC_digit_1 + MCC_digit_2 + MCC_digit_3
|
||||||
|
//
|
||||||
|
// 8 7 6 5 4 3 2 1
|
||||||
|
// +-------------+-------------+
|
||||||
|
// | MCC digit 2 | MCC digit 1 | octet 2
|
||||||
|
// | MNC digit 3 | MCC digit 3 | octet 3
|
||||||
|
// | MNC digit 2 | MNC digit 1 | octet 4
|
||||||
|
// +-------------+-------------+
|
||||||
|
//
|
||||||
|
// Also in TS 24.008
|
||||||
|
// "However a network operator may decide to
|
||||||
|
// use only two digits in the MNC in the LAI over the
|
||||||
|
// radio interface. In this case, bits 5 to 8 of octet 3
|
||||||
|
// shall be coded as '1111'".
|
||||||
|
|
||||||
|
// MCC & MNC, 3 octets
|
||||||
|
let mcc = loc.mcc.toString();
|
||||||
|
let mnc = loc.mnc.toString();
|
||||||
|
if (mnc.length == 1) {
|
||||||
|
mnc = "F0" + mnc;
|
||||||
|
} else if (mnc.length == 2) {
|
||||||
|
mnc = "F" + mnc;
|
||||||
|
} else {
|
||||||
|
mnc = mnc[2] + mnc[0] + mnc[1];
|
||||||
|
}
|
||||||
|
GsmPDUHelper.writeSwappedNibbleBCD(mcc + mnc);
|
||||||
|
|
||||||
|
// LAC, 2 octets
|
||||||
|
GsmPDUHelper.writeHexOctet((loc.gsmLocationAreaCode >> 8) & 0xff);
|
||||||
|
GsmPDUHelper.writeHexOctet(loc.gsmLocationAreaCode & 0xff);
|
||||||
|
|
||||||
|
// Cell Id
|
||||||
|
if (loc.gsmCellId > 0xffff) {
|
||||||
|
// UMTS/WCDMA, gsmCellId is 28 bits.
|
||||||
|
GsmPDUHelper.writeHexOctet((loc.gsmCellId >> 24) & 0xff);
|
||||||
|
GsmPDUHelper.writeHexOctet((loc.gsmCellId >> 16) & 0xff);
|
||||||
|
GsmPDUHelper.writeHexOctet((loc.gsmCellId >> 8) & 0xff);
|
||||||
|
GsmPDUHelper.writeHexOctet(loc.gsmCellId & 0xff);
|
||||||
|
} else {
|
||||||
|
// GSM, gsmCellId is 16 bits.
|
||||||
|
GsmPDUHelper.writeHexOctet((loc.gsmCellId >> 8) & 0xff);
|
||||||
|
GsmPDUHelper.writeHexOctet(loc.gsmCellId & 0xff);
|
||||||
|
}
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
let BerTlvHelper = {
|
let BerTlvHelper = {
|
||||||
|
@ -142,3 +142,202 @@ add_test(function test_write_dialling_number() {
|
|||||||
run_next_test();
|
run_next_test();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verify ComprehensionTlvHelper.writeLocationInfoTlv
|
||||||
|
*/
|
||||||
|
add_test(function test_write_location_info_tlv() {
|
||||||
|
let worker = newUint8Worker();
|
||||||
|
let pduHelper = worker.GsmPDUHelper;
|
||||||
|
let tlvHelper = worker.ComprehensionTlvHelper;
|
||||||
|
|
||||||
|
// Test with 2-digit mnc, and gsmCellId obtained from UMTS network.
|
||||||
|
let loc = {
|
||||||
|
mcc: 466,
|
||||||
|
mnc: 92,
|
||||||
|
gsmLocationAreaCode : 10291,
|
||||||
|
gsmCellId: 19072823
|
||||||
|
};
|
||||||
|
tlvHelper.writeLocationInfoTlv(loc);
|
||||||
|
|
||||||
|
let tag = pduHelper.readHexOctet();
|
||||||
|
do_check_eq(tag, COMPREHENSIONTLV_TAG_LOCATION_INFO |
|
||||||
|
COMPREHENSIONTLV_FLAG_CR);
|
||||||
|
|
||||||
|
let length = pduHelper.readHexOctet();
|
||||||
|
do_check_eq(length, 9);
|
||||||
|
|
||||||
|
let mcc_mnc = pduHelper.readSwappedNibbleBcdString(3);
|
||||||
|
do_check_eq(mcc_mnc, "46692");
|
||||||
|
|
||||||
|
let lac = (pduHelper.readHexOctet() << 8) | pduHelper.readHexOctet();
|
||||||
|
do_check_eq(lac, 10291);
|
||||||
|
|
||||||
|
let cellId = (pduHelper.readHexOctet() << 24) |
|
||||||
|
(pduHelper.readHexOctet() << 16) |
|
||||||
|
(pduHelper.readHexOctet() << 8) |
|
||||||
|
(pduHelper.readHexOctet());
|
||||||
|
do_check_eq(cellId, 19072823);
|
||||||
|
|
||||||
|
// Test with 1-digit mnc, and gsmCellId obtained from GSM network.
|
||||||
|
loc = {
|
||||||
|
mcc: 466,
|
||||||
|
mnc: 2,
|
||||||
|
gsmLocationAreaCode : 10291,
|
||||||
|
gsmCellId: 65534
|
||||||
|
};
|
||||||
|
tlvHelper.writeLocationInfoTlv(loc);
|
||||||
|
|
||||||
|
tag = pduHelper.readHexOctet();
|
||||||
|
do_check_eq(tag, COMPREHENSIONTLV_TAG_LOCATION_INFO |
|
||||||
|
COMPREHENSIONTLV_FLAG_CR);
|
||||||
|
|
||||||
|
length = pduHelper.readHexOctet();
|
||||||
|
do_check_eq(length, 7);
|
||||||
|
|
||||||
|
mcc_mnc = pduHelper.readSwappedNibbleBcdString(3);
|
||||||
|
do_check_eq(mcc_mnc, "46602");
|
||||||
|
|
||||||
|
lac = (pduHelper.readHexOctet() << 8) | pduHelper.readHexOctet();
|
||||||
|
do_check_eq(lac, 10291);
|
||||||
|
|
||||||
|
cellId = (pduHelper.readHexOctet() << 8) |
|
||||||
|
(pduHelper.readHexOctet());
|
||||||
|
do_check_eq(cellId, 65534);
|
||||||
|
|
||||||
|
// Test with 3-digit mnc, and gsmCellId obtained from GSM network.
|
||||||
|
loc = {
|
||||||
|
mcc: 466,
|
||||||
|
mnc: 222,
|
||||||
|
gsmLocationAreaCode : 10291,
|
||||||
|
gsmCellId: 65534
|
||||||
|
};
|
||||||
|
tlvHelper.writeLocationInfoTlv(loc);
|
||||||
|
|
||||||
|
tag = pduHelper.readHexOctet();
|
||||||
|
do_check_eq(tag, COMPREHENSIONTLV_TAG_LOCATION_INFO |
|
||||||
|
COMPREHENSIONTLV_FLAG_CR);
|
||||||
|
|
||||||
|
length = pduHelper.readHexOctet();
|
||||||
|
do_check_eq(length, 7);
|
||||||
|
|
||||||
|
mcc_mnc = pduHelper.readSwappedNibbleBcdString(3);
|
||||||
|
do_check_eq(mcc_mnc, "466222");
|
||||||
|
|
||||||
|
lac = (pduHelper.readHexOctet() << 8) | pduHelper.readHexOctet();
|
||||||
|
do_check_eq(lac, 10291);
|
||||||
|
|
||||||
|
cellId = (pduHelper.readHexOctet() << 8) |
|
||||||
|
(pduHelper.readHexOctet());
|
||||||
|
do_check_eq(cellId, 65534);
|
||||||
|
|
||||||
|
run_next_test();
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verify Proactive Command : Refresh
|
||||||
|
*/
|
||||||
|
add_test(function test_stk_proactive_command_refresh() {
|
||||||
|
let worker = newUint8Worker();
|
||||||
|
let pduHelper = worker.GsmPDUHelper;
|
||||||
|
let berHelper = worker.BerTlvHelper;
|
||||||
|
let stkHelper = worker.StkProactiveCmdHelper;
|
||||||
|
|
||||||
|
let refresh_1 = [
|
||||||
|
0xD0,
|
||||||
|
0x10,
|
||||||
|
0x81, 0x03, 0x01, 0x01, 0x01,
|
||||||
|
0x82, 0x02, 0x81, 0x82,
|
||||||
|
0x92, 0x05, 0x01, 0x3F, 0x00, 0x2F, 0xE2];
|
||||||
|
|
||||||
|
for (let i = 0; i < refresh_1.length; i++) {
|
||||||
|
pduHelper.writeHexOctet(refresh_1[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
let berTlv = berHelper.decode(refresh_1.length);
|
||||||
|
let ctlvs = berTlv.value;
|
||||||
|
let tlv = stkHelper.searchForTag(COMPREHENSIONTLV_TAG_COMMAND_DETAILS, ctlvs);
|
||||||
|
do_check_eq(tlv.value.commandNumber, 0x01);
|
||||||
|
do_check_eq(tlv.value.typeOfCommand, 0x01);
|
||||||
|
do_check_eq(tlv.value.commandQualifier, 0x01);
|
||||||
|
|
||||||
|
tlv = stkHelper.searchForTag(COMPREHENSIONTLV_TAG_FILE_LIST, ctlvs);
|
||||||
|
do_check_eq(tlv.value.fileList, "3F002FE2");
|
||||||
|
|
||||||
|
run_next_test();
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verify Proactive Command : Play Tone
|
||||||
|
*/
|
||||||
|
add_test(function test_stk_proactive_command_play_tone() {
|
||||||
|
let worker = newUint8Worker();
|
||||||
|
let pduHelper = worker.GsmPDUHelper;
|
||||||
|
let berHelper = worker.BerTlvHelper;
|
||||||
|
let stkHelper = worker.StkProactiveCmdHelper;
|
||||||
|
|
||||||
|
let tone_1 = [
|
||||||
|
0xD0,
|
||||||
|
0x1B,
|
||||||
|
0x81, 0x03, 0x01, 0x20, 0x00,
|
||||||
|
0x82, 0x02, 0x81, 0x03,
|
||||||
|
0x85, 0x09, 0x44, 0x69, 0x61, 0x6C, 0x20, 0x54, 0x6F, 0x6E, 0x65,
|
||||||
|
0x8E, 0x01, 0x01,
|
||||||
|
0x84, 0x02, 0x01, 0x05];
|
||||||
|
|
||||||
|
for (let i = 0; i < tone_1.length; i++) {
|
||||||
|
pduHelper.writeHexOctet(tone_1[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
let berTlv = berHelper.decode(tone_1.length);
|
||||||
|
let ctlvs = berTlv.value;
|
||||||
|
let tlv = stkHelper.searchForTag(COMPREHENSIONTLV_TAG_COMMAND_DETAILS, ctlvs);
|
||||||
|
do_check_eq(tlv.value.commandNumber, 0x01);
|
||||||
|
do_check_eq(tlv.value.typeOfCommand, 0x20);
|
||||||
|
do_check_eq(tlv.value.commandQualifier, 0x00);
|
||||||
|
|
||||||
|
tlv = stkHelper.searchForTag(COMPREHENSIONTLV_TAG_ALPHA_ID, ctlvs);
|
||||||
|
do_check_eq(tlv.value.identifier, "Dial Tone");
|
||||||
|
|
||||||
|
tlv = stkHelper.searchForTag(COMPREHENSIONTLV_TAG_TONE, ctlvs);
|
||||||
|
do_check_eq(tlv.value.tone, STK_TONE_TYPE_DIAL_TONE);
|
||||||
|
|
||||||
|
tlv = stkHelper.searchForTag(COMPREHENSIONTLV_TAG_DURATION, ctlvs);
|
||||||
|
do_check_eq(tlv.value.timeUnit, STK_TIME_UNIT_SECOND);
|
||||||
|
do_check_eq(tlv.value.timeInterval, 5);
|
||||||
|
|
||||||
|
run_next_test();
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verify Proactive Command : Poll Interval
|
||||||
|
*/
|
||||||
|
add_test(function test_stk_proactive_command_poll_interval() {
|
||||||
|
let worker = newUint8Worker();
|
||||||
|
let pduHelper = worker.GsmPDUHelper;
|
||||||
|
let berHelper = worker.BerTlvHelper;
|
||||||
|
let stkHelper = worker.StkProactiveCmdHelper;
|
||||||
|
|
||||||
|
let poll_1 = [
|
||||||
|
0xD0,
|
||||||
|
0x0D,
|
||||||
|
0x81, 0x03, 0x01, 0x03, 0x00,
|
||||||
|
0x82, 0x02, 0x81, 0x82,
|
||||||
|
0x84, 0x02, 0x01, 0x14];
|
||||||
|
|
||||||
|
for (let i = 0; i < poll_1.length; i++) {
|
||||||
|
pduHelper.writeHexOctet(poll_1[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
let berTlv = berHelper.decode(poll_1.length);
|
||||||
|
let ctlvs = berTlv.value;
|
||||||
|
let tlv = stkHelper.searchForTag(COMPREHENSIONTLV_TAG_COMMAND_DETAILS, ctlvs);
|
||||||
|
do_check_eq(tlv.value.commandNumber, 0x01);
|
||||||
|
do_check_eq(tlv.value.typeOfCommand, 0x03);
|
||||||
|
do_check_eq(tlv.value.commandQualifier, 0x00);
|
||||||
|
|
||||||
|
tlv = stkHelper.searchForTag(COMPREHENSIONTLV_TAG_DURATION, ctlvs);
|
||||||
|
do_check_eq(tlv.value.timeUnit, STK_TIME_UNIT_SECOND);
|
||||||
|
do_check_eq(tlv.value.timeInterval, 0x14);
|
||||||
|
|
||||||
|
run_next_test();
|
||||||
|
});
|
||||||
|
@ -403,6 +403,21 @@ struct BaseRect {
|
|||||||
width = right - x;
|
width = right - x;
|
||||||
height = bottom - y;
|
height = bottom - y;
|
||||||
}
|
}
|
||||||
|
// Scale 'this' by 1/aScale, converting coordinates to integers so that the result is
|
||||||
|
// the largest integer-coordinate rectangle contained by the unrounded result.
|
||||||
|
void ScaleInverseRoundIn(double aScale) { ScaleInverseRoundIn(aScale, aScale); }
|
||||||
|
// Scale 'this' by 1/aXScale and 1/aYScale, converting coordinates to integers so
|
||||||
|
// that the result is the largest integer-coordinate rectangle contained by the
|
||||||
|
// unrounded result.
|
||||||
|
void ScaleInverseRoundIn(double aXScale, double aYScale)
|
||||||
|
{
|
||||||
|
T right = static_cast<T>(floor(double(XMost()) / aXScale));
|
||||||
|
T bottom = static_cast<T>(floor(double(YMost()) / aYScale));
|
||||||
|
x = static_cast<T>(ceil(double(x) / aXScale));
|
||||||
|
y = static_cast<T>(ceil(double(y) / aYScale));
|
||||||
|
width = gfx_max<T>(0, right - x);
|
||||||
|
height = gfx_max<T>(0, bottom - y);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clamp aPoint to this rectangle. It is allowed to end up on any
|
* Clamp aPoint to this rectangle. It is allowed to end up on any
|
||||||
|
@ -30,12 +30,15 @@ public:
|
|||||||
// will begin at.
|
// will begin at.
|
||||||
|
|
||||||
FrameMetrics()
|
FrameMetrics()
|
||||||
: mViewport(0, 0, 0, 0)
|
: mCompositionBounds(0, 0, 0, 0)
|
||||||
, mContentRect(0, 0, 0, 0)
|
, mContentRect(0, 0, 0, 0)
|
||||||
, mViewportScrollOffset(0, 0)
|
, mDisplayPort(0, 0, 0, 0)
|
||||||
|
, mViewport(0, 0, 0, 0)
|
||||||
|
, mScrollOffset(0, 0)
|
||||||
, mScrollId(NULL_SCROLL_ID)
|
, mScrollId(NULL_SCROLL_ID)
|
||||||
, mCSSContentRect(0, 0, 0, 0)
|
, mScrollableRect(0, 0, 0, 0)
|
||||||
, mResolution(1, 1)
|
, mResolution(1, 1)
|
||||||
|
, mDevPixelsPerCSSPixel(1)
|
||||||
, mMayHaveTouchListeners(false)
|
, mMayHaveTouchListeners(false)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
@ -44,7 +47,7 @@ public:
|
|||||||
bool operator==(const FrameMetrics& aOther) const
|
bool operator==(const FrameMetrics& aOther) const
|
||||||
{
|
{
|
||||||
return (mViewport.IsEqualEdges(aOther.mViewport) &&
|
return (mViewport.IsEqualEdges(aOther.mViewport) &&
|
||||||
mViewportScrollOffset == aOther.mViewportScrollOffset &&
|
mScrollOffset == aOther.mScrollOffset &&
|
||||||
mDisplayPort.IsEqualEdges(aOther.mDisplayPort) &&
|
mDisplayPort.IsEqualEdges(aOther.mDisplayPort) &&
|
||||||
mScrollId == aOther.mScrollId);
|
mScrollId == aOther.mScrollId);
|
||||||
}
|
}
|
||||||
@ -68,21 +71,152 @@ public:
|
|||||||
return mScrollId != NULL_SCROLL_ID;
|
return mScrollId != NULL_SCROLL_ID;
|
||||||
}
|
}
|
||||||
|
|
||||||
// These are all in layer coordinate space.
|
gfxSize LayersPixelsPerCSSPixel() const
|
||||||
nsIntRect mViewport;
|
{
|
||||||
|
return mResolution * mDevPixelsPerCSSPixel;
|
||||||
|
}
|
||||||
|
|
||||||
|
gfx::Point GetScrollOffsetInLayerPixels() const
|
||||||
|
{
|
||||||
|
return gfx::Point(mScrollOffset.x * LayersPixelsPerCSSPixel().width,
|
||||||
|
mScrollOffset.y * LayersPixelsPerCSSPixel().height);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// The following metrics are all in widget space/device pixels.
|
||||||
|
//
|
||||||
|
|
||||||
|
// This is the area within the widget that we're compositing to, which means
|
||||||
|
// that it is the visible region of this frame. It is not relative to
|
||||||
|
// anything.
|
||||||
|
// So { 0, 0, [compositeArea.width], [compositeArea.height] }.
|
||||||
|
//
|
||||||
|
// This is useful because, on mobile, the viewport and composition dimensions
|
||||||
|
// are not always the same. In this case, we calculate the displayport using
|
||||||
|
// an area bigger than the region we're compositing to. If we used the
|
||||||
|
// viewport dimensions to calculate the displayport, we'd run into situations
|
||||||
|
// where we're prerendering the wrong regions and the content may be clipped,
|
||||||
|
// or too much of it prerendered. If the displayport is the same as the
|
||||||
|
// viewport, there is no need for this and we can just use the viewport
|
||||||
|
// instead.
|
||||||
|
//
|
||||||
|
// This is only valid on the root layer. Nested iframes do not need this
|
||||||
|
// metric as they do not have a displayport set. See bug 775452.
|
||||||
|
nsIntRect mCompositionBounds;
|
||||||
|
|
||||||
|
// |mScrollableRect|, stored in device pixels. DECPRECATED, DO NOT USE.
|
||||||
|
//
|
||||||
|
// This is valid on any layer where |mScrollableRect| is, though it may be
|
||||||
|
// more lazily maintained than |mScrollableRect|. That is, when
|
||||||
|
// |mScrollableRect| is updated, this may lag. For this reason, it's better to
|
||||||
|
// use |mScrollableRect| for any control logic.
|
||||||
|
//
|
||||||
|
// FIXME/bug 785929: Is this really necessary? Can it not be calculated from
|
||||||
|
// |mScrollableRect| whenever it's needed?
|
||||||
nsIntRect mContentRect;
|
nsIntRect mContentRect;
|
||||||
gfx::Point mViewportScrollOffset;
|
|
||||||
nsIntRect mDisplayPort;
|
// ---------------------------------------------------------------------------
|
||||||
|
// The following metrics are all in CSS pixels. They are not in any uniform
|
||||||
|
// space, so each is explained separately.
|
||||||
|
//
|
||||||
|
|
||||||
|
// The area of a frame's contents that has been painted, relative to the
|
||||||
|
// viewport. It is in the same coordinate space as |mViewport|. For example,
|
||||||
|
// if it is at 0,0, then it's at the same place at the viewport, which is at
|
||||||
|
// the top-left in the layer, and at the same place as the scroll offset of
|
||||||
|
// the document.
|
||||||
|
//
|
||||||
|
// Note that this is structured in such a way that it doesn't depend on the
|
||||||
|
// method layout uses to scroll content.
|
||||||
|
//
|
||||||
|
// May be larger or smaller than |mScrollableRect|.
|
||||||
|
//
|
||||||
|
// To pre-render a margin of 100 CSS pixels around the window,
|
||||||
|
// { x = -100, y = - 100,
|
||||||
|
// width = window.innerWidth + 100, height = window.innerHeight + 100 }
|
||||||
|
//
|
||||||
|
// This is only valid on the root layer. Nested iframes do not have a
|
||||||
|
// displayport set on them. See bug 775452.
|
||||||
|
gfx::Rect mDisplayPort;
|
||||||
|
|
||||||
|
// The CSS viewport, which is the dimensions we're using to constrain the
|
||||||
|
// <html> element of this frame, relative to the top-left of the layer. Note
|
||||||
|
// that its offset is structured in such a way that it doesn't depend on the
|
||||||
|
// method layout uses to scroll content.
|
||||||
|
//
|
||||||
|
// This is mainly useful on the root layer, however nested iframes can have
|
||||||
|
// their own viewport, which will just be the size of the window of the
|
||||||
|
// iframe. For layers that don't correspond to a document, this metric is
|
||||||
|
// meaningless and invalid.
|
||||||
|
gfx::Rect mViewport;
|
||||||
|
|
||||||
|
// The position of the top-left of the CSS viewport, relative to the document
|
||||||
|
// (or the document relative to the viewport, if that helps understand it).
|
||||||
|
//
|
||||||
|
// Thus it is relative to the document. It is in the same coordinate space as
|
||||||
|
// |mScrollableRect|, but a different coordinate space than |mViewport| and
|
||||||
|
// |mDisplayPort|.
|
||||||
|
//
|
||||||
|
// It is required that the rect:
|
||||||
|
// { x = mScrollOffset.x, y = mScrollOffset.y,
|
||||||
|
// width = mCompositionBounds.x / mResolution.width,
|
||||||
|
// height = mCompositionBounds.y / mResolution.height }
|
||||||
|
// Be within |mScrollableRect|.
|
||||||
|
//
|
||||||
|
// This is valid for any layer, but is always relative to this frame and
|
||||||
|
// not any parents, regardless of parent transforms.
|
||||||
|
gfx::Point mScrollOffset;
|
||||||
|
|
||||||
|
// A unique ID assigned to each scrollable frame (unless this is
|
||||||
|
// ROOT_SCROLL_ID, in which case it is not unique).
|
||||||
ViewID mScrollId;
|
ViewID mScrollId;
|
||||||
|
|
||||||
// Consumers often want to know the origin/size before scaling to pixels
|
// The scrollable bounds of a frame. This is determined by reflow.
|
||||||
// so we record this as well.
|
// For the top-level |window|,
|
||||||
gfx::Rect mCSSContentRect;
|
// { x = window.scrollX, y = window.scrollY, // could be 0, 0
|
||||||
|
// width = window.innerWidth, height = window.innerHeight }
|
||||||
|
//
|
||||||
|
// This is relative to the document. It is in the same coordinate space as
|
||||||
|
// |mScrollOffset|, but a different coordinate space than |mViewport| and
|
||||||
|
// |mDisplayPort|. Note also that this coordinate system is understood by
|
||||||
|
// window.scrollTo().
|
||||||
|
//
|
||||||
|
// This is valid on any layer unless it has no content.
|
||||||
|
gfx::Rect mScrollableRect;
|
||||||
|
|
||||||
// This represents the resolution at which the associated layer
|
// ---------------------------------------------------------------------------
|
||||||
// will been rendered.
|
// The following metrics are dimensionless.
|
||||||
|
//
|
||||||
|
|
||||||
|
// The resolution, along both axes, that the current frame has been painted
|
||||||
|
// at.
|
||||||
|
//
|
||||||
|
// Every time this frame is composited and the compositor samples its
|
||||||
|
// transform, this metric is used to create a transform which is
|
||||||
|
// post-multiplied into the parent's transform. Since this only happens when
|
||||||
|
// we walk the layer tree, the resulting transform isn't stored here. Thus the
|
||||||
|
// resolution of parent layers is opaque to this metric.
|
||||||
gfxSize mResolution;
|
gfxSize mResolution;
|
||||||
|
|
||||||
|
// The amount we are currently zooming the frame. This is distinct from
|
||||||
|
// |mResolution| as we can paint a frame at a different resolution than we
|
||||||
|
// zoom it at. This is useful in situations where we want to zoom a frame
|
||||||
|
// without forcing a repaint. At steady state, this and |mResolution| will be
|
||||||
|
// equal.
|
||||||
|
//
|
||||||
|
// Every time this frame is composited and the compositor samples its
|
||||||
|
// transform, this metric is used to create a transform which is
|
||||||
|
// post-multiplied into the parent's transform. Since this only happens when
|
||||||
|
// we walk the layer tree, the resulting transform isn't stored here. Thus the
|
||||||
|
// zoom of parent layers is opaque to this metric.
|
||||||
|
gfxSize mZoom;
|
||||||
|
|
||||||
|
// The conversion factor between CSS pixels and device pixels for this frame.
|
||||||
|
// This can vary based on a variety of things, such as reflowing-zoom. The
|
||||||
|
// conversion factor for device pixels to layers pixels is just the
|
||||||
|
// resolution.
|
||||||
|
float mDevPixelsPerCSSPixel;
|
||||||
|
|
||||||
// Whether or not this frame may have touch listeners.
|
// Whether or not this frame may have touch listeners.
|
||||||
bool mMayHaveTouchListeners;
|
bool mMayHaveTouchListeners;
|
||||||
};
|
};
|
||||||
|
@ -143,6 +143,17 @@ AppendToString(nsACString& s, const nsIntRect& r,
|
|||||||
return s += sfx;
|
return s += sfx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nsACString&
|
||||||
|
AppendToString(nsACString& s, const Rect& r,
|
||||||
|
const char* pfx="", const char* sfx="")
|
||||||
|
{
|
||||||
|
s += pfx;
|
||||||
|
s.AppendPrintf(
|
||||||
|
"(x=%f, y=%f, w=%f, h=%f)",
|
||||||
|
r.x, r.y, r.width, r.height);
|
||||||
|
return s += sfx;
|
||||||
|
}
|
||||||
|
|
||||||
nsACString&
|
nsACString&
|
||||||
AppendToString(nsACString& s, const nsIntRegion& r,
|
AppendToString(nsACString& s, const nsIntRegion& r,
|
||||||
const char* pfx="", const char* sfx="")
|
const char* pfx="", const char* sfx="")
|
||||||
@ -173,7 +184,7 @@ AppendToString(nsACString& s, const FrameMetrics& m,
|
|||||||
{
|
{
|
||||||
s += pfx;
|
s += pfx;
|
||||||
AppendToString(s, m.mViewport, "{ viewport=");
|
AppendToString(s, m.mViewport, "{ viewport=");
|
||||||
AppendToString(s, m.mViewportScrollOffset, " viewportScroll=");
|
AppendToString(s, m.mScrollOffset, " viewportScroll=");
|
||||||
AppendToString(s, m.mDisplayPort, " displayport=");
|
AppendToString(s, m.mDisplayPort, " displayport=");
|
||||||
AppendToString(s, m.mScrollId, " scrollId=", " }");
|
AppendToString(s, m.mScrollId, " scrollId=", " }");
|
||||||
return s += sfx;
|
return s += sfx;
|
||||||
|
@ -253,7 +253,7 @@ BasicTiledThebesLayer::PaintThebes(gfxContext* aContext,
|
|||||||
Layer* primaryScrollable = BasicManager()->GetPrimaryScrollableLayer();
|
Layer* primaryScrollable = BasicManager()->GetPrimaryScrollableLayer();
|
||||||
if (primaryScrollable) {
|
if (primaryScrollable) {
|
||||||
const FrameMetrics& metrics = primaryScrollable->AsContainerLayer()->GetFrameMetrics();
|
const FrameMetrics& metrics = primaryScrollable->AsContainerLayer()->GetFrameMetrics();
|
||||||
scrollOffset = metrics.mViewportScrollOffset;
|
scrollOffset = metrics.mScrollOffset;
|
||||||
}
|
}
|
||||||
int32_t scrollDiffX = scrollOffset.x - mLastScrollOffset.x;
|
int32_t scrollDiffX = scrollOffset.x - mLastScrollOffset.x;
|
||||||
int32_t scrollDiffY = scrollOffset.y - mLastScrollOffset.y;
|
int32_t scrollDiffY = scrollOffset.y - mLastScrollOffset.y;
|
||||||
|
@ -44,7 +44,7 @@ static const int32_t FLING_REPAINT_INTERVAL = 75;
|
|||||||
* Minimum amount of speed along an axis before we begin painting far ahead by
|
* Minimum amount of speed along an axis before we begin painting far ahead by
|
||||||
* adjusting the displayport.
|
* adjusting the displayport.
|
||||||
*/
|
*/
|
||||||
static const float MIN_SKATE_SPEED = 0.5f;
|
static const float MIN_SKATE_SPEED = 0.7f;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Angle from axis within which we stay axis-locked.
|
* Angle from axis within which we stay axis-locked.
|
||||||
@ -79,17 +79,26 @@ static const double MIN_ZOOM = 0.125;
|
|||||||
*/
|
*/
|
||||||
static const int TOUCH_LISTENER_TIMEOUT = 300;
|
static const int TOUCH_LISTENER_TIMEOUT = 300;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Number of samples to store of how long it took to paint after the previous
|
||||||
|
* requests.
|
||||||
|
*/
|
||||||
|
static const int NUM_PAINT_DURATION_SAMPLES = 3;
|
||||||
|
|
||||||
AsyncPanZoomController::AsyncPanZoomController(GeckoContentController* aGeckoContentController,
|
AsyncPanZoomController::AsyncPanZoomController(GeckoContentController* aGeckoContentController,
|
||||||
GestureBehavior aGestures)
|
GestureBehavior aGestures)
|
||||||
: mGeckoContentController(aGeckoContentController),
|
: mGeckoContentController(aGeckoContentController),
|
||||||
mTouchListenerTimeoutTask(nullptr),
|
mTouchListenerTimeoutTask(nullptr),
|
||||||
mX(this),
|
mX(this),
|
||||||
mY(this),
|
mY(this),
|
||||||
|
mAllowZoom(true),
|
||||||
|
mMinZoom(MIN_ZOOM),
|
||||||
|
mMaxZoom(MAX_ZOOM),
|
||||||
mMonitor("AsyncPanZoomController"),
|
mMonitor("AsyncPanZoomController"),
|
||||||
mLastSampleTime(TimeStamp::Now()),
|
mLastSampleTime(TimeStamp::Now()),
|
||||||
mState(NOTHING),
|
mState(NOTHING),
|
||||||
mDPI(72),
|
mDPI(72),
|
||||||
mContentPainterStatus(CONTENT_IDLE),
|
mWaitingForContentToPaint(false),
|
||||||
mDisableNextTouchBatch(false),
|
mDisableNextTouchBatch(false),
|
||||||
mHandlingTouchQueue(false)
|
mHandlingTouchQueue(false)
|
||||||
{
|
{
|
||||||
@ -137,11 +146,11 @@ AsyncPanZoomController::ReceiveInputEvent(const nsInputEvent& aEvent,
|
|||||||
gfx::Point currentScrollOffset, lastScrollOffset;
|
gfx::Point currentScrollOffset, lastScrollOffset;
|
||||||
{
|
{
|
||||||
MonitorAutoLock monitor(mMonitor);
|
MonitorAutoLock monitor(mMonitor);
|
||||||
currentZoom = mFrameMetrics.mResolution.width;
|
currentZoom = mFrameMetrics.mZoom.width;
|
||||||
currentScrollOffset = gfx::Point(mFrameMetrics.mViewportScrollOffset.x,
|
currentScrollOffset = gfx::Point(mFrameMetrics.mScrollOffset.x,
|
||||||
mFrameMetrics.mViewportScrollOffset.y);
|
mFrameMetrics.mScrollOffset.y);
|
||||||
lastScrollOffset = gfx::Point(mLastContentPaintMetrics.mViewportScrollOffset.x,
|
lastScrollOffset = gfx::Point(mLastContentPaintMetrics.mScrollOffset.x,
|
||||||
mLastContentPaintMetrics.mViewportScrollOffset.y);
|
mLastContentPaintMetrics.mScrollOffset.y);
|
||||||
}
|
}
|
||||||
|
|
||||||
nsEventStatus status;
|
nsEventStatus status;
|
||||||
@ -284,8 +293,13 @@ nsEventStatus AsyncPanZoomController::OnTouchStart(const MultiTouchInput& aEvent
|
|||||||
case ANIMATING_ZOOM:
|
case ANIMATING_ZOOM:
|
||||||
// We just interrupted a double-tap animation, so force a redraw in case
|
// We just interrupted a double-tap animation, so force a redraw in case
|
||||||
// this touchstart is just a tap that doesn't end up triggering a redraw.
|
// this touchstart is just a tap that doesn't end up triggering a redraw.
|
||||||
RequestContentRepaint();
|
{
|
||||||
ScheduleComposite();
|
MonitorAutoLock monitor(mMonitor);
|
||||||
|
// Bring the resolution back in sync with the zoom.
|
||||||
|
SetZoomAndResolution(mFrameMetrics.mZoom.width);
|
||||||
|
RequestContentRepaint();
|
||||||
|
ScheduleComposite();
|
||||||
|
}
|
||||||
// Fall through.
|
// Fall through.
|
||||||
case FLING:
|
case FLING:
|
||||||
CancelAnimation();
|
CancelAnimation();
|
||||||
@ -404,6 +418,10 @@ nsEventStatus AsyncPanZoomController::OnTouchCancel(const MultiTouchInput& aEven
|
|||||||
}
|
}
|
||||||
|
|
||||||
nsEventStatus AsyncPanZoomController::OnScaleBegin(const PinchGestureInput& aEvent) {
|
nsEventStatus AsyncPanZoomController::OnScaleBegin(const PinchGestureInput& aEvent) {
|
||||||
|
if (!mAllowZoom) {
|
||||||
|
return nsEventStatus_eConsumeNoDefault;
|
||||||
|
}
|
||||||
|
|
||||||
SetState(PINCHING);
|
SetState(PINCHING);
|
||||||
mLastZoomFocus = aEvent.mFocusPoint;
|
mLastZoomFocus = aEvent.mFocusPoint;
|
||||||
|
|
||||||
@ -411,6 +429,10 @@ nsEventStatus AsyncPanZoomController::OnScaleBegin(const PinchGestureInput& aEve
|
|||||||
}
|
}
|
||||||
|
|
||||||
nsEventStatus AsyncPanZoomController::OnScale(const PinchGestureInput& aEvent) {
|
nsEventStatus AsyncPanZoomController::OnScale(const PinchGestureInput& aEvent) {
|
||||||
|
if (mState != PINCHING) {
|
||||||
|
return nsEventStatus_eConsumeNoDefault;
|
||||||
|
}
|
||||||
|
|
||||||
float prevSpan = aEvent.mPreviousSpan;
|
float prevSpan = aEvent.mPreviousSpan;
|
||||||
if (fabsf(prevSpan) <= EPSILON || fabsf(aEvent.mCurrentSpan) <= EPSILON) {
|
if (fabsf(prevSpan) <= EPSILON || fabsf(aEvent.mCurrentSpan) <= EPSILON) {
|
||||||
// We're still handling it; we've just decided to throw this event away.
|
// We're still handling it; we've just decided to throw this event away.
|
||||||
@ -422,7 +444,7 @@ nsEventStatus AsyncPanZoomController::OnScale(const PinchGestureInput& aEvent) {
|
|||||||
{
|
{
|
||||||
MonitorAutoLock monitor(mMonitor);
|
MonitorAutoLock monitor(mMonitor);
|
||||||
|
|
||||||
float scale = mFrameMetrics.mResolution.width;
|
float scale = mFrameMetrics.mZoom.width;
|
||||||
|
|
||||||
nsIntPoint focusPoint = aEvent.mFocusPoint;
|
nsIntPoint focusPoint = aEvent.mFocusPoint;
|
||||||
float xFocusChange = (mLastZoomFocus.x - focusPoint.x) / scale, yFocusChange = (mLastZoomFocus.y - focusPoint.y) / scale;
|
float xFocusChange = (mLastZoomFocus.x - focusPoint.x) / scale, yFocusChange = (mLastZoomFocus.y - focusPoint.y) / scale;
|
||||||
@ -442,14 +464,14 @@ nsEventStatus AsyncPanZoomController::OnScale(const PinchGestureInput& aEvent) {
|
|||||||
float neededDisplacementX = 0, neededDisplacementY = 0;
|
float neededDisplacementX = 0, neededDisplacementY = 0;
|
||||||
|
|
||||||
// Only do the scaling if we won't go over 8x zoom in or out.
|
// Only do the scaling if we won't go over 8x zoom in or out.
|
||||||
bool doScale = (scale < MAX_ZOOM && spanRatio > 1.0f) || (scale > MIN_ZOOM && spanRatio < 1.0f);
|
bool doScale = (scale < mMaxZoom && spanRatio > 1.0f) || (scale > mMinZoom && spanRatio < 1.0f);
|
||||||
|
|
||||||
// If this zoom will take it over 8x zoom in either direction, but it's not
|
// If this zoom will take it over 8x zoom in either direction, but it's not
|
||||||
// already there, then normalize it.
|
// already there, then normalize it.
|
||||||
if (scale * spanRatio > MAX_ZOOM) {
|
if (scale * spanRatio > mMaxZoom) {
|
||||||
spanRatio = scale / MAX_ZOOM;
|
spanRatio = scale / mMaxZoom;
|
||||||
} else if (scale * spanRatio < MIN_ZOOM) {
|
} else if (scale * spanRatio < mMinZoom) {
|
||||||
spanRatio = scale / MIN_ZOOM;
|
spanRatio = scale / mMinZoom;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (doScale) {
|
if (doScale) {
|
||||||
@ -529,7 +551,7 @@ nsEventStatus AsyncPanZoomController::OnSingleTapUp(const TapGestureInput& aEven
|
|||||||
|
|
||||||
gfx::Point point = WidgetSpaceToCompensatedViewportSpace(
|
gfx::Point point = WidgetSpaceToCompensatedViewportSpace(
|
||||||
gfx::Point(aEvent.mPoint.x, aEvent.mPoint.y),
|
gfx::Point(aEvent.mPoint.x, aEvent.mPoint.y),
|
||||||
mFrameMetrics.mResolution.width);
|
mFrameMetrics.mZoom.width);
|
||||||
mGeckoContentController->HandleSingleTap(nsIntPoint(NS_lround(point.x), NS_lround(point.y)));
|
mGeckoContentController->HandleSingleTap(nsIntPoint(NS_lround(point.x), NS_lround(point.y)));
|
||||||
return nsEventStatus_eConsumeNoDefault;
|
return nsEventStatus_eConsumeNoDefault;
|
||||||
}
|
}
|
||||||
@ -545,10 +567,13 @@ nsEventStatus AsyncPanZoomController::OnDoubleTap(const TapGestureInput& aEvent)
|
|||||||
if (mGeckoContentController) {
|
if (mGeckoContentController) {
|
||||||
MonitorAutoLock monitor(mMonitor);
|
MonitorAutoLock monitor(mMonitor);
|
||||||
|
|
||||||
gfx::Point point = WidgetSpaceToCompensatedViewportSpace(
|
if (mAllowZoom) {
|
||||||
gfx::Point(aEvent.mPoint.x, aEvent.mPoint.y),
|
gfx::Point point = WidgetSpaceToCompensatedViewportSpace(
|
||||||
mFrameMetrics.mResolution.width);
|
gfx::Point(aEvent.mPoint.x, aEvent.mPoint.y),
|
||||||
mGeckoContentController->HandleDoubleTap(nsIntPoint(NS_lround(point.x), NS_lround(point.y)));
|
mFrameMetrics.mZoom.width);
|
||||||
|
mGeckoContentController->HandleDoubleTap(nsIntPoint(NS_lround(point.x), NS_lround(point.y)));
|
||||||
|
}
|
||||||
|
|
||||||
return nsEventStatus_eConsumeNoDefault;
|
return nsEventStatus_eConsumeNoDefault;
|
||||||
}
|
}
|
||||||
return nsEventStatus_eIgnore;
|
return nsEventStatus_eIgnore;
|
||||||
@ -568,6 +593,10 @@ const gfx::Point AsyncPanZoomController::GetVelocityVector() {
|
|||||||
return gfx::Point(mX.GetVelocity(), mY.GetVelocity());
|
return gfx::Point(mX.GetVelocity(), mY.GetVelocity());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const gfx::Point AsyncPanZoomController::GetAccelerationVector() {
|
||||||
|
return gfx::Point(mX.GetAccelerationFactor(), mY.GetAccelerationFactor());
|
||||||
|
}
|
||||||
|
|
||||||
void AsyncPanZoomController::StartPanning(const MultiTouchInput& aEvent) {
|
void AsyncPanZoomController::StartPanning(const MultiTouchInput& aEvent) {
|
||||||
float dx = mX.PanDistance(),
|
float dx = mX.PanDistance(),
|
||||||
dy = mY.PanDistance();
|
dy = mY.PanDistance();
|
||||||
@ -614,7 +643,7 @@ void AsyncPanZoomController::TrackTouch(const MultiTouchInput& aEvent) {
|
|||||||
|
|
||||||
// We want to inversely scale it because when you're zoomed further in, a
|
// We want to inversely scale it because when you're zoomed further in, a
|
||||||
// larger swipe should move you a shorter distance.
|
// larger swipe should move you a shorter distance.
|
||||||
float inverseScale = 1 / mFrameMetrics.mResolution.width;
|
float inverseScale = 1 / mFrameMetrics.mZoom.width;
|
||||||
|
|
||||||
int32_t xDisplacement = mX.GetDisplacementForDuration(inverseScale, timeDelta);
|
int32_t xDisplacement = mX.GetDisplacementForDuration(inverseScale, timeDelta);
|
||||||
int32_t yDisplacement = mY.GetDisplacementForDuration(inverseScale, timeDelta);
|
int32_t yDisplacement = mY.GetDisplacementForDuration(inverseScale, timeDelta);
|
||||||
@ -642,6 +671,9 @@ bool AsyncPanZoomController::DoFling(const TimeDuration& aDelta) {
|
|||||||
shouldContinueFlingY = mY.FlingApplyFrictionOrCancel(aDelta);
|
shouldContinueFlingY = mY.FlingApplyFrictionOrCancel(aDelta);
|
||||||
// If we shouldn't continue the fling, let's just stop and repaint.
|
// If we shouldn't continue the fling, let's just stop and repaint.
|
||||||
if (!shouldContinueFlingX && !shouldContinueFlingY) {
|
if (!shouldContinueFlingX && !shouldContinueFlingY) {
|
||||||
|
// Bring the resolution back in sync with the zoom, in case we scaled down
|
||||||
|
// the zoom while accelerating.
|
||||||
|
SetZoomAndResolution(mFrameMetrics.mZoom.width);
|
||||||
RequestContentRepaint();
|
RequestContentRepaint();
|
||||||
mState = NOTHING;
|
mState = NOTHING;
|
||||||
return false;
|
return false;
|
||||||
@ -649,7 +681,7 @@ bool AsyncPanZoomController::DoFling(const TimeDuration& aDelta) {
|
|||||||
|
|
||||||
// We want to inversely scale it because when you're zoomed further in, a
|
// We want to inversely scale it because when you're zoomed further in, a
|
||||||
// larger swipe should move you a shorter distance.
|
// larger swipe should move you a shorter distance.
|
||||||
float inverseScale = 1 / mFrameMetrics.mResolution.width;
|
float inverseScale = 1 / mFrameMetrics.mZoom.width;
|
||||||
|
|
||||||
ScrollBy(gfx::Point(
|
ScrollBy(gfx::Point(
|
||||||
mX.GetDisplacementForDuration(inverseScale, aDelta),
|
mX.GetDisplacementForDuration(inverseScale, aDelta),
|
||||||
@ -669,132 +701,167 @@ void AsyncPanZoomController::SetCompositorParent(CompositorParent* aCompositorPa
|
|||||||
}
|
}
|
||||||
|
|
||||||
void AsyncPanZoomController::ScrollBy(const gfx::Point& aOffset) {
|
void AsyncPanZoomController::ScrollBy(const gfx::Point& aOffset) {
|
||||||
gfx::Point newOffset(mFrameMetrics.mViewportScrollOffset.x + aOffset.x,
|
gfx::Point newOffset(mFrameMetrics.mScrollOffset.x + aOffset.x,
|
||||||
mFrameMetrics.mViewportScrollOffset.y + aOffset.y);
|
mFrameMetrics.mScrollOffset.y + aOffset.y);
|
||||||
FrameMetrics metrics(mFrameMetrics);
|
FrameMetrics metrics(mFrameMetrics);
|
||||||
metrics.mViewportScrollOffset = newOffset;
|
metrics.mScrollOffset = newOffset;
|
||||||
mFrameMetrics = metrics;
|
mFrameMetrics = metrics;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AsyncPanZoomController::SetPageRect(const gfx::Rect& aCSSPageRect) {
|
void AsyncPanZoomController::SetPageRect(const gfx::Rect& aCSSPageRect) {
|
||||||
FrameMetrics metrics = mFrameMetrics;
|
FrameMetrics metrics = mFrameMetrics;
|
||||||
gfx::Rect pageSize = aCSSPageRect;
|
gfx::Rect pageSize = aCSSPageRect;
|
||||||
float scale = mFrameMetrics.mResolution.width;
|
float scale = mFrameMetrics.mZoom.width;
|
||||||
|
|
||||||
// The page rect is the css page rect scaled by the current zoom.
|
// The page rect is the css page rect scaled by the current zoom.
|
||||||
pageSize.ScaleRoundOut(1 / scale);
|
pageSize.ScaleInverseRoundOut(scale);
|
||||||
|
|
||||||
// Round the page rect so we don't get any truncation, then get the nsIntRect
|
// Round the page rect so we don't get any truncation, then get the nsIntRect
|
||||||
// from this.
|
// from this.
|
||||||
metrics.mContentRect = nsIntRect(pageSize.x, pageSize.y, pageSize.width, pageSize.height);
|
metrics.mContentRect = nsIntRect(pageSize.x, pageSize.y, pageSize.width, pageSize.height);
|
||||||
metrics.mCSSContentRect = aCSSPageRect;
|
metrics.mScrollableRect = aCSSPageRect;
|
||||||
|
|
||||||
mFrameMetrics = metrics;
|
mFrameMetrics = metrics;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AsyncPanZoomController::ScaleWithFocus(float aScale, const nsIntPoint& aFocus) {
|
void AsyncPanZoomController::ScaleWithFocus(float aScale, const nsIntPoint& aFocus) {
|
||||||
FrameMetrics metrics(mFrameMetrics);
|
float scaleFactor = aScale / mFrameMetrics.mZoom.width;
|
||||||
|
|
||||||
// Don't set the scale to the inputted value, but rather multiply it in.
|
SetZoomAndResolution(aScale);
|
||||||
float scaleFactor = aScale / metrics.mResolution.width,
|
|
||||||
oldScale = metrics.mResolution.width;
|
|
||||||
|
|
||||||
metrics.mResolution.width = metrics.mResolution.height = aScale;
|
|
||||||
|
|
||||||
// Force a recalculation of the page rect based on the new zoom and the
|
// Force a recalculation of the page rect based on the new zoom and the
|
||||||
// current CSS page rect (which is unchanged since it's not affected by zoom).
|
// current CSS page rect (which is unchanged since it's not affected by zoom).
|
||||||
SetPageRect(mFrameMetrics.mCSSContentRect);
|
SetPageRect(mFrameMetrics.mScrollableRect);
|
||||||
|
|
||||||
gfx::Point scrollOffset = metrics.mViewportScrollOffset;
|
// If the new scale is very small, we risk multiplying in huge rounding
|
||||||
|
// errors, so don't bother adjusting the scroll offset.
|
||||||
scrollOffset.x += float(aFocus.x) * (scaleFactor - 1.0f) / oldScale;
|
if (aScale >= 0.01f) {
|
||||||
scrollOffset.y += float(aFocus.y) * (scaleFactor - 1.0f) / oldScale;
|
mFrameMetrics.mScrollOffset.x += float(aFocus.x) * (scaleFactor - 1.0f) / aScale;
|
||||||
|
mFrameMetrics.mScrollOffset.y += float(aFocus.y) * (scaleFactor - 1.0f) / aScale;
|
||||||
metrics.mViewportScrollOffset = scrollOffset;
|
}
|
||||||
|
|
||||||
mFrameMetrics = metrics;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AsyncPanZoomController::EnlargeDisplayPortAlongAxis(float aViewport,
|
bool AsyncPanZoomController::EnlargeDisplayPortAlongAxis(float aSkateSizeMultiplier,
|
||||||
|
double aEstimatedPaintDuration,
|
||||||
|
float aCompositionBounds,
|
||||||
float aVelocity,
|
float aVelocity,
|
||||||
|
float aAcceleration,
|
||||||
float* aDisplayPortOffset,
|
float* aDisplayPortOffset,
|
||||||
float* aDisplayPortLength)
|
float* aDisplayPortLength)
|
||||||
{
|
{
|
||||||
const float MIN_SKATE_SIZE_MULTIPLIER = 2.0f;
|
|
||||||
const float MAX_SKATE_SIZE_MULTIPLIER = 4.0f;
|
|
||||||
|
|
||||||
if (fabsf(aVelocity) > MIN_SKATE_SPEED) {
|
if (fabsf(aVelocity) > MIN_SKATE_SPEED) {
|
||||||
*aDisplayPortLength = aViewport * clamped(fabsf(aVelocity),
|
// Enlarge the area we paint.
|
||||||
MIN_SKATE_SIZE_MULTIPLIER, MAX_SKATE_SIZE_MULTIPLIER);
|
*aDisplayPortLength = aCompositionBounds * aSkateSizeMultiplier;
|
||||||
*aDisplayPortOffset = aVelocity > 0 ? 0 : aViewport - *aDisplayPortLength;
|
// Position the area we paint such that all of the excess that extends past
|
||||||
|
// the screen is on the side towards the velocity.
|
||||||
|
*aDisplayPortOffset = aVelocity > 0 ? 0 : aCompositionBounds - *aDisplayPortLength;
|
||||||
|
|
||||||
|
// Only compensate for acceleration when we actually have any. Otherwise
|
||||||
|
// we'll overcompensate when a user is just panning around without flinging.
|
||||||
|
if (aAcceleration > 1.01f) {
|
||||||
|
// Compensate for acceleration and how long we expect a paint to take. We
|
||||||
|
// try to predict where the viewport will be when painting has finished.
|
||||||
|
*aDisplayPortOffset +=
|
||||||
|
fabsf(aAcceleration) * aVelocity * aCompositionBounds * aEstimatedPaintDuration;
|
||||||
|
// If our velocity is in the negative direction of the axis, we have to
|
||||||
|
// compensate for the fact that our scroll offset is the top-left position
|
||||||
|
// of the viewport. In this case, let's make it relative to the
|
||||||
|
// bottom-right. That way, we'll always be growing the displayport upwards
|
||||||
|
// and to the left when skating negatively.
|
||||||
|
*aDisplayPortOffset -= aVelocity < 0 ? aCompositionBounds : 0;
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const nsIntRect AsyncPanZoomController::CalculatePendingDisplayPort() {
|
const gfx::Rect AsyncPanZoomController::CalculatePendingDisplayPort(
|
||||||
float scale = mFrameMetrics.mResolution.width;
|
const FrameMetrics& aFrameMetrics,
|
||||||
nsIntRect viewport = mFrameMetrics.mViewport;
|
const gfx::Point& aVelocity,
|
||||||
viewport.ScaleRoundIn(1 / scale);
|
const gfx::Point& aAcceleration,
|
||||||
|
double aEstimatedPaintDuration)
|
||||||
|
{
|
||||||
|
// The multiplier we apply to a dimension's length if it is skating. That is,
|
||||||
|
// if it's going above MIN_SKATE_SPEED. We prefer to increase the size of the
|
||||||
|
// Y axis because it is more natural in the case that a user is reading a page
|
||||||
|
// that scrolls up/down. Note that one, both or neither of these may be used
|
||||||
|
// at any instant.
|
||||||
|
const float X_SKATE_SIZE_MULTIPLIER = 3.0f;
|
||||||
|
const float Y_SKATE_SIZE_MULTIPLIER = 3.5f;
|
||||||
|
|
||||||
gfx::Point scrollOffset = mFrameMetrics.mViewportScrollOffset;
|
// The multiplier we apply to a dimension's length if it is stationary. We
|
||||||
gfx::Point velocity = GetVelocityVector();
|
// prefer to increase the size of the Y axis because it is more natural in the
|
||||||
|
// case that a user is reading a page that scrolls up/down. Note that one,
|
||||||
|
// both or neither of these may be used at any instant.
|
||||||
|
const float X_STATIONARY_SIZE_MULTIPLIER = 1.5f;
|
||||||
|
const float Y_STATIONARY_SIZE_MULTIPLIER = 2.5f;
|
||||||
|
|
||||||
|
// If we don't get an estimated paint duration, we probably don't have any
|
||||||
|
// data. In this case, we're dealing with either a stationary frame or a first
|
||||||
|
// paint. In either of these cases, we can just assume it'll take 1 second to
|
||||||
|
// paint. Getting this correct is not important anyways since it's only really
|
||||||
|
// useful when accelerating, which can't be happening at this point.
|
||||||
|
double estimatedPaintDuration =
|
||||||
|
aEstimatedPaintDuration > EPSILON ? aEstimatedPaintDuration : 1.0;
|
||||||
|
|
||||||
|
float scale = aFrameMetrics.mZoom.width;
|
||||||
|
nsIntRect compositionBounds = aFrameMetrics.mCompositionBounds;
|
||||||
|
compositionBounds.ScaleInverseRoundIn(scale);
|
||||||
|
const gfx::Rect& scrollableRect = aFrameMetrics.mScrollableRect;
|
||||||
|
|
||||||
|
gfx::Point scrollOffset = aFrameMetrics.mScrollOffset;
|
||||||
|
|
||||||
// The displayport is relative to the current scroll offset. Here's a little
|
|
||||||
// diagram to make it easier to see:
|
|
||||||
//
|
|
||||||
// - - - -
|
|
||||||
// | |
|
|
||||||
// *************
|
|
||||||
// * | | *
|
|
||||||
// - -*- @------ -*- -
|
|
||||||
// | * |=====| * |
|
|
||||||
// * |=====| *
|
|
||||||
// | * |=====| * |
|
|
||||||
// - -*- ------- -*- -
|
|
||||||
// * | | *
|
|
||||||
// *************
|
|
||||||
// | |
|
|
||||||
// - - - -
|
|
||||||
//
|
|
||||||
// The full --- area with === inside it is the actual viewport rect, the *** area
|
|
||||||
// is the displayport, and the - - - area is an imaginary additional page on all 4
|
|
||||||
// borders of the actual page. Notice that the displayport intersects half-way with
|
|
||||||
// each of the imaginary extra pages. The @ symbol at the top left of the
|
|
||||||
// viewport marks the current scroll offset. From the @ symbol to the far left
|
|
||||||
// and far top, it is clear that this distance is 1/4 of the displayport's
|
|
||||||
// height/width dimension.
|
|
||||||
const float STATIONARY_SIZE_MULTIPLIER = 2.0f;
|
|
||||||
gfx::Rect displayPort(0, 0,
|
gfx::Rect displayPort(0, 0,
|
||||||
viewport.width * STATIONARY_SIZE_MULTIPLIER,
|
compositionBounds.width * X_STATIONARY_SIZE_MULTIPLIER,
|
||||||
viewport.height * STATIONARY_SIZE_MULTIPLIER);
|
compositionBounds.height * Y_STATIONARY_SIZE_MULTIPLIER);
|
||||||
|
|
||||||
// If there's motion along an axis of movement, and it's above a threshold,
|
// If there's motion along an axis of movement, and it's above a threshold,
|
||||||
// then we want to paint a larger area in the direction of that motion so that
|
// then we want to paint a larger area in the direction of that motion so that
|
||||||
// it's less likely to checkerboard.
|
// it's less likely to checkerboard.
|
||||||
bool enlargedX = EnlargeDisplayPortAlongAxis(
|
bool enlargedX = EnlargeDisplayPortAlongAxis(
|
||||||
viewport.width, velocity.x, &displayPort.x, &displayPort.width);
|
X_SKATE_SIZE_MULTIPLIER, estimatedPaintDuration,
|
||||||
|
compositionBounds.width, aVelocity.x, aAcceleration.x,
|
||||||
|
&displayPort.x, &displayPort.width);
|
||||||
bool enlargedY = EnlargeDisplayPortAlongAxis(
|
bool enlargedY = EnlargeDisplayPortAlongAxis(
|
||||||
viewport.height, velocity.y, &displayPort.y, &displayPort.height);
|
Y_SKATE_SIZE_MULTIPLIER, estimatedPaintDuration,
|
||||||
|
compositionBounds.height, aVelocity.y, aAcceleration.y,
|
||||||
|
&displayPort.y, &displayPort.height);
|
||||||
|
|
||||||
if (!enlargedX && !enlargedY) {
|
if (!enlargedX && !enlargedY) {
|
||||||
displayPort.x = -displayPort.width / 4;
|
// Position the x and y such that the screen falls in the middle of the displayport.
|
||||||
displayPort.y = -displayPort.height / 4;
|
displayPort.x = -(displayPort.width - compositionBounds.width) / 2;
|
||||||
|
displayPort.y = -(displayPort.height - compositionBounds.height) / 2;
|
||||||
} else if (!enlargedX) {
|
} else if (!enlargedX) {
|
||||||
displayPort.width = viewport.width;
|
displayPort.width = compositionBounds.width;
|
||||||
} else if (!enlargedY) {
|
} else if (!enlargedY) {
|
||||||
displayPort.height = viewport.height;
|
displayPort.height = compositionBounds.height;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we go over the bounds when trying to predict where we will be when this
|
||||||
|
// paint finishes, move it back into the range of the CSS content rect.
|
||||||
|
// FIXME/bug 780395: Generalize this. This code is pretty hacky as it will
|
||||||
|
// probably not work at all for RTL content. This is not intended to be
|
||||||
|
// incredibly accurate; it'll just prevent the entire displayport from being
|
||||||
|
// outside the content rect (which causes bad things to happen).
|
||||||
|
if (enlargedX || enlargedY) {
|
||||||
|
if (scrollOffset.x + compositionBounds.width > scrollableRect.width) {
|
||||||
|
scrollOffset.x -= compositionBounds.width + scrollOffset.x - scrollableRect.width;
|
||||||
|
} else if (scrollOffset.x < scrollableRect.x) {
|
||||||
|
scrollOffset.x = scrollableRect.x;
|
||||||
|
}
|
||||||
|
if (scrollOffset.y + compositionBounds.height > scrollableRect.height) {
|
||||||
|
scrollOffset.y -= compositionBounds.height + scrollOffset.y - scrollableRect.height;
|
||||||
|
} else if (scrollOffset.y < scrollableRect.y) {
|
||||||
|
scrollOffset.y = scrollableRect.y;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
gfx::Rect shiftedDisplayPort = displayPort;
|
gfx::Rect shiftedDisplayPort = displayPort;
|
||||||
shiftedDisplayPort.MoveBy(scrollOffset.x, scrollOffset.y);
|
shiftedDisplayPort.MoveBy(scrollOffset.x, scrollOffset.y);
|
||||||
displayPort = shiftedDisplayPort.Intersect(mFrameMetrics.mCSSContentRect);
|
displayPort = shiftedDisplayPort.Intersect(aFrameMetrics.mScrollableRect);
|
||||||
displayPort.MoveBy(-scrollOffset.x, -scrollOffset.y);
|
displayPort.MoveBy(-scrollOffset.x, -scrollOffset.y);
|
||||||
|
|
||||||
// Round the displayport so we don't get any truncation, then get the nsIntRect
|
return displayPort;
|
||||||
// from this.
|
|
||||||
displayPort.Round();
|
|
||||||
return nsIntRect(displayPort.x, displayPort.y, displayPort.width, displayPort.height);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AsyncPanZoomController::SetDPI(int aDPI) {
|
void AsyncPanZoomController::SetDPI(int aDPI) {
|
||||||
@ -812,24 +879,31 @@ void AsyncPanZoomController::ScheduleComposite() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void AsyncPanZoomController::RequestContentRepaint() {
|
void AsyncPanZoomController::RequestContentRepaint() {
|
||||||
mFrameMetrics.mDisplayPort = CalculatePendingDisplayPort();
|
mPreviousPaintStartTime = TimeStamp::Now();
|
||||||
|
|
||||||
gfx::Point oldScrollOffset = mLastPaintRequestMetrics.mViewportScrollOffset,
|
double estimatedPaintSum = 0.0;
|
||||||
newScrollOffset = mFrameMetrics.mViewportScrollOffset;
|
for (uint32_t i = 0; i < mPreviousPaintDurations.Length(); i++) {
|
||||||
|
estimatedPaintSum += mPreviousPaintDurations[i].ToSeconds();
|
||||||
|
}
|
||||||
|
|
||||||
|
double estimatedPaintDuration = 0.0;
|
||||||
|
if (estimatedPaintSum > EPSILON) {
|
||||||
|
estimatedPaintDuration = estimatedPaintSum / mPreviousPaintDurations.Length();
|
||||||
|
}
|
||||||
|
|
||||||
|
mFrameMetrics.mDisplayPort =
|
||||||
|
CalculatePendingDisplayPort(mFrameMetrics,
|
||||||
|
GetVelocityVector(),
|
||||||
|
GetAccelerationVector(),
|
||||||
|
estimatedPaintDuration);
|
||||||
|
|
||||||
|
gfx::Point oldScrollOffset = mLastPaintRequestMetrics.mScrollOffset,
|
||||||
|
newScrollOffset = mFrameMetrics.mScrollOffset;
|
||||||
|
|
||||||
// If we're trying to paint what we already think is painted, discard this
|
// If we're trying to paint what we already think is painted, discard this
|
||||||
// request since it's a pointless paint.
|
// request since it's a pointless paint.
|
||||||
nsRect oldDisplayPort = nsRect(
|
gfx::Rect oldDisplayPort = mLastPaintRequestMetrics.mDisplayPort;
|
||||||
mLastPaintRequestMetrics.mDisplayPort.x,
|
gfx::Rect newDisplayPort = mFrameMetrics.mDisplayPort;
|
||||||
mLastPaintRequestMetrics.mDisplayPort.y,
|
|
||||||
mLastPaintRequestMetrics.mDisplayPort.width,
|
|
||||||
mLastPaintRequestMetrics.mDisplayPort.height);
|
|
||||||
|
|
||||||
gfx::Rect newDisplayPort = gfx::Rect(
|
|
||||||
mFrameMetrics.mDisplayPort.x,
|
|
||||||
mFrameMetrics.mDisplayPort.y,
|
|
||||||
mFrameMetrics.mDisplayPort.width,
|
|
||||||
mFrameMetrics.mDisplayPort.height);
|
|
||||||
|
|
||||||
oldDisplayPort.MoveBy(oldScrollOffset.x, oldScrollOffset.y);
|
oldDisplayPort.MoveBy(oldScrollOffset.x, oldScrollOffset.y);
|
||||||
newDisplayPort.MoveBy(newScrollOffset.x, newScrollOffset.y);
|
newDisplayPort.MoveBy(newScrollOffset.x, newScrollOffset.y);
|
||||||
@ -842,13 +916,27 @@ void AsyncPanZoomController::RequestContentRepaint() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mContentPainterStatus == CONTENT_IDLE) {
|
// Cache the resolution since we're temporarily changing it to accomodate
|
||||||
mContentPainterStatus = CONTENT_PAINTING;
|
// mixed resolution/zoom (normally we make them the same thing).
|
||||||
mLastPaintRequestMetrics = mFrameMetrics;
|
float actualResolution = mFrameMetrics.mResolution.width;
|
||||||
mGeckoContentController->RequestContentRepaint(mFrameMetrics);
|
// Calculate the factor of acceleration based on the faster of the two axes.
|
||||||
} else {
|
float accelerationFactor =
|
||||||
mContentPainterStatus = CONTENT_PAINTING_AND_PAINT_PENDING;
|
clamped(NS_MAX(mX.GetAccelerationFactor(), mY.GetAccelerationFactor()),
|
||||||
}
|
float(MIN_ZOOM) / 2.0f, float(MAX_ZOOM));
|
||||||
|
// Scale down the resolution a bit based on acceleration.
|
||||||
|
mFrameMetrics.mResolution.width = mFrameMetrics.mResolution.height =
|
||||||
|
actualResolution / accelerationFactor;
|
||||||
|
|
||||||
|
// This message is compressed, so fire whether or not we already have a paint
|
||||||
|
// queued up. We need to know whether or not a paint was requested anyways,
|
||||||
|
// ofr the purposes of content calling window.scrollTo().
|
||||||
|
mGeckoContentController->RequestContentRepaint(mFrameMetrics);
|
||||||
|
mLastPaintRequestMetrics = mFrameMetrics;
|
||||||
|
mWaitingForContentToPaint = true;
|
||||||
|
|
||||||
|
// Set the resolution back to what it was for the purpose of logic control.
|
||||||
|
mFrameMetrics.mResolution.width = mFrameMetrics.mResolution.height =
|
||||||
|
actualResolution;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AsyncPanZoomController::SampleContentTransformForFrame(const TimeStamp& aSampleTime,
|
bool AsyncPanZoomController::SampleContentTransformForFrame(const TimeStamp& aSampleTime,
|
||||||
@ -888,20 +976,22 @@ bool AsyncPanZoomController::SampleContentTransformForFrame(const TimeStamp& aSa
|
|||||||
}
|
}
|
||||||
double sampledPosition = gComputedTimingFunction->GetValue(animPosition);
|
double sampledPosition = gComputedTimingFunction->GetValue(animPosition);
|
||||||
|
|
||||||
mFrameMetrics.mResolution.width = mFrameMetrics.mResolution.height =
|
mFrameMetrics.mZoom.width = mFrameMetrics.mZoom.height =
|
||||||
mEndZoomToMetrics.mResolution.width * sampledPosition +
|
mEndZoomToMetrics.mZoom.width * sampledPosition +
|
||||||
mStartZoomToMetrics.mResolution.width * (1 - sampledPosition);
|
mStartZoomToMetrics.mZoom.width * (1 - sampledPosition);
|
||||||
|
|
||||||
mFrameMetrics.mViewportScrollOffset = gfx::Point(
|
mFrameMetrics.mScrollOffset = gfx::Point(
|
||||||
mEndZoomToMetrics.mViewportScrollOffset.x * sampledPosition +
|
mEndZoomToMetrics.mScrollOffset.x * sampledPosition +
|
||||||
mStartZoomToMetrics.mViewportScrollOffset.x * (1 - sampledPosition),
|
mStartZoomToMetrics.mScrollOffset.x * (1 - sampledPosition),
|
||||||
mEndZoomToMetrics.mViewportScrollOffset.y * sampledPosition +
|
mEndZoomToMetrics.mScrollOffset.y * sampledPosition +
|
||||||
mStartZoomToMetrics.mViewportScrollOffset.y * (1 - sampledPosition)
|
mStartZoomToMetrics.mScrollOffset.y * (1 - sampledPosition)
|
||||||
);
|
);
|
||||||
|
|
||||||
requestAnimationFrame = true;
|
requestAnimationFrame = true;
|
||||||
|
|
||||||
if (aSampleTime - mAnimationStartTime >= ZOOM_TO_DURATION) {
|
if (aSampleTime - mAnimationStartTime >= ZOOM_TO_DURATION) {
|
||||||
|
// Bring the resolution in sync with the zoom.
|
||||||
|
SetZoomAndResolution(mFrameMetrics.mZoom.width);
|
||||||
mState = NOTHING;
|
mState = NOTHING;
|
||||||
RequestContentRepaint();
|
RequestContentRepaint();
|
||||||
}
|
}
|
||||||
@ -916,14 +1006,14 @@ bool AsyncPanZoomController::SampleContentTransformForFrame(const TimeStamp& aSa
|
|||||||
// transformed due to touches like panning or pinching. Eventually, the root
|
// transformed due to touches like panning or pinching. Eventually, the root
|
||||||
// layer transform will become this during runtime, but we must wait for Gecko
|
// layer transform will become this during runtime, but we must wait for Gecko
|
||||||
// to repaint.
|
// to repaint.
|
||||||
localScaleX = mFrameMetrics.mResolution.width;
|
localScaleX = mFrameMetrics.mZoom.width;
|
||||||
localScaleY = mFrameMetrics.mResolution.height;
|
localScaleY = mFrameMetrics.mZoom.height;
|
||||||
|
|
||||||
if (frame.IsScrollable()) {
|
if (frame.IsScrollable()) {
|
||||||
metricsScrollOffset = frame.mViewportScrollOffset;
|
metricsScrollOffset = frame.GetScrollOffsetInLayerPixels();
|
||||||
}
|
}
|
||||||
|
|
||||||
scrollOffset = mFrameMetrics.mViewportScrollOffset;
|
scrollOffset = mFrameMetrics.mScrollOffset;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsIntPoint scrollCompensation(
|
nsIntPoint scrollCompensation(
|
||||||
@ -953,13 +1043,15 @@ void AsyncPanZoomController::NotifyLayersUpdated(const FrameMetrics& aViewportFr
|
|||||||
|
|
||||||
mLastContentPaintMetrics = aViewportFrame;
|
mLastContentPaintMetrics = aViewportFrame;
|
||||||
|
|
||||||
if (mContentPainterStatus != CONTENT_IDLE) {
|
if (mWaitingForContentToPaint) {
|
||||||
if (mContentPainterStatus == CONTENT_PAINTING_AND_PAINT_PENDING) {
|
// Remove the oldest sample we have if adding a new sample takes us over our
|
||||||
mContentPainterStatus = CONTENT_IDLE;
|
// desired number of samples.
|
||||||
RequestContentRepaint();
|
if (mPreviousPaintDurations.Length() >= NUM_PAINT_DURATION_SAMPLES) {
|
||||||
} else {
|
mPreviousPaintDurations.RemoveElementAt(0);
|
||||||
mContentPainterStatus = CONTENT_IDLE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mPreviousPaintDurations.AppendElement(
|
||||||
|
TimeStamp::Now() - mPreviousPaintStartTime);
|
||||||
} else {
|
} else {
|
||||||
// No paint was requested, but we got one anyways. One possible cause of this
|
// No paint was requested, but we got one anyways. One possible cause of this
|
||||||
// is that content could have fired a scrollTo(). In this case, we should take
|
// is that content could have fired a scrollTo(). In this case, we should take
|
||||||
@ -972,10 +1064,7 @@ void AsyncPanZoomController::NotifyLayersUpdated(const FrameMetrics& aViewportFr
|
|||||||
case FLING:
|
case FLING:
|
||||||
case TOUCHING:
|
case TOUCHING:
|
||||||
case WAITING_LISTENERS:
|
case WAITING_LISTENERS:
|
||||||
// FIXME/bug 784908: Scroll offset is stored in layer pixels in the rest
|
mFrameMetrics.mScrollOffset = aViewportFrame.mScrollOffset;
|
||||||
// of the layers code, but we want it in CSS pixels.
|
|
||||||
mFrameMetrics.mViewportScrollOffset =
|
|
||||||
aViewportFrame.mViewportScrollOffset / aViewportFrame.mResolution.width;
|
|
||||||
break;
|
break;
|
||||||
// Don't clobber if we're in other states.
|
// Don't clobber if we're in other states.
|
||||||
default:
|
default:
|
||||||
@ -983,25 +1072,28 @@ void AsyncPanZoomController::NotifyLayersUpdated(const FrameMetrics& aViewportFr
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mWaitingForContentToPaint = false;
|
||||||
|
|
||||||
if (aIsFirstPaint || mFrameMetrics.IsDefault()) {
|
if (aIsFirstPaint || mFrameMetrics.IsDefault()) {
|
||||||
mContentPainterStatus = CONTENT_IDLE;
|
mPreviousPaintDurations.Clear();
|
||||||
|
|
||||||
mX.CancelTouch();
|
mX.CancelTouch();
|
||||||
mY.CancelTouch();
|
mY.CancelTouch();
|
||||||
mFrameMetrics = aViewportFrame;
|
|
||||||
mFrameMetrics.mResolution.width = 1 / mFrameMetrics.mResolution.width;
|
|
||||||
mFrameMetrics.mResolution.height = 1 / mFrameMetrics.mResolution.height;
|
|
||||||
SetPageRect(mFrameMetrics.mCSSContentRect);
|
|
||||||
|
|
||||||
// Bug 776413/fixme: Request a repaint as soon as a page is loaded so that
|
// The composition bounds are not stored within the layers code, so we have
|
||||||
// we get a larger displayport. This is very bad because we're wasting a
|
// to reset them back to what they were every time we overwrite them.
|
||||||
// paint and not initializating the displayport correctly.
|
nsIntRect compositionBounds = mFrameMetrics.mCompositionBounds;
|
||||||
RequestContentRepaint();
|
mFrameMetrics = aViewportFrame;
|
||||||
|
mFrameMetrics.mCompositionBounds = compositionBounds;
|
||||||
|
|
||||||
|
// On first paint, we want to bring zoom back in sync with resolution.
|
||||||
|
mFrameMetrics.mZoom = mFrameMetrics.mResolution;
|
||||||
|
SetPageRect(mFrameMetrics.mScrollableRect);
|
||||||
|
|
||||||
mState = NOTHING;
|
mState = NOTHING;
|
||||||
} else if (!mFrameMetrics.mCSSContentRect.IsEqualEdges(aViewportFrame.mCSSContentRect)) {
|
} else if (!mFrameMetrics.mScrollableRect.IsEqualEdges(aViewportFrame.mScrollableRect)) {
|
||||||
mFrameMetrics.mCSSContentRect = aViewportFrame.mCSSContentRect;
|
mFrameMetrics.mScrollableRect = aViewportFrame.mScrollableRect;
|
||||||
SetPageRect(mFrameMetrics.mCSSContentRect);
|
SetPageRect(mFrameMetrics.mScrollableRect);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1010,11 +1102,27 @@ const FrameMetrics& AsyncPanZoomController::GetFrameMetrics() {
|
|||||||
return mFrameMetrics;
|
return mFrameMetrics;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AsyncPanZoomController::UpdateViewportSize(int aWidth, int aHeight) {
|
void AsyncPanZoomController::UpdateCompositionBounds(const nsIntRect& aCompositionBounds) {
|
||||||
MonitorAutoLock mon(mMonitor);
|
MonitorAutoLock mon(mMonitor);
|
||||||
FrameMetrics metrics = GetFrameMetrics();
|
|
||||||
metrics.mViewport = nsIntRect(0, 0, aWidth, aHeight);
|
nsIntRect oldCompositionBounds = mFrameMetrics.mCompositionBounds;
|
||||||
mFrameMetrics = metrics;
|
mFrameMetrics.mCompositionBounds = aCompositionBounds;
|
||||||
|
|
||||||
|
// If the window had 0 dimensions before, or does now, we don't want to
|
||||||
|
// repaint or update the zoom since we'll run into rendering issues and/or
|
||||||
|
// divide-by-zero. This manifests itself as the screen flashing. If the page
|
||||||
|
// has gone out of view, the buffer will be cleared elsewhere anyways.
|
||||||
|
if (aCompositionBounds.width && aCompositionBounds.height &&
|
||||||
|
oldCompositionBounds.width && oldCompositionBounds.height) {
|
||||||
|
// Alter the zoom such that we can see the same width of the page as we used
|
||||||
|
// to be able to.
|
||||||
|
SetZoomAndResolution(mFrameMetrics.mResolution.width *
|
||||||
|
aCompositionBounds.width /
|
||||||
|
oldCompositionBounds.width);
|
||||||
|
|
||||||
|
// Repaint on a rotation so that our new resolution gets properly updated.
|
||||||
|
RequestContentRepaint();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AsyncPanZoomController::CancelDefaultPanZoom() {
|
void AsyncPanZoomController::CancelDefaultPanZoom() {
|
||||||
@ -1032,27 +1140,29 @@ void AsyncPanZoomController::ZoomToRect(const gfxRect& aRect) {
|
|||||||
{
|
{
|
||||||
MonitorAutoLock mon(mMonitor);
|
MonitorAutoLock mon(mMonitor);
|
||||||
|
|
||||||
nsIntRect viewport = mFrameMetrics.mViewport;
|
nsIntRect compositionBounds = mFrameMetrics.mCompositionBounds;
|
||||||
gfx::Rect cssPageRect = mFrameMetrics.mCSSContentRect;
|
gfx::Rect cssPageRect = mFrameMetrics.mScrollableRect;
|
||||||
gfx::Point scrollOffset = mFrameMetrics.mViewportScrollOffset;
|
gfx::Point scrollOffset = mFrameMetrics.mScrollOffset;
|
||||||
|
|
||||||
// If the rect is empty, treat it as a request to zoom out to the full page
|
// If the rect is empty, treat it as a request to zoom out to the full page
|
||||||
// size.
|
// size.
|
||||||
if (zoomToRect.IsEmpty()) {
|
if (zoomToRect.IsEmpty()) {
|
||||||
nsIntRect cssViewport = viewport;
|
// composition bounds in CSS coordinates
|
||||||
cssViewport.ScaleRoundIn(1 / mFrameMetrics.mResolution.width);
|
nsIntRect cssCompositionBounds = compositionBounds;
|
||||||
cssViewport.MoveBy(nsIntPoint(NS_lround(scrollOffset.x), NS_lround(scrollOffset.y)));
|
cssCompositionBounds.ScaleInverseRoundIn(mFrameMetrics.mZoom.width);
|
||||||
|
cssCompositionBounds.MoveBy(scrollOffset.x, scrollOffset.y);
|
||||||
|
|
||||||
float y = mFrameMetrics.mViewportScrollOffset.y;
|
float y = mFrameMetrics.mScrollOffset.y;
|
||||||
float newHeight = cssViewport.height * cssPageRect.width / cssViewport.width;
|
float newHeight =
|
||||||
float dh = cssViewport.height - newHeight;
|
cssCompositionBounds.height * cssPageRect.width / cssCompositionBounds.width;
|
||||||
|
float dh = cssCompositionBounds.height - newHeight;
|
||||||
|
|
||||||
zoomToRect = gfx::Rect(0.0f,
|
zoomToRect = gfx::Rect(0.0f,
|
||||||
y + dh/2,
|
y + dh/2,
|
||||||
cssPageRect.width,
|
cssPageRect.width,
|
||||||
y + dh/2 + newHeight);
|
y + dh/2 + newHeight);
|
||||||
} else {
|
} else {
|
||||||
float targetRatio = float(viewport.width) / float(viewport.height);
|
float targetRatio = float(compositionBounds.width) / float(compositionBounds.height);
|
||||||
float rectRatio = zoomToRect.width / zoomToRect.height;
|
float rectRatio = zoomToRect.width / zoomToRect.height;
|
||||||
|
|
||||||
if (fabsf(targetRatio - rectRatio) < EPSILON) {
|
if (fabsf(targetRatio - rectRatio) < EPSILON) {
|
||||||
@ -1072,25 +1182,27 @@ void AsyncPanZoomController::ZoomToRect(const gfxRect& aRect) {
|
|||||||
zoomToRect = zoomToRect.Intersect(cssPageRect);
|
zoomToRect = zoomToRect.Intersect(cssPageRect);
|
||||||
}
|
}
|
||||||
|
|
||||||
mEndZoomToMetrics.mResolution.width = mEndZoomToMetrics.mResolution.height =
|
mEndZoomToMetrics.mZoom.width = mEndZoomToMetrics.mZoom.height =
|
||||||
NS_MIN(viewport.width / zoomToRect.width, viewport.height / zoomToRect.height);
|
NS_MIN(compositionBounds.width / zoomToRect.width, compositionBounds.height / zoomToRect.height);
|
||||||
|
|
||||||
mEndZoomToMetrics.mResolution.width = mEndZoomToMetrics.mResolution.height =
|
mEndZoomToMetrics.mZoom.width = mEndZoomToMetrics.mZoom.height =
|
||||||
clamped(mEndZoomToMetrics.mResolution.width, MIN_ZOOM, MAX_ZOOM);
|
clamped(float(mEndZoomToMetrics.mZoom.width),
|
||||||
|
mMinZoom,
|
||||||
|
mMaxZoom);
|
||||||
|
|
||||||
// Recalculate the zoom to rect using the new dimensions.
|
// Recalculate the zoom to rect using the new dimensions.
|
||||||
zoomToRect.width = viewport.width / mEndZoomToMetrics.mResolution.width;
|
zoomToRect.width = compositionBounds.width / mEndZoomToMetrics.mZoom.width;
|
||||||
zoomToRect.height = viewport.height / mEndZoomToMetrics.mResolution.height;
|
zoomToRect.height = compositionBounds.height / mEndZoomToMetrics.mZoom.height;
|
||||||
|
|
||||||
// Clamp the zoom to rect to the CSS rect to make sure it fits.
|
// Clamp the zoom to rect to the CSS rect to make sure it fits.
|
||||||
zoomToRect = zoomToRect.Intersect(cssPageRect);
|
zoomToRect = zoomToRect.Intersect(cssPageRect);
|
||||||
|
|
||||||
// Do one final recalculation to get the resolution.
|
// Do one final recalculation to get the resolution.
|
||||||
mEndZoomToMetrics.mResolution.width = mEndZoomToMetrics.mResolution.height =
|
mEndZoomToMetrics.mZoom.width = mEndZoomToMetrics.mZoom.height =
|
||||||
NS_MAX(viewport.width / zoomToRect.width, viewport.height / zoomToRect.height);
|
NS_MAX(compositionBounds.width / zoomToRect.width, compositionBounds.height / zoomToRect.height);
|
||||||
|
|
||||||
mStartZoomToMetrics = mFrameMetrics;
|
mStartZoomToMetrics = mFrameMetrics;
|
||||||
mEndZoomToMetrics.mViewportScrollOffset =
|
mEndZoomToMetrics.mScrollOffset =
|
||||||
gfx::Point(zoomToRect.x, zoomToRect.y);
|
gfx::Point(zoomToRect.x, zoomToRect.y);
|
||||||
|
|
||||||
mAnimationStartTime = TimeStamp::Now();
|
mAnimationStartTime = TimeStamp::Now();
|
||||||
@ -1144,5 +1256,19 @@ void AsyncPanZoomController::TimeoutTouchListeners() {
|
|||||||
ContentReceivedTouch(false);
|
ContentReceivedTouch(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AsyncPanZoomController::SetZoomAndResolution(float aScale) {
|
||||||
|
mMonitor.AssertCurrentThreadOwns();
|
||||||
|
mFrameMetrics.mResolution.width = mFrameMetrics.mResolution.height =
|
||||||
|
mFrameMetrics.mZoom.width = mFrameMetrics.mZoom.height = aScale;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AsyncPanZoomController::UpdateZoomConstraints(bool aAllowZoom,
|
||||||
|
float aMinZoom,
|
||||||
|
float aMaxZoom) {
|
||||||
|
mAllowZoom = aAllowZoom;
|
||||||
|
mMinZoom = aMinZoom;
|
||||||
|
mMaxZoom = aMaxZoom;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
#include "mozilla/TimeStamp.h"
|
#include "mozilla/TimeStamp.h"
|
||||||
#include "InputData.h"
|
#include "InputData.h"
|
||||||
#include "Axis.h"
|
#include "Axis.h"
|
||||||
|
#include "nsContentUtils.h"
|
||||||
|
|
||||||
#include "base/message_loop.h"
|
#include "base/message_loop.h"
|
||||||
|
|
||||||
@ -97,17 +98,13 @@ public:
|
|||||||
nsInputEvent* aOutEvent);
|
nsInputEvent* aOutEvent);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates the viewport size, i.e. the dimensions of the frame (not
|
* Updates the composition bounds, i.e. the dimensions of the final size of
|
||||||
* necessarily the screen) content will actually be rendered onto in device
|
* the frame this is tied to during composition onto, in device pixels. In
|
||||||
* pixels for example, a subframe will not take the entire screen, but we
|
* general, this will just be:
|
||||||
* still want to know how big it is in device pixels. Ideally we want to be
|
* { x = 0, y = 0, width = surface.width, height = surface.height }, however
|
||||||
* using CSS pixels everywhere inside here, but in this case we need to know
|
* there is no hard requirement for this.
|
||||||
* how large of a displayport to set so we use these dimensions plus some
|
|
||||||
* extra.
|
|
||||||
*
|
|
||||||
* XXX: Use nsIntRect instead.
|
|
||||||
*/
|
*/
|
||||||
void UpdateViewportSize(int aWidth, int aHeight);
|
void UpdateCompositionBounds(const nsIntRect& aCompositionBounds);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* We have found a scrollable subframe, so disable our machinery until we hit
|
* We have found a scrollable subframe, so disable our machinery until we hit
|
||||||
@ -134,6 +131,13 @@ public:
|
|||||||
*/
|
*/
|
||||||
void ContentReceivedTouch(bool aPreventDefault);
|
void ContentReceivedTouch(bool aPreventDefault);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates any zoom constraints contained in the <meta name="viewport"> tag.
|
||||||
|
* We try to obey everything it asks us elsewhere, but here we only handle
|
||||||
|
* minimum-scale, maximum-scale, and user-scalable.
|
||||||
|
*/
|
||||||
|
void UpdateZoomConstraints(bool aAllowZoom, float aMinScale, float aMaxScale);
|
||||||
|
|
||||||
// --------------------------------------------------------------------------
|
// --------------------------------------------------------------------------
|
||||||
// These methods must only be called on the compositor thread.
|
// These methods must only be called on the compositor thread.
|
||||||
//
|
//
|
||||||
@ -193,6 +197,18 @@ public:
|
|||||||
*/
|
*/
|
||||||
int GetDPI();
|
int GetDPI();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Recalculates the displayport. Ideally, this should paint an area bigger
|
||||||
|
* than the composite-to dimensions so that when you scroll down, you don't
|
||||||
|
* checkerboard immediately. This includes a bunch of logic, including
|
||||||
|
* algorithms to bias painting in the direction of the velocity.
|
||||||
|
*/
|
||||||
|
static const gfx::Rect CalculatePendingDisplayPort(
|
||||||
|
const FrameMetrics& aFrameMetrics,
|
||||||
|
const gfx::Point& aVelocity,
|
||||||
|
const gfx::Point& aAcceleration,
|
||||||
|
double aEstimatedPaintDuration);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/**
|
/**
|
||||||
* Internal handler for ReceiveInputEvent(). Does all the actual work.
|
* Internal handler for ReceiveInputEvent(). Does all the actual work.
|
||||||
@ -319,6 +335,11 @@ protected:
|
|||||||
*/
|
*/
|
||||||
const gfx::Point GetVelocityVector();
|
const gfx::Point GetVelocityVector();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a vector of the acceleration factors of each axis.
|
||||||
|
*/
|
||||||
|
const gfx::Point GetAccelerationVector();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets a reference to the first SingleTouchData from a MultiTouchInput. This
|
* Gets a reference to the first SingleTouchData from a MultiTouchInput. This
|
||||||
* gets only the first one and assumes the rest are either missing or not
|
* gets only the first one and assumes the rest are either missing or not
|
||||||
@ -343,15 +364,6 @@ protected:
|
|||||||
*/
|
*/
|
||||||
void TrackTouch(const MultiTouchInput& aEvent);
|
void TrackTouch(const MultiTouchInput& aEvent);
|
||||||
|
|
||||||
/**
|
|
||||||
* Recalculates the displayport. Ideally, this should paint an area bigger
|
|
||||||
* than the actual screen. The viewport refers to the size of the screen,
|
|
||||||
* while the displayport is the area actually painted by Gecko. We paint
|
|
||||||
* a larger area than the screen so that when you scroll down, you don't
|
|
||||||
* checkerboard immediately.
|
|
||||||
*/
|
|
||||||
const nsIntRect CalculatePendingDisplayPort();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Attempts to enlarge the displayport along a single axis. Returns whether or
|
* Attempts to enlarge the displayport along a single axis. Returns whether or
|
||||||
* not the displayport was enlarged. This will fail in circumstances where the
|
* not the displayport was enlarged. This will fail in circumstances where the
|
||||||
@ -360,8 +372,13 @@ protected:
|
|||||||
* |aDisplayPortLength|. If enlarged, these will be updated with the new
|
* |aDisplayPortLength|. If enlarged, these will be updated with the new
|
||||||
* metrics.
|
* metrics.
|
||||||
*/
|
*/
|
||||||
bool EnlargeDisplayPortAlongAxis(float aViewport, float aVelocity,
|
static bool EnlargeDisplayPortAlongAxis(float aSkateSizeMultiplier,
|
||||||
float* aDisplayPortOffset, float* aDisplayPortLength);
|
double aEstimatedPaintDuration,
|
||||||
|
float aCompositionBounds,
|
||||||
|
float aVelocity,
|
||||||
|
float aAcceleration,
|
||||||
|
float* aDisplayPortOffset,
|
||||||
|
float* aDisplayPortLength);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Utility function to send updated FrameMetrics to Gecko so that it can paint
|
* Utility function to send updated FrameMetrics to Gecko so that it can paint
|
||||||
@ -396,6 +413,14 @@ protected:
|
|||||||
*/
|
*/
|
||||||
void TimeoutTouchListeners();
|
void TimeoutTouchListeners();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Utility function that sets the zoom and resolution simultaneously. This is
|
||||||
|
* useful when we want to repaint at the current zoom level.
|
||||||
|
*
|
||||||
|
* *** The monitor must be held while calling this.
|
||||||
|
*/
|
||||||
|
void SetZoomAndResolution(float aScale);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
enum PanZoomState {
|
enum PanZoomState {
|
||||||
NOTHING, /* no touch-start events received */
|
NOTHING, /* no touch-start events received */
|
||||||
@ -409,25 +434,6 @@ private:
|
|||||||
prevented the default actions yet. we still need to abort animations. */
|
prevented the default actions yet. we still need to abort animations. */
|
||||||
};
|
};
|
||||||
|
|
||||||
enum ContentPainterStatus {
|
|
||||||
// A paint may be happening, but it is not due to any action taken by this
|
|
||||||
// thread. For example, content could be invalidating itself, but
|
|
||||||
// AsyncPanZoomController has nothing to do with that.
|
|
||||||
CONTENT_IDLE,
|
|
||||||
// Set every time we dispatch a request for a repaint. When a
|
|
||||||
// ShadowLayersUpdate arrives and the metrics of this frame have changed, we
|
|
||||||
// toggle this off and assume that the paint has completed.
|
|
||||||
CONTENT_PAINTING,
|
|
||||||
// Set when we have a new displayport in the pipeline that we want to paint.
|
|
||||||
// When a ShadowLayersUpdate comes in, we dispatch a new repaint using
|
|
||||||
// mFrameMetrics.mDisplayPort (the most recent request) if this is toggled.
|
|
||||||
// This is distinct from CONTENT_PAINTING in that it signals that a repaint
|
|
||||||
// is happening, whereas this signals that we want to repaint as soon as the
|
|
||||||
// previous paint finishes. When the request is eventually made, it will use
|
|
||||||
// the most up-to-date metrics.
|
|
||||||
CONTENT_PAINTING_AND_PAINT_PENDING
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper to set the current state. Holds the monitor before actually setting
|
* Helper to set the current state. Holds the monitor before actually setting
|
||||||
* it. If the monitor is already held by the current thread, it is safe to
|
* it. If the monitor is already held by the current thread, it is safe to
|
||||||
@ -467,10 +473,19 @@ private:
|
|||||||
AxisX mX;
|
AxisX mX;
|
||||||
AxisY mY;
|
AxisY mY;
|
||||||
|
|
||||||
// Protects |mFrameMetrics|, |mLastContentPaintMetrics| and |mState|. Before
|
// Most up-to-date constraints on zooming. These should always be reasonable
|
||||||
// manipulating |mFrameMetrics| or |mLastContentPaintMetrics|, the monitor
|
// values; for example, allowing a min zoom of 0.0 can cause very bad things
|
||||||
// should be held. When setting |mState|, either the SetState() function can
|
// to happen.
|
||||||
// be used, or the monitor can be held and then |mState| updated.
|
bool mAllowZoom;
|
||||||
|
float mMinZoom;
|
||||||
|
float mMaxZoom;
|
||||||
|
|
||||||
|
// Protects |mFrameMetrics|, |mLastContentPaintMetrics|, |mState| and
|
||||||
|
// |mMetaViewportInfo|. Before manipulating |mFrameMetrics| or
|
||||||
|
// |mLastContentPaintMetrics|, the monitor should be held. When setting
|
||||||
|
// |mState|, either the SetState() function can be used, or the monitor can be
|
||||||
|
// held and then |mState| updated. |mMetaViewportInfo| should be updated
|
||||||
|
// using UpdateMetaViewport().
|
||||||
Monitor mMonitor;
|
Monitor mMonitor;
|
||||||
|
|
||||||
// The last time the compositor has sampled the content transform for this
|
// The last time the compositor has sampled the content transform for this
|
||||||
@ -491,13 +506,20 @@ private:
|
|||||||
// |mMonitor|; that is, it should be held whenever this is updated.
|
// |mMonitor|; that is, it should be held whenever this is updated.
|
||||||
PanZoomState mState;
|
PanZoomState mState;
|
||||||
|
|
||||||
|
// How long it took in the past to paint after a series of previous requests.
|
||||||
|
nsTArray<TimeDuration> mPreviousPaintDurations;
|
||||||
|
|
||||||
|
// When the last paint request started. Used to determine the duration of
|
||||||
|
// previous paints.
|
||||||
|
TimeStamp mPreviousPaintStartTime;
|
||||||
|
|
||||||
int mDPI;
|
int mDPI;
|
||||||
|
|
||||||
// Stores the current paint status of the frame that we're managing. Repaints
|
// Stores the current paint status of the frame that we're managing. Repaints
|
||||||
// may be triggered by other things (like content doing things), in which case
|
// may be triggered by other things (like content doing things), in which case
|
||||||
// this status will not be updated. It is only changed when this class
|
// this status will not be updated. It is only changed when this class
|
||||||
// requests a repaint.
|
// requests a repaint.
|
||||||
ContentPainterStatus mContentPainterStatus;
|
bool mWaitingForContentToPaint;
|
||||||
|
|
||||||
// Flag used to determine whether or not we should disable handling of the
|
// Flag used to determine whether or not we should disable handling of the
|
||||||
// next batch of touch events. This is used for sync scrolling of subframes.
|
// next batch of touch events. This is used for sync scrolling of subframes.
|
||||||
|
@ -18,7 +18,7 @@ static const float EPSILON = 0.0001f;
|
|||||||
* or we get a touch point very far away from the previous position for some
|
* or we get a touch point very far away from the previous position for some
|
||||||
* reason.
|
* reason.
|
||||||
*/
|
*/
|
||||||
static const float MAX_EVENT_ACCELERATION = 0.5f;
|
static const float MAX_EVENT_ACCELERATION = 999.0f;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Amount of friction applied during flings.
|
* Amount of friction applied during flings.
|
||||||
@ -95,15 +95,19 @@ void Axis::StartTouch(int32_t aPos) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
float Axis::GetDisplacementForDuration(float aScale, const TimeDuration& aDelta) {
|
float Axis::GetDisplacementForDuration(float aScale, const TimeDuration& aDelta) {
|
||||||
float velocityFactor = powf(ACCELERATION_MULTIPLIER,
|
if (fabsf(mVelocity) < VELOCITY_THRESHOLD) {
|
||||||
NS_MAX(0, (mAcceleration - 4) * 3));
|
mAcceleration = 0;
|
||||||
float displacement = mVelocity * aScale * aDelta.ToMilliseconds() * velocityFactor;
|
}
|
||||||
|
|
||||||
|
float accelerationFactor = GetAccelerationFactor();
|
||||||
|
float displacement = mVelocity * aScale * aDelta.ToMilliseconds() * accelerationFactor;
|
||||||
// If this displacement will cause an overscroll, throttle it. Can potentially
|
// If this displacement will cause an overscroll, throttle it. Can potentially
|
||||||
// bring it to 0 even if the velocity is high.
|
// bring it to 0 even if the velocity is high.
|
||||||
if (DisplacementWillOverscroll(displacement) != OVERSCROLL_NONE) {
|
if (DisplacementWillOverscroll(displacement) != OVERSCROLL_NONE) {
|
||||||
// No need to have a velocity along this axis anymore; it won't take us
|
// No need to have a velocity along this axis anymore; it won't take us
|
||||||
// anywhere, so we're just spinning needlessly.
|
// anywhere, so we're just spinning needlessly.
|
||||||
mVelocity = 0.0f;
|
mVelocity = 0.0f;
|
||||||
|
mAcceleration = 0;
|
||||||
displacement -= DisplacementWillOverscrollAmount(displacement);
|
displacement -= DisplacementWillOverscrollAmount(displacement);
|
||||||
}
|
}
|
||||||
return displacement;
|
return displacement;
|
||||||
@ -140,12 +144,12 @@ bool Axis::FlingApplyFrictionOrCancel(const TimeDuration& aDelta) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Axis::Overscroll Axis::GetOverscroll() {
|
Axis::Overscroll Axis::GetOverscroll() {
|
||||||
// If the current pan takes the viewport to the left of or above the current
|
// If the current pan takes the window to the left of or above the current
|
||||||
// page rect.
|
// page rect.
|
||||||
bool minus = GetOrigin() < GetPageStart();
|
bool minus = GetOrigin() < GetPageStart();
|
||||||
// If the current pan takes the viewport to the right of or below the current
|
// If the current pan takes the window to the right of or below the current
|
||||||
// page rect.
|
// page rect.
|
||||||
bool plus = GetViewportEnd() > GetPageEnd();
|
bool plus = GetCompositionEnd() > GetPageEnd();
|
||||||
if (minus && plus) {
|
if (minus && plus) {
|
||||||
return OVERSCROLL_BOTH;
|
return OVERSCROLL_BOTH;
|
||||||
}
|
}
|
||||||
@ -161,19 +165,20 @@ Axis::Overscroll Axis::GetOverscroll() {
|
|||||||
float Axis::GetExcess() {
|
float Axis::GetExcess() {
|
||||||
switch (GetOverscroll()) {
|
switch (GetOverscroll()) {
|
||||||
case OVERSCROLL_MINUS: return GetOrigin() - GetPageStart();
|
case OVERSCROLL_MINUS: return GetOrigin() - GetPageStart();
|
||||||
case OVERSCROLL_PLUS: return GetViewportEnd() - GetPageEnd();
|
case OVERSCROLL_PLUS: return GetCompositionEnd() - GetPageEnd();
|
||||||
case OVERSCROLL_BOTH: return (GetViewportEnd() - GetPageEnd()) + (GetPageStart() - GetOrigin());
|
case OVERSCROLL_BOTH: return (GetCompositionEnd() - GetPageEnd()) +
|
||||||
|
(GetPageStart() - GetOrigin());
|
||||||
default: return 0;
|
default: return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Axis::Overscroll Axis::DisplacementWillOverscroll(int32_t aDisplacement) {
|
Axis::Overscroll Axis::DisplacementWillOverscroll(int32_t aDisplacement) {
|
||||||
// If the current pan plus a displacement takes the viewport to the left of or
|
// If the current pan plus a displacement takes the window to the left of or
|
||||||
// above the current page rect.
|
// above the current page rect.
|
||||||
bool minus = GetOrigin() + aDisplacement < GetPageStart();
|
bool minus = GetOrigin() + aDisplacement < GetPageStart();
|
||||||
// If the current pan plus a displacement takes the viewport to the right of or
|
// If the current pan plus a displacement takes the window to the right of or
|
||||||
// below the current page rect.
|
// below the current page rect.
|
||||||
bool plus = GetViewportEnd() + aDisplacement > GetPageEnd();
|
bool plus = GetCompositionEnd() + aDisplacement > GetPageEnd();
|
||||||
if (minus && plus) {
|
if (minus && plus) {
|
||||||
return OVERSCROLL_BOTH;
|
return OVERSCROLL_BOTH;
|
||||||
}
|
}
|
||||||
@ -189,7 +194,7 @@ Axis::Overscroll Axis::DisplacementWillOverscroll(int32_t aDisplacement) {
|
|||||||
float Axis::DisplacementWillOverscrollAmount(int32_t aDisplacement) {
|
float Axis::DisplacementWillOverscrollAmount(int32_t aDisplacement) {
|
||||||
switch (DisplacementWillOverscroll(aDisplacement)) {
|
switch (DisplacementWillOverscroll(aDisplacement)) {
|
||||||
case OVERSCROLL_MINUS: return (GetOrigin() + aDisplacement) - GetPageStart();
|
case OVERSCROLL_MINUS: return (GetOrigin() + aDisplacement) - GetPageStart();
|
||||||
case OVERSCROLL_PLUS: return (GetViewportEnd() + aDisplacement) - GetPageEnd();
|
case OVERSCROLL_PLUS: return (GetCompositionEnd() + aDisplacement) - GetPageEnd();
|
||||||
// Don't handle overscrolled in both directions; a displacement can't cause
|
// Don't handle overscrolled in both directions; a displacement can't cause
|
||||||
// this, it must have already been zoomed out too far.
|
// this, it must have already been zoomed out too far.
|
||||||
default: return 0;
|
default: return 0;
|
||||||
@ -201,7 +206,7 @@ Axis::Overscroll Axis::ScaleWillOverscroll(float aScale, int32_t aFocus) {
|
|||||||
|
|
||||||
bool both = ScaleWillOverscrollBothSides(aScale);
|
bool both = ScaleWillOverscrollBothSides(aScale);
|
||||||
bool minus = originAfterScale < GetPageStart() * aScale;
|
bool minus = originAfterScale < GetPageStart() * aScale;
|
||||||
bool plus = (originAfterScale + GetViewportLength()) > GetPageEnd() * aScale;
|
bool plus = (originAfterScale + GetCompositionLength()) > GetPageEnd() * aScale;
|
||||||
|
|
||||||
if ((minus && plus) || both) {
|
if ((minus && plus) || both) {
|
||||||
return OVERSCROLL_BOTH;
|
return OVERSCROLL_BOTH;
|
||||||
@ -219,7 +224,8 @@ float Axis::ScaleWillOverscrollAmount(float aScale, int32_t aFocus) {
|
|||||||
float originAfterScale = (GetOrigin() + aFocus) * aScale - aFocus;
|
float originAfterScale = (GetOrigin() + aFocus) * aScale - aFocus;
|
||||||
switch (ScaleWillOverscroll(aScale, aFocus)) {
|
switch (ScaleWillOverscroll(aScale, aFocus)) {
|
||||||
case OVERSCROLL_MINUS: return originAfterScale - GetPageStart() * aScale;
|
case OVERSCROLL_MINUS: return originAfterScale - GetPageStart() * aScale;
|
||||||
case OVERSCROLL_PLUS: return (originAfterScale + GetViewportLength()) - GetPageEnd() * aScale;
|
case OVERSCROLL_PLUS: return (originAfterScale + GetCompositionLength()) -
|
||||||
|
NS_lround(GetPageEnd() * aScale);
|
||||||
// Don't handle OVERSCROLL_BOTH. Client code is expected to deal with it.
|
// Don't handle OVERSCROLL_BOTH. Client code is expected to deal with it.
|
||||||
default: return 0;
|
default: return 0;
|
||||||
}
|
}
|
||||||
@ -229,8 +235,12 @@ float Axis::GetVelocity() {
|
|||||||
return mVelocity;
|
return mVelocity;
|
||||||
}
|
}
|
||||||
|
|
||||||
float Axis::GetViewportEnd() {
|
float Axis::GetAccelerationFactor() {
|
||||||
return GetOrigin() + GetViewportLength();
|
return powf(ACCELERATION_MULTIPLIER, NS_MAX(0, (mAcceleration - 4) * 3));
|
||||||
|
}
|
||||||
|
|
||||||
|
float Axis::GetCompositionEnd() {
|
||||||
|
return GetOrigin() + GetCompositionLength();
|
||||||
}
|
}
|
||||||
|
|
||||||
float Axis::GetPageEnd() {
|
float Axis::GetPageEnd() {
|
||||||
@ -238,40 +248,44 @@ float Axis::GetPageEnd() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
float Axis::GetOrigin() {
|
float Axis::GetOrigin() {
|
||||||
gfx::Point origin = mAsyncPanZoomController->GetFrameMetrics().mViewportScrollOffset;
|
gfx::Point origin = mAsyncPanZoomController->GetFrameMetrics().mScrollOffset;
|
||||||
return GetPointOffset(origin);
|
return GetPointOffset(origin);
|
||||||
}
|
}
|
||||||
|
|
||||||
float Axis::GetViewportLength() {
|
float Axis::GetCompositionLength() {
|
||||||
nsIntRect viewport = mAsyncPanZoomController->GetFrameMetrics().mViewport;
|
nsIntRect compositionBounds =
|
||||||
gfx::Rect scaledViewport = gfx::Rect(viewport.x, viewport.y, viewport.width, viewport.height);
|
mAsyncPanZoomController->GetFrameMetrics().mCompositionBounds;
|
||||||
scaledViewport.ScaleRoundIn(1 / mAsyncPanZoomController->GetFrameMetrics().mResolution.width);
|
gfx::Rect scaledCompositionBounds =
|
||||||
return GetRectLength(scaledViewport);
|
gfx::Rect(compositionBounds.x, compositionBounds.y,
|
||||||
|
compositionBounds.width, compositionBounds.height);
|
||||||
|
scaledCompositionBounds.ScaleInverseRoundIn(
|
||||||
|
mAsyncPanZoomController->GetFrameMetrics().mZoom.width);
|
||||||
|
return GetRectLength(scaledCompositionBounds);
|
||||||
}
|
}
|
||||||
|
|
||||||
float Axis::GetPageStart() {
|
float Axis::GetPageStart() {
|
||||||
gfx::Rect pageRect = mAsyncPanZoomController->GetFrameMetrics().mCSSContentRect;
|
gfx::Rect pageRect = mAsyncPanZoomController->GetFrameMetrics().mScrollableRect;
|
||||||
return GetRectOffset(pageRect);
|
return GetRectOffset(pageRect);
|
||||||
}
|
}
|
||||||
|
|
||||||
float Axis::GetPageLength() {
|
float Axis::GetPageLength() {
|
||||||
gfx::Rect pageRect = mAsyncPanZoomController->GetFrameMetrics().mCSSContentRect;
|
gfx::Rect pageRect = mAsyncPanZoomController->GetFrameMetrics().mScrollableRect;
|
||||||
return GetRectLength(pageRect);
|
return GetRectLength(pageRect);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Axis::ScaleWillOverscrollBothSides(float aScale) {
|
bool Axis::ScaleWillOverscrollBothSides(float aScale) {
|
||||||
const FrameMetrics& metrics = mAsyncPanZoomController->GetFrameMetrics();
|
const FrameMetrics& metrics = mAsyncPanZoomController->GetFrameMetrics();
|
||||||
|
|
||||||
gfx::Rect cssContentRect = metrics.mCSSContentRect;
|
gfx::Rect cssContentRect = metrics.mScrollableRect;
|
||||||
|
|
||||||
float currentScale = metrics.mResolution.width;
|
float currentScale = metrics.mZoom.width;
|
||||||
gfx::Rect viewport = gfx::Rect(metrics.mViewport.x,
|
nsIntRect compositionBounds = metrics.mCompositionBounds;
|
||||||
metrics.mViewport.y,
|
gfx::Rect scaledCompositionBounds =
|
||||||
metrics.mViewport.width,
|
gfx::Rect(compositionBounds.x, compositionBounds.y,
|
||||||
metrics.mViewport.height);
|
compositionBounds.width, compositionBounds.height);
|
||||||
viewport.ScaleRoundIn(1 / (currentScale * aScale));
|
scaledCompositionBounds.ScaleInverseRoundIn(currentScale * aScale);
|
||||||
|
|
||||||
return GetRectLength(cssContentRect) < GetRectLength(viewport);
|
return GetRectLength(cssContentRect) < GetRectLength(scaledCompositionBounds);
|
||||||
}
|
}
|
||||||
|
|
||||||
AxisX::AxisX(AsyncPanZoomController* aAsyncPanZoomController)
|
AxisX::AxisX(AsyncPanZoomController* aAsyncPanZoomController)
|
||||||
|
@ -116,6 +116,12 @@ public:
|
|||||||
*/
|
*/
|
||||||
float GetExcess();
|
float GetExcess();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the factor of acceleration applied to the velocity, based on the
|
||||||
|
* amount of flings that have been done successively.
|
||||||
|
*/
|
||||||
|
float GetAccelerationFactor();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the raw velocity of this axis at this moment.
|
* Gets the raw velocity of this axis at this moment.
|
||||||
*/
|
*/
|
||||||
@ -165,10 +171,10 @@ public:
|
|||||||
bool ScaleWillOverscrollBothSides(float aScale);
|
bool ScaleWillOverscrollBothSides(float aScale);
|
||||||
|
|
||||||
float GetOrigin();
|
float GetOrigin();
|
||||||
float GetViewportLength();
|
float GetCompositionLength();
|
||||||
float GetPageStart();
|
float GetPageStart();
|
||||||
float GetPageLength();
|
float GetPageLength();
|
||||||
float GetViewportEnd();
|
float GetCompositionEnd();
|
||||||
float GetPageEnd();
|
float GetPageEnd();
|
||||||
|
|
||||||
virtual float GetPointOffset(const gfx::Point& aPoint) = 0;
|
virtual float GetPointOffset(const gfx::Point& aPoint) = 0;
|
||||||
|
@ -467,8 +467,8 @@ private:
|
|||||||
}
|
}
|
||||||
const FrameMetrics& fm = c->GetFrameMetrics();
|
const FrameMetrics& fm = c->GetFrameMetrics();
|
||||||
gfx3DMatrix m(aContainer->GetTransform());
|
gfx3DMatrix m(aContainer->GetTransform());
|
||||||
m.Translate(gfxPoint3D(-fm.mViewportScrollOffset.x,
|
m.Translate(gfxPoint3D(-fm.GetScrollOffsetInLayerPixels().x,
|
||||||
-fm.mViewportScrollOffset.y, 0));
|
-fm.GetScrollOffsetInLayerPixels().y, 0));
|
||||||
|
|
||||||
// The transform already takes the resolution scale into account. Since we
|
// The transform already takes the resolution scale into account. Since we
|
||||||
// will apply the resolution scale again when computing the effective
|
// will apply the resolution scale again when computing the effective
|
||||||
@ -787,30 +787,43 @@ CompositorParent::TransformShadowTree(TimeStamp aCurrentFrame)
|
|||||||
|
|
||||||
float rootScaleX = rootTransform.GetXScale(),
|
float rootScaleX = rootTransform.GetXScale(),
|
||||||
rootScaleY = rootTransform.GetYScale();
|
rootScaleY = rootTransform.GetYScale();
|
||||||
|
// The ratio of layers pixels to device pixels. The Java
|
||||||
|
// compositor wants to see values in units of device pixels, so we
|
||||||
|
// map our FrameMetrics values to that space. This is not exposed
|
||||||
|
// as a FrameMetrics helper because it's a deprecated conversion.
|
||||||
|
float devPixelRatioX = 1 / rootScaleX, devPixelRatioY = 1 / rootScaleY;
|
||||||
|
|
||||||
|
gfx::Point scrollOffsetLayersPixels(metrics.GetScrollOffsetInLayerPixels());
|
||||||
|
nsIntPoint scrollOffsetDevPixels(
|
||||||
|
NS_lround(scrollOffsetLayersPixels.x * devPixelRatioX),
|
||||||
|
NS_lround(scrollOffsetLayersPixels.y * devPixelRatioY));
|
||||||
|
|
||||||
if (mIsFirstPaint) {
|
if (mIsFirstPaint) {
|
||||||
mContentRect = metrics.mContentRect;
|
mContentRect = metrics.mContentRect;
|
||||||
const gfx::Point& scrollOffset = metrics.mViewportScrollOffset;
|
SetFirstPaintViewport(scrollOffsetDevPixels,
|
||||||
SetFirstPaintViewport(nsIntPoint(NS_lround(scrollOffset.x),
|
|
||||||
NS_lround(scrollOffset.y)),
|
|
||||||
1/rootScaleX,
|
1/rootScaleX,
|
||||||
mContentRect,
|
mContentRect,
|
||||||
metrics.mCSSContentRect);
|
metrics.mScrollableRect);
|
||||||
mIsFirstPaint = false;
|
mIsFirstPaint = false;
|
||||||
} else if (!metrics.mContentRect.IsEqualEdges(mContentRect)) {
|
} else if (!metrics.mContentRect.IsEqualEdges(mContentRect)) {
|
||||||
mContentRect = metrics.mContentRect;
|
mContentRect = metrics.mContentRect;
|
||||||
SetPageRect(metrics.mCSSContentRect);
|
SetPageRect(metrics.mScrollableRect);
|
||||||
}
|
}
|
||||||
|
|
||||||
// We synchronise the viewport information with Java after sending the above
|
// We synchronise the viewport information with Java after sending the above
|
||||||
// notifications, so that Java can take these into account in its response.
|
// notifications, so that Java can take these into account in its response.
|
||||||
// Calculate the absolute display port to send to Java
|
// Calculate the absolute display port to send to Java
|
||||||
nsIntRect displayPort = metrics.mDisplayPort;
|
gfx::Rect displayPortLayersPixels(metrics.mDisplayPort);
|
||||||
gfx::Point scrollOffset = metrics.mViewportScrollOffset;
|
nsIntRect displayPortDevPixels(
|
||||||
displayPort.x += NS_lround(scrollOffset.x);
|
NS_lround(displayPortLayersPixels.x * devPixelRatioX),
|
||||||
displayPort.y += NS_lround(scrollOffset.y);
|
NS_lround(displayPortLayersPixels.y * devPixelRatioY),
|
||||||
|
NS_lround(displayPortLayersPixels.width * devPixelRatioX),
|
||||||
|
NS_lround(displayPortLayersPixels.height * devPixelRatioY));
|
||||||
|
|
||||||
SyncViewportInfo(displayPort, 1/rootScaleX, mLayersUpdated,
|
displayPortDevPixels.x += scrollOffsetDevPixels.x;
|
||||||
|
displayPortDevPixels.y += scrollOffsetDevPixels.y;
|
||||||
|
|
||||||
|
SyncViewportInfo(displayPortDevPixels, 1/rootScaleX, mLayersUpdated,
|
||||||
mScrollOffset, mXScale, mYScale);
|
mScrollOffset, mXScale, mYScale);
|
||||||
mLayersUpdated = false;
|
mLayersUpdated = false;
|
||||||
|
|
||||||
@ -825,8 +838,7 @@ CompositorParent::TransformShadowTree(TimeStamp aCurrentFrame)
|
|||||||
|
|
||||||
nsIntPoint metricsScrollOffset(0, 0);
|
nsIntPoint metricsScrollOffset(0, 0);
|
||||||
if (metrics.IsScrollable()) {
|
if (metrics.IsScrollable()) {
|
||||||
metricsScrollOffset =
|
metricsScrollOffset = scrollOffsetDevPixels;
|
||||||
nsIntPoint(NS_lround(scrollOffset.x), NS_lround(scrollOffset.y));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
nsIntPoint scrollCompensation(
|
nsIntPoint scrollCompensation(
|
||||||
|
@ -37,7 +37,9 @@ ReusableTileStoreOGL::InvalidateTiles(TiledThebesLayerOGL* aLayer,
|
|||||||
// This will be incorrect when the transform involves rotation, but
|
// This will be incorrect when the transform involves rotation, but
|
||||||
// it'd be quite hard to retain invalid tiles correctly in this
|
// it'd be quite hard to retain invalid tiles correctly in this
|
||||||
// situation anyway.
|
// situation anyway.
|
||||||
renderBounds = parent->GetEffectiveTransform().TransformBounds(gfxRect(metrics.mDisplayPort));
|
renderBounds = parent->GetEffectiveTransform().TransformBounds(
|
||||||
|
gfxRect(metrics.mDisplayPort.x, metrics.mDisplayPort.y,
|
||||||
|
metrics.mDisplayPort.width, metrics.mDisplayPort.height));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -217,10 +219,14 @@ ReusableTileStoreOGL::DrawTiles(TiledThebesLayerOGL* aLayer,
|
|||||||
scrollableLayer = parent;
|
scrollableLayer = parent;
|
||||||
if (!parentMetrics.mDisplayPort.IsEmpty() && scrollableLayer) {
|
if (!parentMetrics.mDisplayPort.IsEmpty() && scrollableLayer) {
|
||||||
displayPort = parent->GetEffectiveTransform().
|
displayPort = parent->GetEffectiveTransform().
|
||||||
TransformBounds(gfxRect(parentMetrics.mDisplayPort));
|
TransformBounds(gfxRect(
|
||||||
|
parentMetrics.mDisplayPort.x, parentMetrics.mDisplayPort.y,
|
||||||
|
parentMetrics.mDisplayPort.width, parentMetrics.mDisplayPort.height));
|
||||||
const FrameMetrics& metrics = scrollableLayer->GetFrameMetrics();
|
const FrameMetrics& metrics = scrollableLayer->GetFrameMetrics();
|
||||||
const nsIntSize& contentSize = metrics.mContentRect.Size();
|
const nsIntSize& contentSize = metrics.mContentRect.Size();
|
||||||
const gfx::Point& scrollOffset = metrics.mViewportScrollOffset;
|
gfx::Point scrollOffset =
|
||||||
|
gfx::Point(metrics.mScrollOffset.x * metrics.LayersPixelsPerCSSPixel().width,
|
||||||
|
metrics.mScrollOffset.y * metrics.LayersPixelsPerCSSPixel().height);
|
||||||
const nsIntPoint& contentOrigin = metrics.mContentRect.TopLeft() -
|
const nsIntPoint& contentOrigin = metrics.mContentRect.TopLeft() -
|
||||||
nsIntPoint(NS_lround(scrollOffset.x), NS_lround(scrollOffset.y));
|
nsIntPoint(NS_lround(scrollOffset.x), NS_lround(scrollOffset.y));
|
||||||
gfxRect contentRect = gfxRect(contentOrigin.x, contentOrigin.y,
|
gfxRect contentRect = gfxRect(contentOrigin.x, contentOrigin.y,
|
||||||
|
@ -473,15 +473,17 @@ const SkPMColor* SkGradientShaderBase::getCache32() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Write the clamp colours into the first and last entries of fCache32
|
// Write the clamp colours into the first and last entries of fCache32
|
||||||
fCache32[kCache32ClampLower] = SkPackARGB32(fCacheAlpha,
|
fCache32[kCache32ClampLower] = SkPremultiplyARGBInline(SkMulDiv255Round(SkColorGetA(fOrigColors[0]),
|
||||||
SkColorGetR(fOrigColors[0]),
|
fCacheAlpha),
|
||||||
SkColorGetG(fOrigColors[0]),
|
SkColorGetR(fOrigColors[0]),
|
||||||
SkColorGetB(fOrigColors[0]));
|
SkColorGetG(fOrigColors[0]),
|
||||||
|
SkColorGetB(fOrigColors[0]));
|
||||||
|
|
||||||
fCache32[kCache32ClampUpper] = SkPackARGB32(fCacheAlpha,
|
fCache32[kCache32ClampUpper] = SkPremultiplyARGBInline(SkMulDiv255Round(SkColorGetA(fOrigColors[fColorCount - 1]),
|
||||||
SkColorGetR(fOrigColors[fColorCount - 1]),
|
fCacheAlpha),
|
||||||
SkColorGetG(fOrigColors[fColorCount - 1]),
|
SkColorGetR(fOrigColors[fColorCount - 1]),
|
||||||
SkColorGetB(fOrigColors[fColorCount - 1]));
|
SkColorGetG(fOrigColors[fColorCount - 1]),
|
||||||
|
SkColorGetB(fOrigColors[fColorCount - 1]));
|
||||||
|
|
||||||
return fCache32;
|
return fCache32;
|
||||||
}
|
}
|
||||||
|
@ -960,25 +960,31 @@ struct ParamTraits<mozilla::layers::FrameMetrics>
|
|||||||
|
|
||||||
static void Write(Message* aMsg, const paramType& aParam)
|
static void Write(Message* aMsg, const paramType& aParam)
|
||||||
{
|
{
|
||||||
WriteParam(aMsg, aParam.mCSSContentRect);
|
WriteParam(aMsg, aParam.mScrollableRect);
|
||||||
WriteParam(aMsg, aParam.mViewport);
|
WriteParam(aMsg, aParam.mViewport);
|
||||||
WriteParam(aMsg, aParam.mContentRect);
|
WriteParam(aMsg, aParam.mContentRect);
|
||||||
WriteParam(aMsg, aParam.mViewportScrollOffset);
|
WriteParam(aMsg, aParam.mScrollOffset);
|
||||||
WriteParam(aMsg, aParam.mDisplayPort);
|
WriteParam(aMsg, aParam.mDisplayPort);
|
||||||
|
WriteParam(aMsg, aParam.mCompositionBounds);
|
||||||
WriteParam(aMsg, aParam.mScrollId);
|
WriteParam(aMsg, aParam.mScrollId);
|
||||||
WriteParam(aMsg, aParam.mResolution);
|
WriteParam(aMsg, aParam.mResolution);
|
||||||
|
WriteParam(aMsg, aParam.mZoom);
|
||||||
|
WriteParam(aMsg, aParam.mDevPixelsPerCSSPixel);
|
||||||
WriteParam(aMsg, aParam.mMayHaveTouchListeners);
|
WriteParam(aMsg, aParam.mMayHaveTouchListeners);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
|
static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
|
||||||
{
|
{
|
||||||
return (ReadParam(aMsg, aIter, &aResult->mCSSContentRect) &&
|
return (ReadParam(aMsg, aIter, &aResult->mScrollableRect) &&
|
||||||
ReadParam(aMsg, aIter, &aResult->mViewport) &&
|
ReadParam(aMsg, aIter, &aResult->mViewport) &&
|
||||||
ReadParam(aMsg, aIter, &aResult->mContentRect) &&
|
ReadParam(aMsg, aIter, &aResult->mContentRect) &&
|
||||||
ReadParam(aMsg, aIter, &aResult->mViewportScrollOffset) &&
|
ReadParam(aMsg, aIter, &aResult->mScrollOffset) &&
|
||||||
ReadParam(aMsg, aIter, &aResult->mDisplayPort) &&
|
ReadParam(aMsg, aIter, &aResult->mDisplayPort) &&
|
||||||
|
ReadParam(aMsg, aIter, &aResult->mCompositionBounds) &&
|
||||||
ReadParam(aMsg, aIter, &aResult->mScrollId) &&
|
ReadParam(aMsg, aIter, &aResult->mScrollId) &&
|
||||||
ReadParam(aMsg, aIter, &aResult->mResolution) &&
|
ReadParam(aMsg, aIter, &aResult->mResolution) &&
|
||||||
|
ReadParam(aMsg, aIter, &aResult->mZoom) &&
|
||||||
|
ReadParam(aMsg, aIter, &aResult->mDevPixelsPerCSSPixel) &&
|
||||||
ReadParam(aMsg, aIter, &aResult->mMayHaveTouchListeners));
|
ReadParam(aMsg, aIter, &aResult->mMayHaveTouchListeners));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -5914,24 +5914,7 @@ IonBuilder::jsop_getprop(HandlePropertyName name)
|
|||||||
return makeCallBarrier(getter, 0, false, types, barrier);
|
return makeCallBarrier(getter, 0, false, types, barrier);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the input is guaranteed to be an object, then we want
|
if (unary.ival == MIRType_Object) {
|
||||||
// to specialize it via an slot load or an IC. If it's
|
|
||||||
// guaranteed to be an object or NULL, then we do the same
|
|
||||||
// thing except prefixed by a fallible unbox.
|
|
||||||
bool targetIsObject = (unary.ival == MIRType_Object);
|
|
||||||
|
|
||||||
if (!targetIsObject) {
|
|
||||||
if (unaryTypes.inTypes->objectOrSentinel()) {
|
|
||||||
// Fallibly unwrap the object before getprop. Getprop
|
|
||||||
// on null or undefined will cause exception anyway.
|
|
||||||
MUnbox *unbox = MUnbox::New(obj, MIRType_Object, MUnbox::Fallible);
|
|
||||||
current->add(unbox);
|
|
||||||
obj = unbox;
|
|
||||||
targetIsObject = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (targetIsObject) {
|
|
||||||
MIRType rvalType = MIRType_Value;
|
MIRType rvalType = MIRType_Value;
|
||||||
if (!barrier && !IsNullOrUndefined(unary.rval))
|
if (!barrier && !IsNullOrUndefined(unary.rval))
|
||||||
rvalType = unary.rval;
|
rvalType = unary.rval;
|
||||||
|
@ -373,16 +373,6 @@ TypeInferenceOracle::elementReadGeneric(JSScript *script, jsbytecode *pc, bool *
|
|||||||
|
|
||||||
*cacheable = (obj == MIRType_Object &&
|
*cacheable = (obj == MIRType_Object &&
|
||||||
(id == MIRType_Value || id == MIRType_Int32 || id == MIRType_String));
|
(id == MIRType_Value || id == MIRType_Int32 || id == MIRType_String));
|
||||||
|
|
||||||
// Turn off cacheing if the element is int32 and we've seen non-native objects as the target
|
|
||||||
// of this getelem.
|
|
||||||
if (*cacheable) {
|
|
||||||
if (id == MIRType_Int32) {
|
|
||||||
if (script->analysis()->getCode(pc).nonNativeGetElement)
|
|
||||||
*cacheable = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (*cacheable)
|
if (*cacheable)
|
||||||
*monitorResult = (id == MIRType_String || script->analysis()->getCode(pc).getStringElement);
|
*monitorResult = (id == MIRType_String || script->analysis()->getCode(pc).getStringElement);
|
||||||
else
|
else
|
||||||
|
@ -111,11 +111,10 @@ class Bytecode
|
|||||||
* Dynamically observed state about the execution of this opcode. These are
|
* Dynamically observed state about the execution of this opcode. These are
|
||||||
* hints about the script for use during compilation.
|
* hints about the script for use during compilation.
|
||||||
*/
|
*/
|
||||||
bool arrayWriteHole: 1; /* SETELEM which has written to an array hole. */
|
bool arrayWriteHole: 1; /* SETELEM which has written to an array hole. */
|
||||||
bool getStringElement:1; /* GETELEM which has accessed string properties. */
|
bool getStringElement:1; /* GETELEM which has accessed string properties. */
|
||||||
bool nonNativeGetElement:1; /* GETELEM on a non-native object. */
|
bool accessGetter: 1; /* Property read on a shape with a getter hook. */
|
||||||
bool accessGetter: 1; /* Property read on a shape with a getter hook. */
|
bool notIdempotent: 1; /* Don't use an idempotent cache for this property read. */
|
||||||
bool notIdempotent: 1; /* Don't use an idempotent cache for this property read. */
|
|
||||||
|
|
||||||
/* Stack depth before this opcode. */
|
/* Stack depth before this opcode. */
|
||||||
uint32_t stackDepth;
|
uint32_t stackDepth;
|
||||||
|
@ -571,19 +571,6 @@ class StackTypeSet : public TypeSet
|
|||||||
/* Whether this value may be an object. */
|
/* Whether this value may be an object. */
|
||||||
bool maybeObject() { return unknownObject() || baseObjectCount() > 0; }
|
bool maybeObject() { return unknownObject() || baseObjectCount() > 0; }
|
||||||
|
|
||||||
/*
|
|
||||||
* Whether this typeset represents a potentially sentineled object value:
|
|
||||||
* where the value may be an object, but maybe potentially null or undefined.
|
|
||||||
* This returns false in situations where the value cannot ever be an object.
|
|
||||||
*/
|
|
||||||
bool objectOrSentinel() {
|
|
||||||
TypeFlags flags = TYPE_FLAG_UNDEFINED | TYPE_FLAG_NULL | TYPE_FLAG_ANYOBJECT;
|
|
||||||
if (baseFlags() & (~flags & TYPE_FLAG_BASE_MASK))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return hasAnyFlag(TYPE_FLAG_ANYOBJECT) || baseObjectCount() > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Whether the type set contains objects with any of a set of flags. */
|
/* Whether the type set contains objects with any of a set of flags. */
|
||||||
bool hasObjectFlags(JSContext *cx, TypeObjectFlags flags);
|
bool hasObjectFlags(JSContext *cx, TypeObjectFlags flags);
|
||||||
|
|
||||||
|
@ -686,19 +686,6 @@ GetObjectElementOperation(JSContext *cx, JSOp op, HandleObject obj, const Value
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
bool updateAnalysis = false;
|
|
||||||
RootedScript script(cx, NULL);
|
|
||||||
jsbytecode *pc = NULL;
|
|
||||||
if (!cx->fp()->beginsIonActivation()) {
|
|
||||||
// Don't call GetPcScript from inside Ion since it's expensive.
|
|
||||||
types::TypeScript::GetPcScript(cx, &script, &pc);
|
|
||||||
if (script->hasAnalysis())
|
|
||||||
updateAnalysis = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (updateAnalysis && !obj->isNative())
|
|
||||||
script->analysis()->getCode(pc).nonNativeGetElement = true;
|
|
||||||
|
|
||||||
uint32_t index;
|
uint32_t index;
|
||||||
if (IsDefinitelyIndex(rref, &index)) {
|
if (IsDefinitelyIndex(rref, &index)) {
|
||||||
do {
|
do {
|
||||||
@ -716,8 +703,16 @@ GetObjectElementOperation(JSContext *cx, JSOp op, HandleObject obj, const Value
|
|||||||
return false;
|
return false;
|
||||||
} while(0);
|
} while(0);
|
||||||
} else {
|
} else {
|
||||||
if (updateAnalysis)
|
if (!cx->fp()->beginsIonActivation()) {
|
||||||
script->analysis()->getCode(pc).getStringElement = true;
|
// Don't update getStringElement if called from Ion code, since
|
||||||
|
// ion::GetPcScript is expensive.
|
||||||
|
RootedScript script(cx);
|
||||||
|
jsbytecode *pc;
|
||||||
|
types::TypeScript::GetPcScript(cx, &script, &pc);
|
||||||
|
|
||||||
|
if (script->hasAnalysis())
|
||||||
|
script->analysis()->getCode(pc).getStringElement = true;
|
||||||
|
}
|
||||||
|
|
||||||
SpecialId special;
|
SpecialId special;
|
||||||
res.set(rref);
|
res.set(rref);
|
||||||
|
@ -21,7 +21,8 @@ dictionaries = [
|
|||||||
[ 'CameraRegion', 'nsIDOMCameraManager.idl' ],
|
[ 'CameraRegion', 'nsIDOMCameraManager.idl' ],
|
||||||
[ 'CameraPosition', 'nsIDOMCameraManager.idl' ],
|
[ 'CameraPosition', 'nsIDOMCameraManager.idl' ],
|
||||||
[ 'CameraSelector', 'nsIDOMCameraManager.idl' ],
|
[ 'CameraSelector', 'nsIDOMCameraManager.idl' ],
|
||||||
[ 'CameraPictureOptions', 'nsIDOMCameraManager.idl' ]
|
[ 'CameraPictureOptions', 'nsIDOMCameraManager.idl' ],
|
||||||
|
[ 'CameraRecordingOptions', 'nsIDOMCameraManager.idl' ]
|
||||||
]
|
]
|
||||||
|
|
||||||
# include file names
|
# include file names
|
||||||
|
@ -575,6 +575,7 @@ static void RecordFrameMetrics(nsIFrame* aForFrame,
|
|||||||
bool aMayHaveTouchListeners) {
|
bool aMayHaveTouchListeners) {
|
||||||
nsPresContext* presContext = aForFrame->PresContext();
|
nsPresContext* presContext = aForFrame->PresContext();
|
||||||
int32_t auPerDevPixel = presContext->AppUnitsPerDevPixel();
|
int32_t auPerDevPixel = presContext->AppUnitsPerDevPixel();
|
||||||
|
float auPerCSSPixel = nsPresContext::AppUnitsPerCSSPixel();
|
||||||
|
|
||||||
nsIntRect visible = aVisibleRect.ScaleToNearestPixels(
|
nsIntRect visible = aVisibleRect.ScaleToNearestPixels(
|
||||||
aContainerParameters.mXScale, aContainerParameters.mYScale, auPerDevPixel);
|
aContainerParameters.mXScale, aContainerParameters.mYScale, auPerDevPixel);
|
||||||
@ -582,12 +583,18 @@ static void RecordFrameMetrics(nsIFrame* aForFrame,
|
|||||||
|
|
||||||
FrameMetrics metrics;
|
FrameMetrics metrics;
|
||||||
|
|
||||||
metrics.mViewport = aViewport.ScaleToNearestPixels(
|
metrics.mViewport = mozilla::gfx::Rect(
|
||||||
aContainerParameters.mXScale, aContainerParameters.mYScale, auPerDevPixel);
|
NSAppUnitsToDoublePixels(aViewport.x, auPerDevPixel),
|
||||||
|
NSAppUnitsToDoublePixels(aViewport.y, auPerDevPixel),
|
||||||
|
NSAppUnitsToDoublePixels(aViewport.width, auPerDevPixel),
|
||||||
|
NSAppUnitsToDoublePixels(aViewport.height, auPerDevPixel));
|
||||||
|
|
||||||
if (aDisplayPort) {
|
if (aDisplayPort) {
|
||||||
metrics.mDisplayPort = aDisplayPort->ScaleToNearestPixels(
|
metrics.mDisplayPort = mozilla::gfx::Rect(
|
||||||
aContainerParameters.mXScale, aContainerParameters.mYScale, auPerDevPixel);
|
NSAppUnitsToDoublePixels(aDisplayPort->x, auPerDevPixel),
|
||||||
|
NSAppUnitsToDoublePixels(aDisplayPort->y, auPerDevPixel),
|
||||||
|
NSAppUnitsToDoublePixels(aDisplayPort->width, auPerDevPixel),
|
||||||
|
NSAppUnitsToDoublePixels(aDisplayPort->height, auPerDevPixel));
|
||||||
}
|
}
|
||||||
|
|
||||||
nsIScrollableFrame* scrollableFrame = nullptr;
|
nsIScrollableFrame* scrollableFrame = nullptr;
|
||||||
@ -598,7 +605,7 @@ static void RecordFrameMetrics(nsIFrame* aForFrame,
|
|||||||
nsRect contentBounds = scrollableFrame->GetScrollRange();
|
nsRect contentBounds = scrollableFrame->GetScrollRange();
|
||||||
contentBounds.width += scrollableFrame->GetScrollPortRect().width;
|
contentBounds.width += scrollableFrame->GetScrollPortRect().width;
|
||||||
contentBounds.height += scrollableFrame->GetScrollPortRect().height;
|
contentBounds.height += scrollableFrame->GetScrollPortRect().height;
|
||||||
metrics.mCSSContentRect =
|
metrics.mScrollableRect =
|
||||||
mozilla::gfx::Rect(nsPresContext::AppUnitsToFloatCSSPixels(contentBounds.x),
|
mozilla::gfx::Rect(nsPresContext::AppUnitsToFloatCSSPixels(contentBounds.x),
|
||||||
nsPresContext::AppUnitsToFloatCSSPixels(contentBounds.y),
|
nsPresContext::AppUnitsToFloatCSSPixels(contentBounds.y),
|
||||||
nsPresContext::AppUnitsToFloatCSSPixels(contentBounds.width),
|
nsPresContext::AppUnitsToFloatCSSPixels(contentBounds.width),
|
||||||
@ -606,13 +613,13 @@ static void RecordFrameMetrics(nsIFrame* aForFrame,
|
|||||||
metrics.mContentRect = contentBounds.ScaleToNearestPixels(
|
metrics.mContentRect = contentBounds.ScaleToNearestPixels(
|
||||||
aContainerParameters.mXScale, aContainerParameters.mYScale, auPerDevPixel);
|
aContainerParameters.mXScale, aContainerParameters.mYScale, auPerDevPixel);
|
||||||
nsPoint scrollPosition = scrollableFrame->GetScrollPosition();
|
nsPoint scrollPosition = scrollableFrame->GetScrollPosition();
|
||||||
metrics.mViewportScrollOffset = mozilla::gfx::Point(
|
metrics.mScrollOffset = mozilla::gfx::Point(
|
||||||
NSAppUnitsToDoublePixels(scrollPosition.x, auPerDevPixel) * aContainerParameters.mXScale,
|
NSAppUnitsToDoublePixels(scrollPosition.x, auPerCSSPixel),
|
||||||
NSAppUnitsToDoublePixels(scrollPosition.y, auPerDevPixel) * aContainerParameters.mYScale);
|
NSAppUnitsToDoublePixels(scrollPosition.y, auPerCSSPixel));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
nsRect contentBounds = aForFrame->GetRect();
|
nsRect contentBounds = aForFrame->GetRect();
|
||||||
metrics.mCSSContentRect =
|
metrics.mScrollableRect =
|
||||||
mozilla::gfx::Rect(nsPresContext::AppUnitsToFloatCSSPixels(contentBounds.x),
|
mozilla::gfx::Rect(nsPresContext::AppUnitsToFloatCSSPixels(contentBounds.x),
|
||||||
nsPresContext::AppUnitsToFloatCSSPixels(contentBounds.y),
|
nsPresContext::AppUnitsToFloatCSSPixels(contentBounds.y),
|
||||||
nsPresContext::AppUnitsToFloatCSSPixels(contentBounds.width),
|
nsPresContext::AppUnitsToFloatCSSPixels(contentBounds.width),
|
||||||
@ -626,6 +633,8 @@ static void RecordFrameMetrics(nsIFrame* aForFrame,
|
|||||||
nsIPresShell* presShell = presContext->GetPresShell();
|
nsIPresShell* presShell = presContext->GetPresShell();
|
||||||
metrics.mResolution = gfxSize(presShell->GetXResolution(), presShell->GetYResolution());
|
metrics.mResolution = gfxSize(presShell->GetXResolution(), presShell->GetYResolution());
|
||||||
|
|
||||||
|
metrics.mDevPixelsPerCSSPixel = auPerCSSPixel / auPerDevPixel;
|
||||||
|
|
||||||
metrics.mMayHaveTouchListeners = aMayHaveTouchListeners;
|
metrics.mMayHaveTouchListeners = aMayHaveTouchListeners;
|
||||||
|
|
||||||
aRoot->SetFrameMetrics(metrics);
|
aRoot->SetFrameMetrics(metrics);
|
||||||
@ -1070,8 +1079,10 @@ void nsDisplayList::PaintForFrame(nsDisplayListBuilder* aBuilder,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nsRect viewport(aBuilder->ToReferenceFrame(aForFrame), aForFrame->GetSize());
|
||||||
|
|
||||||
RecordFrameMetrics(aForFrame, rootScrollFrame,
|
RecordFrameMetrics(aForFrame, rootScrollFrame,
|
||||||
root, mVisibleRect, mVisibleRect,
|
root, mVisibleRect, viewport,
|
||||||
(usingDisplayport ? &displayport : nullptr), id,
|
(usingDisplayport ? &displayport : nullptr), id,
|
||||||
containerParameters, mayHaveTouchListeners);
|
containerParameters, mayHaveTouchListeners);
|
||||||
if (usingDisplayport &&
|
if (usingDisplayport &&
|
||||||
|
@ -158,7 +158,7 @@ ComputeShadowTreeTransform(nsIFrame* aContainerFrame,
|
|||||||
nsIntPoint scrollOffset =
|
nsIntPoint scrollOffset =
|
||||||
aConfig.mScrollOffset.ToNearestPixels(auPerDevPixel);
|
aConfig.mScrollOffset.ToNearestPixels(auPerDevPixel);
|
||||||
// metricsScrollOffset is in layer coordinates.
|
// metricsScrollOffset is in layer coordinates.
|
||||||
gfx::Point metricsScrollOffset = aMetrics->mViewportScrollOffset;
|
gfx::Point metricsScrollOffset = aMetrics->GetScrollOffsetInLayerPixels();
|
||||||
nsIntPoint roundedMetricsScrollOffset =
|
nsIntPoint roundedMetricsScrollOffset =
|
||||||
nsIntPoint(NS_lround(metricsScrollOffset.x), NS_lround(metricsScrollOffset.y));
|
nsIntPoint(NS_lround(metricsScrollOffset.x), NS_lround(metricsScrollOffset.y));
|
||||||
|
|
||||||
@ -217,7 +217,9 @@ BuildListForLayer(Layer* aLayer,
|
|||||||
nsRect bounds;
|
nsRect bounds;
|
||||||
{
|
{
|
||||||
nscoord auPerDevPixel = aSubdocFrame->PresContext()->AppUnitsPerDevPixel();
|
nscoord auPerDevPixel = aSubdocFrame->PresContext()->AppUnitsPerDevPixel();
|
||||||
bounds = metrics->mViewport.ToAppUnits(auPerDevPixel);
|
gfx::Rect viewport = metrics->mViewport;
|
||||||
|
bounds = nsIntRect(viewport.x, viewport.y,
|
||||||
|
viewport.width, viewport.height).ToAppUnits(auPerDevPixel);
|
||||||
ApplyTransform(bounds, tmpTransform, auPerDevPixel);
|
ApplyTransform(bounds, tmpTransform, auPerDevPixel);
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -362,6 +364,7 @@ BuildViewMap(ViewMap& oldContentViews, ViewMap& newContentViews,
|
|||||||
if (metrics.IsScrollable()) {
|
if (metrics.IsScrollable()) {
|
||||||
nscoord auPerDevPixel = aFrameLoader->GetPrimaryFrameOfOwningContent()
|
nscoord auPerDevPixel = aFrameLoader->GetPrimaryFrameOfOwningContent()
|
||||||
->PresContext()->AppUnitsPerDevPixel();
|
->PresContext()->AppUnitsPerDevPixel();
|
||||||
|
nscoord auPerCSSPixel = auPerDevPixel * metrics.mDevPixelsPerCSSPixel;
|
||||||
nsContentView* view = FindViewForId(oldContentViews, scrollId);
|
nsContentView* view = FindViewForId(oldContentViews, scrollId);
|
||||||
if (view) {
|
if (view) {
|
||||||
// View already exists. Be sure to propagate scales for any values
|
// View already exists. Be sure to propagate scales for any values
|
||||||
@ -392,8 +395,8 @@ BuildViewMap(ViewMap& oldContentViews, ViewMap& newContentViews,
|
|||||||
// The default scale is 1, so no need to propagate scale down.
|
// The default scale is 1, so no need to propagate scale down.
|
||||||
ViewConfig config;
|
ViewConfig config;
|
||||||
config.mScrollOffset = nsPoint(
|
config.mScrollOffset = nsPoint(
|
||||||
NSIntPixelsToAppUnits(metrics.mViewportScrollOffset.x, auPerDevPixel) * aXScale,
|
NSIntPixelsToAppUnits(metrics.mScrollOffset.x, auPerCSSPixel) * aXScale,
|
||||||
NSIntPixelsToAppUnits(metrics.mViewportScrollOffset.y, auPerDevPixel) * aYScale);
|
NSIntPixelsToAppUnits(metrics.mScrollOffset.y, auPerCSSPixel) * aYScale);
|
||||||
view = new nsContentView(aFrameLoader, scrollId, config);
|
view = new nsContentView(aFrameLoader, scrollId, config);
|
||||||
view->mParentScaleX = aAccConfigXScale;
|
view->mParentScaleX = aAccConfigXScale;
|
||||||
view->mParentScaleY = aAccConfigYScale;
|
view->mParentScaleY = aAccConfigYScale;
|
||||||
@ -728,7 +731,8 @@ void
|
|||||||
RenderFrameParent::NotifyDimensionsChanged(int width, int height)
|
RenderFrameParent::NotifyDimensionsChanged(int width, int height)
|
||||||
{
|
{
|
||||||
if (mPanZoomController) {
|
if (mPanZoomController) {
|
||||||
mPanZoomController->UpdateViewportSize(width, height);
|
mPanZoomController->UpdateCompositionBounds(
|
||||||
|
nsIntRect(0, 0, width, height));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -909,6 +913,14 @@ RenderFrameParent::ContentReceivedTouch(bool aPreventDefault)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
RenderFrameParent::UpdateZoomConstraints(bool aAllowZoom, float aMinZoom, float aMaxZoom)
|
||||||
|
{
|
||||||
|
if (mPanZoomController) {
|
||||||
|
mPanZoomController->UpdateZoomConstraints(aAllowZoom, aMinZoom, aMaxZoom);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace layout
|
} // namespace layout
|
||||||
} // namespace mozilla
|
} // namespace mozilla
|
||||||
|
|
||||||
|
@ -101,6 +101,8 @@ public:
|
|||||||
|
|
||||||
void ContentReceivedTouch(bool aPreventDefault);
|
void ContentReceivedTouch(bool aPreventDefault);
|
||||||
|
|
||||||
|
void UpdateZoomConstraints(bool aAllowZoom, float aMinZoom, float aMaxZoom);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void ActorDestroy(ActorDestroyReason why) MOZ_OVERRIDE;
|
void ActorDestroy(ActorDestroyReason why) MOZ_OVERRIDE;
|
||||||
|
|
||||||
|
@ -156,6 +156,7 @@ abstract public class GeckoApp
|
|||||||
public static int mOrientation;
|
public static int mOrientation;
|
||||||
private boolean mIsRestoringActivity;
|
private boolean mIsRestoringActivity;
|
||||||
private String mCurrentResponse = "";
|
private String mCurrentResponse = "";
|
||||||
|
public static boolean sIsUsingCustomProfile = false;
|
||||||
|
|
||||||
private PromptService mPromptService;
|
private PromptService mPromptService;
|
||||||
private Favicons mFavicons;
|
private Favicons mFavicons;
|
||||||
@ -1554,6 +1555,7 @@ abstract public class GeckoApp
|
|||||||
if (profileName == null)
|
if (profileName == null)
|
||||||
profileName = "default";
|
profileName = "default";
|
||||||
}
|
}
|
||||||
|
GeckoApp.sIsUsingCustomProfile = true;
|
||||||
}
|
}
|
||||||
if (profileName != null || profilePath != null) {
|
if (profileName != null || profilePath != null) {
|
||||||
mProfile = GeckoProfile.get(this, profileName, profilePath);
|
mProfile = GeckoProfile.get(this, profileName, profilePath);
|
||||||
@ -2252,7 +2254,8 @@ abstract public class GeckoApp
|
|||||||
ProfileMigrator profileMigrator = new ProfileMigrator(app);
|
ProfileMigrator profileMigrator = new ProfileMigrator(app);
|
||||||
|
|
||||||
// Do a migration run on the first start after an upgrade.
|
// Do a migration run on the first start after an upgrade.
|
||||||
if (!profileMigrator.hasMigrationRun()) {
|
if (!GeckoApp.sIsUsingCustomProfile &&
|
||||||
|
!profileMigrator.hasMigrationRun()) {
|
||||||
// Show the "Setting up Fennec" screen if this takes
|
// Show the "Setting up Fennec" screen if this takes
|
||||||
// a while.
|
// a while.
|
||||||
final SetupScreen setupScreen = new SetupScreen(app);
|
final SetupScreen setupScreen = new SetupScreen(app);
|
||||||
@ -2296,7 +2299,7 @@ abstract public class GeckoApp
|
|||||||
|
|
||||||
private void checkMigrateSync() {
|
private void checkMigrateSync() {
|
||||||
final File profileDir = getProfile().getDir();
|
final File profileDir = getProfile().getDir();
|
||||||
if (profileDir != null) {
|
if (!GeckoApp.sIsUsingCustomProfile && profileDir != null) {
|
||||||
final GeckoApp app = GeckoApp.mAppContext;
|
final GeckoApp app = GeckoApp.mAppContext;
|
||||||
ProfileMigrator profileMigrator = new ProfileMigrator(app);
|
ProfileMigrator profileMigrator = new ProfileMigrator(app);
|
||||||
if (!profileMigrator.hasSyncMigrated()) {
|
if (!profileMigrator.hasSyncMigrated()) {
|
||||||
|
@ -148,7 +148,8 @@ public final class GeckoProfile {
|
|||||||
try {
|
try {
|
||||||
// Check for old profiles that may need migration.
|
// Check for old profiles that may need migration.
|
||||||
ProfileMigrator profileMigrator = new ProfileMigrator(mContext);
|
ProfileMigrator profileMigrator = new ProfileMigrator(mContext);
|
||||||
if (!profileMigrator.isProfileMoved()) {
|
if (!GeckoApp.sIsUsingCustomProfile &&
|
||||||
|
!profileMigrator.isProfileMoved()) {
|
||||||
Log.i(LOGTAG, "New installation or update, checking for old profiles.");
|
Log.i(LOGTAG, "New installation or update, checking for old profiles.");
|
||||||
profileMigrator.launchMoveProfile();
|
profileMigrator.launchMoveProfile();
|
||||||
}
|
}
|
||||||
|
@ -687,6 +687,15 @@ nsDNSService::Resolve(const nsACString &hostname,
|
|||||||
uint32_t flags,
|
uint32_t flags,
|
||||||
nsIDNSRecord **result)
|
nsIDNSRecord **result)
|
||||||
{
|
{
|
||||||
|
NS_WARNING("Do not use synchronous DNS resolution! This API may be removed soon.");
|
||||||
|
|
||||||
|
// We will not allow this to be called on the main thread. This is transitional
|
||||||
|
// and a bit of a test for removing the synchronous API entirely.
|
||||||
|
if (NS_IsMainThread()) {
|
||||||
|
NS_ERROR("Synchronous DNS resolve failing - not allowed on the main thread!");
|
||||||
|
return NS_ERROR_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
// grab reference to global host resolver and IDN service. beware
|
// grab reference to global host resolver and IDN service. beware
|
||||||
// simultaneous shutdown!!
|
// simultaneous shutdown!!
|
||||||
nsRefPtr<nsHostResolver> res;
|
nsRefPtr<nsHostResolver> res;
|
||||||
|
@ -59,9 +59,8 @@ interface nsIDNSService : nsISupports
|
|||||||
in nsresult aReason);
|
in nsresult aReason);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* called to synchronously resolve a hostname. warning this method may
|
* Called to synchronously resolve a hostname. This method will fail
|
||||||
* block the calling thread for a long period of time. it is extremely
|
* if called from the main thread.
|
||||||
* unwise to call this function on the UI thread of an application.
|
|
||||||
*
|
*
|
||||||
* @param aHostName
|
* @param aHostName
|
||||||
* the hostname or IP-address-literal to resolve.
|
* the hostname or IP-address-literal to resolve.
|
||||||
|
@ -118,6 +118,10 @@ ifeq (gonk,$(MOZ_WIDGET_TOOLKIT))
|
|||||||
STATIC_LIBS += moznetd_s
|
STATIC_LIBS += moznetd_s
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
ifdef MOZ_B2G_CAMERA #{
|
||||||
|
OS_LIBS += -lstagefright -lstagefright_omx
|
||||||
|
endif #}
|
||||||
|
|
||||||
ifdef MOZ_IPDL_TESTS
|
ifdef MOZ_IPDL_TESTS
|
||||||
STATIC_LIBS += ipdlunittest_s
|
STATIC_LIBS += ipdlunittest_s
|
||||||
endif
|
endif
|
||||||
|
Loading…
Reference in New Issue
Block a user