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
bb75747da7
@ -16,7 +16,7 @@
|
||||
<ShortName>Google</ShortName>
|
||||
<Description>Google Search</Description>
|
||||
<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="text/html" method="GET" template="https://www.google.com/search">
|
||||
#expand __GOOGLE_PARAMS__
|
||||
|
@ -1,3 +1,4 @@
|
||||
|
||||
dnl -*- Mode: Autoconf; tab-width: 4; indent-tabs-mode: nil; -*-
|
||||
dnl vi: set tabstop=4 shiftwidth=4 expandtab syntax=m4:
|
||||
dnl This Source Code Form is subject to the terms of the Mozilla Public
|
||||
@ -197,7 +198,7 @@ if test -n "$gonkdir" ; then
|
||||
;;
|
||||
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"
|
||||
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.
|
||||
|
@ -2,7 +2,7 @@
|
||||
<body onpopstate='opener.page1Popstate();' onload='opener.page1Load();'
|
||||
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>
|
||||
</html>
|
||||
|
@ -206,42 +206,20 @@ const ContentPanning = {
|
||||
let metrics = data.json;
|
||||
let displayPort = metrics.displayPort;
|
||||
|
||||
let screenWidth = metrics.screenSize.width;
|
||||
let screenHeight = metrics.screenSize.height;
|
||||
let compositionWidth = metrics.compositionBounds.width;
|
||||
let compositionHeight = metrics.compositionBounds.height;
|
||||
|
||||
let x = metrics.x;
|
||||
let y = metrics.y;
|
||||
|
||||
this._zoom = metrics.zoom;
|
||||
this._viewport = new Rect(x, y,
|
||||
screenWidth / metrics.zoom,
|
||||
screenHeight / metrics.zoom);
|
||||
compositionWidth / metrics.zoom,
|
||||
compositionHeight / metrics.zoom);
|
||||
this._cssPageRect = new Rect(metrics.cssPageRect.x,
|
||||
metrics.cssPageRect.y,
|
||||
metrics.cssPageRect.width,
|
||||
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) {
|
||||
@ -272,7 +250,7 @@ const ContentPanning = {
|
||||
|
||||
let cssPageRect = this._cssPageRect;
|
||||
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.w + 2 * margin,
|
||||
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
|
||||
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);
|
||||
}
|
||||
|
||||
@ -223,6 +223,13 @@ CameraControlImpl::StopPreview()
|
||||
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
|
||||
CameraControlImpl::ReceiveFrame(void* aBuffer, ImageFormat aFormat, FrameBuilder aBuilder)
|
||||
{
|
||||
|
@ -8,6 +8,7 @@
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsDOMFile.h"
|
||||
#include "DictionaryHelpers.h"
|
||||
#include "nsIDOMDeviceStorage.h"
|
||||
#include "nsIDOMCameraManager.h"
|
||||
#include "ICameraControl.h"
|
||||
#include "CameraCommon.h"
|
||||
@ -25,6 +26,7 @@ class StartRecordingTask;
|
||||
class StopRecordingTask;
|
||||
class SetParameterTask;
|
||||
class GetParameterTask;
|
||||
class GetPreviewStreamVideoModeTask;
|
||||
|
||||
class DOMCameraPreview;
|
||||
|
||||
@ -39,6 +41,7 @@ class CameraControlImpl : public ICameraControl
|
||||
friend class StopRecordingTask;
|
||||
friend class SetParameterTask;
|
||||
friend class GetParameterTask;
|
||||
friend class GetPreviewStreamVideoModeTask;
|
||||
|
||||
public:
|
||||
CameraControlImpl(uint32_t aCameraId, nsIThread* aCameraThread)
|
||||
@ -64,8 +67,9 @@ public:
|
||||
void StopPreview();
|
||||
nsresult AutoFocus(nsICameraAutoFocusCallback* 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 GetPreviewStreamVideoMode(CameraRecordingOptions* aOptions, nsICameraPreviewStreamCallback* onSuccess, nsICameraErrorCallback* onError);
|
||||
|
||||
nsresult Set(uint32_t aKey, const nsAString& aValue);
|
||||
nsresult Get(uint32_t aKey, nsAString& aValue);
|
||||
@ -111,6 +115,7 @@ protected:
|
||||
virtual nsresult StopRecordingImpl(StopRecordingTask* aStopRecording) = 0;
|
||||
virtual nsresult PushParametersImpl() = 0;
|
||||
virtual nsresult PullParametersImpl() = 0;
|
||||
virtual nsresult GetPreviewStreamVideoModeImpl(GetPreviewStreamVideoModeTask* aGetPreviewStreamVideoMode) = 0;
|
||||
|
||||
uint32_t mCameraId;
|
||||
nsCOMPtr<nsIThread> mCameraThread;
|
||||
@ -347,9 +352,8 @@ public:
|
||||
class StartRecordingResult : public nsRunnable
|
||||
{
|
||||
public:
|
||||
StartRecordingResult(nsIDOMMediaStream* aStream, nsICameraStartRecordingCallback* onSuccess)
|
||||
: mStream(aStream)
|
||||
, mOnSuccessCb(onSuccess)
|
||||
StartRecordingResult(nsICameraStartRecordingCallback* onSuccess)
|
||||
: mOnSuccessCb(onSuccess)
|
||||
{ }
|
||||
|
||||
virtual ~StartRecordingResult() { }
|
||||
@ -359,13 +363,12 @@ public:
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (mOnSuccessCb) {
|
||||
mOnSuccessCb->HandleEvent(mStream);
|
||||
mOnSuccessCb->HandleEvent();
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
protected:
|
||||
nsCOMPtr<nsIDOMMediaStream> mStream;
|
||||
nsCOMPtr<nsICameraStartRecordingCallback> mOnSuccessCb;
|
||||
};
|
||||
|
||||
@ -373,9 +376,10 @@ protected:
|
||||
class StartRecordingTask : public nsRunnable
|
||||
{
|
||||
public:
|
||||
StartRecordingTask(CameraControlImpl* aCameraControl, CameraSize aSize, nsICameraStartRecordingCallback* onSuccess, nsICameraErrorCallback* onError)
|
||||
: mSize(aSize)
|
||||
, mCameraControl(aCameraControl)
|
||||
StartRecordingTask(CameraControlImpl* aCameraControl, nsIDOMDeviceStorage* aStorageArea, const nsAString& aFilename, nsICameraStartRecordingCallback* onSuccess, nsICameraErrorCallback* onError)
|
||||
: mCameraControl(aCameraControl)
|
||||
, mStorageArea(aStorageArea)
|
||||
, mFilename(aFilename)
|
||||
, mOnSuccessCb(onSuccess)
|
||||
, mOnErrorCb(onError)
|
||||
{
|
||||
@ -391,17 +395,21 @@ public:
|
||||
{
|
||||
DOM_CAMERA_LOGT("%s:%d\n", __func__, __LINE__);
|
||||
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")));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
CameraSize mSize;
|
||||
nsRefPtr<CameraControlImpl> mCameraControl;
|
||||
nsCOMPtr<nsIDOMDeviceStorage> mStorageArea;
|
||||
nsString mFilename;
|
||||
nsCOMPtr<nsICameraStartRecordingCallback> mOnSuccessCb;
|
||||
nsCOMPtr<nsICameraErrorCallback> mOnErrorCb;
|
||||
};
|
||||
@ -491,6 +499,67 @@ public:
|
||||
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
|
||||
|
||||
#endif // DOM_CAMERA_CAMERACONTROLIMPL_H
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include "nsThread.h"
|
||||
#include "mozilla/Services.h"
|
||||
#include "nsIObserverService.h"
|
||||
#include "nsIDOMDeviceStorage.h"
|
||||
#include "DOMCameraManager.h"
|
||||
#include "DOMCameraCapabilities.h"
|
||||
#include "DOMCameraControl.h"
|
||||
@ -218,16 +219,12 @@ nsDOMCameraControl::SetOnShutter(nsICameraShutterCallback* aOnShutter)
|
||||
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
|
||||
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);
|
||||
|
||||
CameraSize size;
|
||||
nsresult rv = size.Init(cx, &aOptions);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
|
||||
if (!obs) {
|
||||
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",
|
||||
NS_LITERAL_STRING("starting").get());
|
||||
|
||||
return mCameraControl->StartRecording(size, onSuccess, onError);
|
||||
return mCameraControl->StartRecording(storageArea, filename, onSuccess, onError);
|
||||
}
|
||||
|
||||
/* void stopRecording (); */
|
||||
@ -316,6 +313,19 @@ nsDOMCameraControl::TakePicture(const JS::Value& aOptions, nsICameraTakePictureC
|
||||
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
|
||||
{
|
||||
public:
|
||||
|
@ -15,6 +15,10 @@
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <libgen.h>
|
||||
#include "base/basictypes.h"
|
||||
#include "libcameraservice/CameraHardwareInterface.h"
|
||||
#include "camera/CameraParameters.h"
|
||||
@ -23,6 +27,8 @@
|
||||
#include "nsMemory.h"
|
||||
#include "jsapi.h"
|
||||
#include "nsThread.h"
|
||||
#include <media/MediaProfiles.h>
|
||||
#include "nsDirectoryServiceDefs.h" // for NS_GetSpecialDirectory
|
||||
#include "nsPrintfCString.h"
|
||||
#include "DOMCameraManager.h"
|
||||
#include "GonkCameraHwMgr.h"
|
||||
@ -547,19 +553,27 @@ nsGonkCameraControl::StartPreviewImpl(StartPreviewTask* aStartPreview)
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsGonkCameraControl::StopPreviewImpl(StopPreviewTask* aStopPreview)
|
||||
nsGonkCameraControl::StopPreviewInternal(bool aForced)
|
||||
{
|
||||
DOM_CAMERA_LOGI("%s: stopping preview\n", __func__);
|
||||
|
||||
// StopPreview() is a synchronous call--it doesn't return
|
||||
// until the camera preview thread exits.
|
||||
GonkCameraHardware::StopPreview(mHwHandle);
|
||||
mDOMPreview->Stopped();
|
||||
mDOMPreview = nullptr;
|
||||
if (mDOMPreview) {
|
||||
GonkCameraHardware::StopPreview(mHwHandle);
|
||||
mDOMPreview->Stopped(aForced);
|
||||
mDOMPreview = nullptr;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsGonkCameraControl::StopPreviewImpl(StopPreviewTask* aStopPreview)
|
||||
{
|
||||
return StopPreviewInternal();
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsGonkCameraControl::AutoFocusImpl(AutoFocusTask* aAutoFocus)
|
||||
{
|
||||
@ -691,13 +705,71 @@ nsGonkCameraControl::PullParametersImpl()
|
||||
nsresult
|
||||
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
|
||||
nsGonkCameraControl::StopRecordingImpl(StopRecordingTask* aStopRecording)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
mRecorder->stop();
|
||||
delete mRecorder;
|
||||
mRecorder = nullptr;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
@ -809,6 +881,152 @@ nsGonkCameraControl::SetPreviewSize(uint32_t aWidth, uint32_t aHeight)
|
||||
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.
|
||||
namespace mozilla {
|
||||
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include "DOMCameraControl.h"
|
||||
#include "CameraControlImpl.h"
|
||||
#include "CameraCommon.h"
|
||||
#include "GonkRecorder.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
@ -47,6 +48,9 @@ public:
|
||||
void SetParameter(uint32_t aKey, const nsTArray<dom::CameraRegion>& aRegions);
|
||||
nsresult PushParameters();
|
||||
|
||||
nsresult SetupRecording(int aFd);
|
||||
nsresult SetupVideoMode();
|
||||
|
||||
void AutoFocusComplete(bool aSuccess);
|
||||
void TakePictureComplete(uint8_t* aData, uint32_t aLength);
|
||||
|
||||
@ -56,12 +60,14 @@ protected:
|
||||
nsresult GetPreviewStreamImpl(GetPreviewStreamTask* aGetPreviewStream);
|
||||
nsresult StartPreviewImpl(StartPreviewTask* aStartPreview);
|
||||
nsresult StopPreviewImpl(StopPreviewTask* aStopPreview);
|
||||
nsresult StopPreviewInternal(bool aForced = false);
|
||||
nsresult AutoFocusImpl(AutoFocusTask* aAutoFocus);
|
||||
nsresult TakePictureImpl(TakePictureTask* aTakePicture);
|
||||
nsresult StartRecordingImpl(StartRecordingTask* aStartRecording);
|
||||
nsresult StopRecordingImpl(StopRecordingTask* aStopRecording);
|
||||
nsresult PushParametersImpl();
|
||||
nsresult PullParametersImpl();
|
||||
nsresult GetPreviewStreamVideoModeImpl(GetPreviewStreamVideoModeTask* aGetPreviewStreamVideoMode);
|
||||
|
||||
void SetPreviewSize(uint32_t aWidth, uint32_t aHeight);
|
||||
|
||||
@ -84,6 +90,27 @@ protected:
|
||||
uint32_t mFps;
|
||||
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:
|
||||
nsGonkCameraControl(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
|
||||
GonkCameraHardware::Init()
|
||||
{
|
||||
@ -162,7 +190,7 @@ GonkCameraHardware::Init()
|
||||
if (sHwHandle == 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;
|
||||
}
|
||||
|
||||
@ -314,3 +342,81 @@ GonkCameraHardware::StopPreview(uint32_t aHwHandle)
|
||||
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 "binder/IMemory.h"
|
||||
#include "mozilla/ReentrantMonitor.h"
|
||||
#include "GonkCameraListener.h"
|
||||
#include <utils/threads.h>
|
||||
|
||||
#include "GonkCameraControl.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 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:
|
||||
virtual void OnNewFrame() MOZ_OVERRIDE;
|
||||
@ -60,6 +63,11 @@ public:
|
||||
static void StopPreview(uint32_t aHwHandle);
|
||||
static int PushParameters(uint32_t aHwHandle, const 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:
|
||||
static GonkCameraHardware* sHw;
|
||||
@ -93,6 +101,7 @@ protected:
|
||||
struct timespec mStart;
|
||||
struct timespec mAutoFocusStart;
|
||||
#endif
|
||||
sp<GonkCameraListener> mListener;
|
||||
bool mInitialized;
|
||||
|
||||
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
|
||||
|
||||
#include "jsapi.h"
|
||||
#include "nsIDOMDeviceStorage.h"
|
||||
#include "nsIDOMCameraManager.h"
|
||||
#include "DictionaryHelpers.h"
|
||||
#include "CameraCommon.h"
|
||||
@ -26,8 +27,9 @@ public:
|
||||
virtual void StopPreview() = 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 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 GetPreviewStreamVideoMode(CameraRecordingOptions* aOptions, nsICameraPreviewStreamCallback* onSuccess, nsICameraErrorCallback* onError) = 0;
|
||||
|
||||
virtual nsresult Set(uint32_t aKey, const nsAString& aValue) = 0;
|
||||
virtual nsresult Get(uint32_t aKey, nsAString& aValue) = 0;
|
||||
|
@ -32,6 +32,9 @@ CPPSRCS += \
|
||||
GonkCameraControl.cpp \
|
||||
GonkCameraHwMgr.cpp \
|
||||
GonkNativeWindow.cpp \
|
||||
GonkRecorder.cpp \
|
||||
GonkCameraSource.cpp \
|
||||
AudioParameter.cpp \
|
||||
$(NULL)
|
||||
else ifeq (gonk,$(MOZ_WIDGET_TOOLKIT))
|
||||
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 nsIDOMDeviceStorage;
|
||||
|
||||
/* Used to set the dimensions of a captured picture,
|
||||
a preview stream, a video capture stream, etc. */
|
||||
@ -108,10 +109,8 @@ interface nsICameraCapabilities : nsISupports
|
||||
readonly attribute jsval videoSizes;
|
||||
};
|
||||
|
||||
/*
|
||||
These properties only affect the captured image;
|
||||
invalid property settings are ignored.
|
||||
*/
|
||||
/* These properties only affect the captured image;
|
||||
invalid property settings are ignored. */
|
||||
dictionary CameraPictureOptions
|
||||
{
|
||||
/* an object with a combination of 'height' and 'width' properties
|
||||
@ -147,6 +146,14 @@ dictionary CameraPictureOptions
|
||||
jsval position;
|
||||
};
|
||||
|
||||
/* These properties affect video recording. */
|
||||
dictionary CameraRecordingOptions
|
||||
{
|
||||
long width;
|
||||
long height;
|
||||
long rotation;
|
||||
};
|
||||
|
||||
[scriptable, function, uuid(0444a687-4bc9-462c-8246-5423f0fe46a4)]
|
||||
interface nsICameraPreviewStreamCallback : nsISupports
|
||||
{
|
||||
@ -165,10 +172,10 @@ interface nsICameraTakePictureCallback : nsISupports
|
||||
void handleEvent(in nsIDOMBlob picture);
|
||||
};
|
||||
|
||||
[scriptable, function, uuid(ac43f123-529c-48d3-84dd-ad206b7aca9b)]
|
||||
[scriptable, function, uuid(89a762f8-581b-410a-ad86-e2bd2113ad82)]
|
||||
interface nsICameraStartRecordingCallback : nsISupports
|
||||
{
|
||||
void handleEvent(in nsIDOMMediaStream stream);
|
||||
void handleEvent();
|
||||
};
|
||||
|
||||
[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
|
||||
any video recorded by the camera.
|
||||
*/
|
||||
[scriptable, uuid(b8949e5c-55b0-49dd-99a9-68d11342915a)]
|
||||
[scriptable, uuid(469e0462-59e4-4ed5-afa9-aecd1256ee30)]
|
||||
interface nsICameraControl : nsISupports
|
||||
{
|
||||
readonly attribute nsICameraCapabilities capabilities;
|
||||
@ -290,15 +297,21 @@ interface nsICameraControl : nsISupports
|
||||
[implicit_jscontext]
|
||||
void takePicture(in jsval aOptions, in nsICameraTakePictureCallback onSuccess, [optional] in nsICameraErrorCallback onError);
|
||||
|
||||
/* start recording video; 'aOptions' define the frame size of to
|
||||
capture, chosen from capabilities.videoSizes, e.g.:
|
||||
/* get a media stream to be used as a camera viewfinder in video mode; 'aOptions'
|
||||
define the frame size of the video capture, chosen from capabilities.videoSizes, e.g.:
|
||||
{
|
||||
width: 640,
|
||||
height: 480
|
||||
height: 480,
|
||||
rotation: 90
|
||||
}
|
||||
*/
|
||||
[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. */
|
||||
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());
|
||||
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);
|
||||
break;
|
||||
}
|
||||
|
@ -1913,6 +1913,17 @@ nsDOMDeviceStorage::Stat(nsIDOMDOMRequest** aRetval)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDOMDeviceStorage::GetRootDirectory(nsIFile** aRootDirectory)
|
||||
{
|
||||
if (!mRootDirectory) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIFile> file;
|
||||
return mRootDirectory->Clone(aRootDirectory);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDOMDeviceStorage::Enumerate(const JS::Value & aName,
|
||||
const JS::Value & aOptions,
|
||||
|
@ -255,6 +255,94 @@ dictionary MozStkSetUpEventList
|
||||
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
|
||||
{
|
||||
/**
|
||||
@ -306,6 +394,22 @@ dictionary MozStkCommand
|
||||
* When typeOfCommand is
|
||||
* - STK_CMD_SET_UP_EVENT_LIST
|
||||
* 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;
|
||||
};
|
||||
|
@ -7,7 +7,7 @@
|
||||
|
||||
interface nsIDOMEventListener;
|
||||
|
||||
[scriptable, builtinclass, uuid(2eace3f9-6aa4-491b-820e-7d69ce7b3f02)]
|
||||
[scriptable, builtinclass, uuid(9d898c66-3485-4cd5-ab8d-92ef2988887b)]
|
||||
interface nsIDOMMozIccManager : nsIDOMEventTarget
|
||||
{
|
||||
/**
|
||||
@ -30,6 +30,8 @@ interface nsIDOMMozIccManager : nsIDOMEventTarget
|
||||
* @see TS 11.14, clause 13.4
|
||||
*/
|
||||
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_CALL = 0x10;
|
||||
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_DTMF = 0x14;
|
||||
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_GET_INKEY = 0x22;
|
||||
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_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
|
||||
* Command.
|
||||
@ -185,6 +217,16 @@ interface nsIDOMMozIccManager : nsIDOMEventTarget
|
||||
void sendStkMenuSelection(in unsigned short itemIdentifier,
|
||||
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
|
||||
* issued from ICC.
|
||||
|
@ -137,6 +137,17 @@ IccManager::SendStkMenuSelection(uint16_t aItemIdentifier, bool aHelpRequested)
|
||||
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
|
||||
IccManager::InternalDispatchEvent(const nsAString& aType)
|
||||
{
|
||||
|
@ -9,13 +9,14 @@ interface nsIDOMDOMRequest;
|
||||
interface nsIDOMDeviceStorageCursor;
|
||||
interface nsIDOMDeviceStorageChangeEvent;
|
||||
interface nsIDOMEventListener;
|
||||
interface nsIFile;
|
||||
|
||||
dictionary DeviceStorageEnumerationParameters
|
||||
{
|
||||
jsval since;
|
||||
};
|
||||
|
||||
[scriptable, uuid(7efbe025-3a8a-4151-9257-3e8c941dc099), builtinclass]
|
||||
[scriptable, uuid(7f69936f-2948-4733-ba41-c7e1d657a88b), builtinclass]
|
||||
interface nsIDOMDeviceStorage : nsIDOMEventTarget
|
||||
{
|
||||
[implicit_jscontext] attribute jsval onchange;
|
||||
@ -38,4 +39,6 @@ interface nsIDOMDeviceStorage : nsIDOMEventTarget
|
||||
nsIDOMDeviceStorageCursor enumerateEditable([optional] in jsval aName, /* DeviceStorageEnumerationParameters */ [optional] in jsval options);
|
||||
|
||||
nsIDOMDOMRequest stat();
|
||||
|
||||
[noscript] readonly attribute nsIFile rootDirectory;
|
||||
};
|
||||
|
@ -266,6 +266,12 @@ parent:
|
||||
*/
|
||||
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__();
|
||||
|
||||
child:
|
||||
@ -282,9 +288,9 @@ child:
|
||||
|
||||
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
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include "mozilla/dom/PContentChild.h"
|
||||
#include "mozilla/dom/PContentDialogChild.h"
|
||||
#include "mozilla/ipc/DocumentRendererChild.h"
|
||||
#include "mozilla/layers/AsyncPanZoomController.h"
|
||||
#include "mozilla/layers/CompositorChild.h"
|
||||
#include "mozilla/layers/PLayersChild.h"
|
||||
#include "mozilla/layout/RenderFrameChild.h"
|
||||
@ -29,10 +30,12 @@
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsEmbedCID.h"
|
||||
#include "nsEventListenerManager.h"
|
||||
#include "nsGenericElement.h"
|
||||
#include "nsIAppsService.h"
|
||||
#include "nsIBaseWindow.h"
|
||||
#include "nsIComponentManager.h"
|
||||
#include "nsIDOMClassInfo.h"
|
||||
#include "nsIDOMElement.h"
|
||||
#include "nsIDOMEvent.h"
|
||||
#include "nsIDOMWindow.h"
|
||||
#include "nsIDOMWindowUtils.h"
|
||||
@ -50,6 +53,8 @@
|
||||
#include "nsIServiceManager.h"
|
||||
#include "nsISupportsImpl.h"
|
||||
#include "nsIURI.h"
|
||||
#include "nsIURIFixup.h"
|
||||
#include "nsCDefaultURIFixup.h"
|
||||
#include "nsIView.h"
|
||||
#include "nsIWebBrowser.h"
|
||||
#include "nsIWebBrowserFocus.h"
|
||||
@ -85,6 +90,12 @@ using namespace mozilla::widget;
|
||||
|
||||
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
|
||||
ContentListener::HandleEvent(nsIDOMEvent* aEvent)
|
||||
{
|
||||
@ -151,28 +162,45 @@ TabChild::TabChild(uint32_t aChromeFlags, bool aIsBrowserElement,
|
||||
, mTabChildGlobal(nullptr)
|
||||
, mChromeFlags(aChromeFlags)
|
||||
, mOuterRect(0, 0, 0, 0)
|
||||
, mInnerSize(0, 0)
|
||||
, mOldViewportWidth(0.0f)
|
||||
, mLastBackgroundColor(NS_RGB(255, 255, 255))
|
||||
, mAppId(aAppId)
|
||||
, mDidFakeShow(false)
|
||||
, mIsBrowserElement(aIsBrowserElement)
|
||||
, mNotified(false)
|
||||
, mContentDocumentIsDisplayed(false)
|
||||
, mTriedBrowserInit(false)
|
||||
{
|
||||
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,
|
||||
const char *aTopic,
|
||||
const PRUnichar *aData)
|
||||
{
|
||||
if (!strcmp(aTopic, "cancel-default-pan-zoom")) {
|
||||
if (!strcmp(aTopic, CANCEL_DEFAULT_PAN_ZOOM)) {
|
||||
nsCOMPtr<nsIDocShell> docShell(do_QueryInterface(aSubject));
|
||||
nsCOMPtr<nsITabChild> tabChild(GetTabChildFrom(docShell));
|
||||
if (tabChild == this) {
|
||||
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<nsITabChild> tabChild(GetTabChildFrom(docShell));
|
||||
if (tabChild == this) {
|
||||
@ -182,11 +210,264 @@ TabChild::Observe(nsISupports *aSubject,
|
||||
&rect.x, &rect.y, &rect.width, &rect.height);
|
||||
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;
|
||||
}
|
||||
|
||||
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
|
||||
TabChild::Init()
|
||||
{
|
||||
@ -238,6 +519,12 @@ TabChild::Init()
|
||||
"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;
|
||||
}
|
||||
|
||||
@ -266,8 +553,11 @@ NS_INTERFACE_MAP_BEGIN(TabChild)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIWebBrowserChromeFocus)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIWindowProvider)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIDOMEventListener)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIWebProgressListener)
|
||||
NS_INTERFACE_MAP_ENTRY(nsITabChild)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIDialogCreator)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIObserver)
|
||||
NS_INTERFACE_MAP_ENTRY(nsSupportsWeakReference)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
@ -799,6 +1089,7 @@ TabChild::RecvUpdateDimensions(const nsRect& rect, const nsIntSize& size)
|
||||
mOuterRect.width = rect.width;
|
||||
mOuterRect.height = rect.height;
|
||||
|
||||
mInnerSize = size;
|
||||
mWidget->Resize(0, 0, size.width, size.height,
|
||||
true);
|
||||
|
||||
@ -806,6 +1097,8 @@ TabChild::RecvUpdateDimensions(const nsRect& rect, const nsIntSize& size)
|
||||
baseWin->SetPositionAndSize(0, 0, size.width, size.height,
|
||||
true);
|
||||
|
||||
HandlePossibleMetaViewportChange();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -842,33 +1135,63 @@ TabChild::RecvUpdateFrame(const FrameMetrics& aFrameMetrics)
|
||||
return true;
|
||||
}
|
||||
|
||||
// The BrowserElementScrolling helper must know about these updated metrics
|
||||
// for other functions it performs, such as double tap handling.
|
||||
nsCString data;
|
||||
data += nsPrintfCString("{ \"x\" : %d", NS_lround(aFrameMetrics.mViewportScrollOffset.x));
|
||||
data += nsPrintfCString(", \"y\" : %d", NS_lround(aFrameMetrics.mViewportScrollOffset.y));
|
||||
data += nsPrintfCString("{ \"x\" : %d", NS_lround(aFrameMetrics.mScrollOffset.x));
|
||||
data += nsPrintfCString(", \"y\" : %d", NS_lround(aFrameMetrics.mScrollOffset.y));
|
||||
// We don't treat the x and y scales any differently for this
|
||||
// semi-platform-specific code.
|
||||
data += nsPrintfCString(", \"zoom\" : %f", aFrameMetrics.mResolution.width);
|
||||
data += nsPrintfCString(", \"zoom\" : %f", aFrameMetrics.mZoom.width);
|
||||
data += nsPrintfCString(", \"displayPort\" : ");
|
||||
data += nsPrintfCString("{ \"left\" : %d", aFrameMetrics.mDisplayPort.X());
|
||||
data += nsPrintfCString(", \"top\" : %d", aFrameMetrics.mDisplayPort.Y());
|
||||
data += nsPrintfCString(", \"width\" : %d", aFrameMetrics.mDisplayPort.Width());
|
||||
data += nsPrintfCString(", \"height\" : %d", aFrameMetrics.mDisplayPort.Height());
|
||||
data += nsPrintfCString("{ \"x\" : %f", aFrameMetrics.mDisplayPort.x);
|
||||
data += nsPrintfCString(", \"y\" : %f", aFrameMetrics.mDisplayPort.y);
|
||||
data += nsPrintfCString(", \"width\" : %f", aFrameMetrics.mDisplayPort.width);
|
||||
data += nsPrintfCString(", \"height\" : %f", aFrameMetrics.mDisplayPort.height);
|
||||
data += nsPrintfCString(", \"resolution\" : %f", aFrameMetrics.mResolution.width);
|
||||
data += nsPrintfCString(" }");
|
||||
data += nsPrintfCString(", \"screenSize\" : ");
|
||||
data += nsPrintfCString("{ \"width\" : %d", aFrameMetrics.mViewport.width);
|
||||
data += nsPrintfCString(", \"height\" : %d", aFrameMetrics.mViewport.height);
|
||||
data += nsPrintfCString(", \"compositionBounds\" : ");
|
||||
data += nsPrintfCString("{ \"x\" : %d", aFrameMetrics.mCompositionBounds.x);
|
||||
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(", \"cssPageRect\" : ");
|
||||
data += nsPrintfCString("{ \"x\" : %f", aFrameMetrics.mCSSContentRect.x);
|
||||
data += nsPrintfCString(", \"y\" : %f", aFrameMetrics.mCSSContentRect.y);
|
||||
data += nsPrintfCString(", \"width\" : %f", aFrameMetrics.mCSSContentRect.width);
|
||||
data += nsPrintfCString(", \"height\" : %f", aFrameMetrics.mCSSContentRect.height);
|
||||
data += nsPrintfCString("{ \"x\" : %f", aFrameMetrics.mScrollableRect.x);
|
||||
data += nsPrintfCString(", \"y\" : %f", aFrameMetrics.mScrollableRect.y);
|
||||
data += nsPrintfCString(", \"width\" : %f", aFrameMetrics.mScrollableRect.width);
|
||||
data += nsPrintfCString(", \"height\" : %f", aFrameMetrics.mScrollableRect.height);
|
||||
data += nsPrintfCString(" }");
|
||||
data += nsPrintfCString(" }");
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@ -926,8 +1249,7 @@ TabChild::RecvMouseEvent(const nsString& aType,
|
||||
const int32_t& aModifiers,
|
||||
const bool& aIgnoreRootScrollFrame)
|
||||
{
|
||||
nsCOMPtr<nsPIDOMWindow> window = do_GetInterface(mWebNav);
|
||||
nsCOMPtr<nsIDOMWindowUtils> utils = do_GetInterface(window);
|
||||
nsCOMPtr<nsIDOMWindowUtils> utils(GetDOMWindowUtils());
|
||||
NS_ENSURE_TRUE(utils, true);
|
||||
utils->SendMouseEvent(aType, aX, aY, aButton, aClickCount, aModifiers,
|
||||
aIgnoreRootScrollFrame, 0, 0);
|
||||
@ -1028,8 +1350,7 @@ TabChild::RecvKeyEvent(const nsString& aType,
|
||||
const int32_t& aModifiers,
|
||||
const bool& aPreventDefault)
|
||||
{
|
||||
nsCOMPtr<nsPIDOMWindow> window = do_GetInterface(mWebNav);
|
||||
nsCOMPtr<nsIDOMWindowUtils> utils = do_GetInterface(window);
|
||||
nsCOMPtr<nsIDOMWindowUtils> utils(GetDOMWindowUtils());
|
||||
NS_ENSURE_TRUE(utils, true);
|
||||
bool ignored = false;
|
||||
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?
|
||||
DestroyWindow();
|
||||
|
||||
@ -1317,7 +1645,7 @@ TabChild::InitTabChildGlobal(FrameScriptLoading aScriptLoading)
|
||||
mTabChildGlobal = scope;
|
||||
|
||||
nsISupports* scopeSupports = NS_ISUPPORTS_CAST(nsIDOMEventTarget*, scope);
|
||||
|
||||
|
||||
NS_ENSURE_TRUE(InitTabChildGlobalInternal(scopeSupports), false);
|
||||
|
||||
scope->Init();
|
||||
@ -1325,6 +1653,8 @@ TabChild::InitTabChildGlobal(FrameScriptLoading aScriptLoading)
|
||||
nsCOMPtr<nsPIWindowRoot> root = do_QueryInterface(chromeHandler);
|
||||
NS_ENSURE_TRUE(root, false);
|
||||
root->SetParentTarget(scope);
|
||||
|
||||
chromeHandler->AddEventListener(NS_LITERAL_STRING("DOMMetaAdded"), this, false);
|
||||
}
|
||||
|
||||
if (aScriptLoading != DONT_LOAD_SCRIPTS && !mTriedBrowserInit) {
|
||||
@ -1389,10 +1719,13 @@ TabChild::InitRenderingState()
|
||||
|
||||
if (observerService) {
|
||||
observerService->AddObserver(this,
|
||||
"cancel-default-pan-zoom",
|
||||
CANCEL_DEFAULT_PAN_ZOOM,
|
||||
false);
|
||||
observerService->AddObserver(this,
|
||||
"browser-zoom-to-rect",
|
||||
BROWSER_ZOOM_TO_RECT,
|
||||
false);
|
||||
observerService->AddObserver(this,
|
||||
BEFORE_FIRST_PAINT,
|
||||
false);
|
||||
}
|
||||
|
||||
|
@ -36,9 +36,11 @@
|
||||
#include "nsNetUtil.h"
|
||||
#include "nsFrameMessageManager.h"
|
||||
#include "nsIScriptContext.h"
|
||||
#include "nsIWebProgressListener.h"
|
||||
#include "nsDOMEventTargetHelper.h"
|
||||
#include "nsIDialogCreator.h"
|
||||
#include "nsIDialogParamBlock.h"
|
||||
#include "nsIDOMWindowUtils.h"
|
||||
#include "nsIPresShell.h"
|
||||
#include "nsIPrincipal.h"
|
||||
#include "nsIScriptObjectPrincipal.h"
|
||||
@ -141,6 +143,8 @@ class TabChild : public PBrowserChild,
|
||||
public nsIWebBrowserChromeFocus,
|
||||
public nsIInterfaceRequestor,
|
||||
public nsIWindowProvider,
|
||||
public nsIDOMEventListener,
|
||||
public nsIWebProgressListener,
|
||||
public nsSupportsWeakReference,
|
||||
public nsIDialogCreator,
|
||||
public nsITabChild,
|
||||
@ -175,6 +179,8 @@ public:
|
||||
NS_DECL_NSIWEBBROWSERCHROMEFOCUS
|
||||
NS_DECL_NSIINTERFACEREQUESTOR
|
||||
NS_DECL_NSIWINDOWPROVIDER
|
||||
NS_DECL_NSIDOMEVENTLISTENER
|
||||
NS_DECL_NSIWEBPROGRESSLISTENER
|
||||
NS_DECL_NSIDIALOGCREATOR
|
||||
NS_DECL_NSITABCHILD
|
||||
NS_DECL_NSIOBSERVER
|
||||
@ -328,6 +334,16 @@ private:
|
||||
// Call RecvShow(nsIntSize(0, 0)) and block future calls to RecvShow().
|
||||
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
|
||||
// chrome script.
|
||||
//
|
||||
@ -347,18 +363,30 @@ private:
|
||||
bool* aWindowIsNew,
|
||||
nsIDOMWindow** aReturn);
|
||||
|
||||
nsIDOMWindowUtils* GetDOMWindowUtils()
|
||||
{
|
||||
nsCOMPtr<nsPIDOMWindow> window = do_GetInterface(mWebNav);
|
||||
nsCOMPtr<nsIDOMWindowUtils> utils = do_GetInterface(window);
|
||||
return utils;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIWebNavigation> mWebNav;
|
||||
nsCOMPtr<nsIWidget> mWidget;
|
||||
nsCOMPtr<nsIURI> mLastURI;
|
||||
FrameMetrics mLastMetrics;
|
||||
RenderFrameChild* mRemoteFrame;
|
||||
nsRefPtr<TabChildGlobal> mTabChildGlobal;
|
||||
uint32_t mChromeFlags;
|
||||
nsIntRect mOuterRect;
|
||||
nsIntSize mInnerSize;
|
||||
float mOldViewportWidth;
|
||||
nscolor mLastBackgroundColor;
|
||||
ScrollingBehavior mScrolling;
|
||||
uint32_t mAppId;
|
||||
bool mDidFakeShow;
|
||||
bool mIsBrowserElement;
|
||||
bool mNotified;
|
||||
bool mContentDocumentIsDisplayed;
|
||||
bool mTriedBrowserInit;
|
||||
|
||||
DISALLOW_EVIL_CONSTRUCTORS(TabChild);
|
||||
|
@ -83,6 +83,7 @@ TabParent::TabParent(mozIApplication* aApp, bool aIsBrowserElement)
|
||||
, mIMECompositionStart(0)
|
||||
, mIMESeqno(0)
|
||||
, mEventCaptureDepth(0)
|
||||
, mDimensions(0, 0)
|
||||
, mDPI(0)
|
||||
, mIsBrowserElement(aIsBrowserElement)
|
||||
, mShown(false)
|
||||
@ -229,6 +230,7 @@ TabParent::Show(const nsIntSize& size)
|
||||
{
|
||||
// sigh
|
||||
mShown = true;
|
||||
mDimensions = size;
|
||||
unused << SendShow(size);
|
||||
}
|
||||
|
||||
@ -239,6 +241,7 @@ TabParent::UpdateDimensions(const nsRect& rect, const nsIntSize& size)
|
||||
if (RenderFrameParent* rfp = GetRenderFrame()) {
|
||||
rfp->NotifyDimensionsChanged(size.width, size.height);
|
||||
}
|
||||
mDimensions = size;
|
||||
}
|
||||
|
||||
void
|
||||
@ -1172,6 +1175,21 @@ TabParent::RecvBrowserFrameOpenWindow(PBrowserParent* aOpener,
|
||||
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
|
||||
TabParent::RecvZoomToRect(const gfxRect& aRect)
|
||||
{
|
||||
@ -1181,6 +1199,17 @@ TabParent::RecvZoomToRect(const gfxRect& aRect)
|
||||
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
|
||||
TabParent::RecvContentReceivedTouch(const bool& aPreventDefault)
|
||||
{
|
||||
|
@ -94,6 +94,11 @@ public:
|
||||
|
||||
virtual bool RecvMoveFocus(const bool& aForward);
|
||||
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,
|
||||
const nsString& aURL,
|
||||
const nsString& aName,
|
||||
@ -131,6 +136,9 @@ public:
|
||||
virtual bool RecvGetDPI(float* aValue);
|
||||
virtual bool RecvGetWidgetNativeData(WindowsHandle* aValue);
|
||||
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 PContentDialogParent* AllocPContentDialog(const uint32_t& aType,
|
||||
const nsCString& aName,
|
||||
@ -269,6 +277,7 @@ protected:
|
||||
// The number of event series we're currently capturing.
|
||||
int32_t mEventCaptureDepth;
|
||||
|
||||
nsIntSize mDimensions;
|
||||
float mDPI;
|
||||
bool mIsBrowserElement;
|
||||
bool mShown;
|
||||
|
@ -14,7 +14,7 @@ interface nsIDOMWindow;
|
||||
* XPCOM component (in the content process) that provides the mobile
|
||||
* network information.
|
||||
*/
|
||||
[scriptable, uuid(63787ba1-5091-450b-8810-d321a8b4f77a)]
|
||||
[scriptable, uuid(bc1a82aa-2a1f-4a27-a5e7-614d06b72e0a)]
|
||||
interface nsIMobileConnectionProvider : nsISupports
|
||||
{
|
||||
readonly attribute DOMString cardState;
|
||||
@ -40,4 +40,6 @@ interface nsIMobileConnectionProvider : nsISupports
|
||||
void sendStkMenuSelection(in nsIDOMWindow window,
|
||||
in unsigned short itemIdentifier,
|
||||
in boolean helpRequested);
|
||||
void sendStkEventDownload(in nsIDOMWindow window,
|
||||
in jsval event);
|
||||
};
|
||||
|
@ -453,6 +453,15 @@ RILContentHelper.prototype = {
|
||||
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,
|
||||
_voicemailCallbacks: null,
|
||||
_enumerateTelephonyCallbacks: null,
|
||||
|
@ -73,6 +73,7 @@ const RIL_IPC_MOBILECONNECTION_MSG_NAMES = [
|
||||
"RIL:CancelUSSD",
|
||||
"RIL:SendStkResponse",
|
||||
"RIL:SendStkMenuSelection",
|
||||
"RIL:SendStkEventDownload",
|
||||
];
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "gSmsService",
|
||||
@ -384,6 +385,9 @@ RadioInterfaceLayer.prototype = {
|
||||
case "RIL:SendStkMenuSelection":
|
||||
this.sendStkMenuSelection(msg.json);
|
||||
break;
|
||||
case "RIL:SendStkEventDownload":
|
||||
this.sendStkEventDownload(msg.json);
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
@ -1530,6 +1534,11 @@ RadioInterfaceLayer.prototype = {
|
||||
this.worker.postMessage(message);
|
||||
},
|
||||
|
||||
sendStkEventDownload: function sendStkEventDownload(message) {
|
||||
message.rilMessageType = "sendStkEventDownload";
|
||||
this.worker.postMessage(message);
|
||||
},
|
||||
|
||||
get microphoneMuted() {
|
||||
return gAudioManager.microphoneMuted;
|
||||
},
|
||||
|
@ -537,11 +537,15 @@ const COMPREHENSIONTLV_TAG_ALPHA_ID = 0x05;
|
||||
const COMPREHENSIONTLV_TAG_ADDRESS = 0x06;
|
||||
const COMPREHENSIONTLV_TAG_SMS_TPDU = 0x0b;
|
||||
const COMPREHENSIONTLV_TAG_TEXT_STRING = 0x0d;
|
||||
const COMPREHENSIONTLV_TAG_TONE = 0x0e;
|
||||
const COMPREHENSIONTLV_TAG_ITEM = 0x0f;
|
||||
const COMPREHENSIONTLV_TAG_ITEM_ID = 0x10;
|
||||
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_DEFAULT_TEXT = 0x17;
|
||||
const COMPREHENSIONTLV_TAG_LOCATION_STATUS = 0x1b;
|
||||
const COMPREHENSIONTLV_TAG_EVENT_LIST = 0x19;
|
||||
const COMPREHENSIONTLV_TAG_ICON_ID = 0x1e;
|
||||
const COMPREHENSIONTLV_TAG_ICON_ID_LIST = 0x1f;
|
||||
@ -558,6 +562,8 @@ const STK_DEVICE_ID_NETWORK = 0x83;
|
||||
|
||||
// STK Proactive commands.
|
||||
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_CALL = 0x10;
|
||||
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_DTMF = 0x14;
|
||||
const STK_CMD_LAUNCH_BROWSER = 0x15;
|
||||
const STK_CMD_PLAY_TONE = 0x20;
|
||||
const STK_CMD_DISPLAY_TEXT = 0x21;
|
||||
const STK_CMD_GET_INKEY = 0x22;
|
||||
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_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.
|
||||
*
|
||||
|
@ -51,6 +51,16 @@ const PARCEL_SIZE_SIZE = UINT32_SIZE;
|
||||
|
||||
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"];
|
||||
|
||||
let RILQUIRKS_CALLSTATE_EXTRA_UINT32 = libcutils.property_get("ro.moz.ril.callstate_extra_int");
|
||||
@ -2257,10 +2267,10 @@ let RIL = {
|
||||
}
|
||||
|
||||
// 1 octets = 2 chars.
|
||||
let size = (5 + /* Size of Command Details TLV */
|
||||
4 + /* Size of Device Identifier TLV */
|
||||
3 + /* Size of Result */
|
||||
(response.itemIdentifier ? 3 : 0) +
|
||||
let size = (TLV_COMMAND_DETAILS_SIZE +
|
||||
TLV_DEVICE_ID_SIZE +
|
||||
TLV_RESULT_SIZE +
|
||||
(response.itemIdentifier ? TLV_ITEM_ID_SIZE : 0) +
|
||||
(textLen ? textLen + 3 : 0)) * 2;
|
||||
Buf.writeUint32(size);
|
||||
|
||||
@ -2365,6 +2375,29 @@ let RIL = {
|
||||
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.
|
||||
*
|
||||
@ -2372,12 +2405,25 @@ let RIL = {
|
||||
* @patam deviceId
|
||||
* @param [optioanl] itemIdentifier
|
||||
* @param [optional] helpRequested
|
||||
* @param [optional] eventList
|
||||
* @param [optional] locationStatus
|
||||
* @param [optional] locationInfo
|
||||
*/
|
||||
sendICCEnvelopeCommand: function sendICCEnvelopeCommand(options) {
|
||||
if (DEBUG) {
|
||||
debug("Stk Envelope " + JSON.stringify(options));
|
||||
}
|
||||
let token = Buf.newParcel(REQUEST_STK_SEND_ENVELOPE_COMMAND);
|
||||
let berLen = 4 + /* Size of Device Identifier TLV */
|
||||
(options.itemIdentifier ? 3 : 0) +
|
||||
(options.helpRequested ? 2 : 0);
|
||||
let berLen = TLV_DEVICE_ID_SIZE + /* Size of Device Identifier TLV */
|
||||
(options.itemIdentifier ? TLV_ITEM_ID_SIZE : 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;
|
||||
|
||||
Buf.writeUint32(size);
|
||||
@ -2409,6 +2455,28 @@ let RIL = {
|
||||
// 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.sendParcel();
|
||||
},
|
||||
@ -6006,6 +6074,15 @@ let StkCommandParamsFactory = {
|
||||
createParam: function createParam(cmdDetails, ctlvs) {
|
||||
let param;
|
||||
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:
|
||||
param = this.processSetUpEventList(cmdDetails, ctlvs);
|
||||
break;
|
||||
@ -6034,9 +6111,12 @@ let StkCommandParamsFactory = {
|
||||
case STK_CMD_SET_UP_CALL:
|
||||
param = this.processSetupCall(cmdDetails, ctlvs);
|
||||
break;
|
||||
case STK_LAUNCH_BROWSER:
|
||||
case STK_CMD_LAUNCH_BROWSER:
|
||||
param = this.processLaunchBrowser(cmdDetails, ctlvs);
|
||||
break;
|
||||
case STK_CMD_PLAY_TONE:
|
||||
param = this.processPlayTone(cmdDetails, ctlvs);
|
||||
break;
|
||||
default:
|
||||
debug("unknown proactive command");
|
||||
break;
|
||||
@ -6044,6 +6124,66 @@ let StkCommandParamsFactory = {
|
||||
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.
|
||||
*
|
||||
@ -6309,6 +6449,32 @@ let StkCommandParamsFactory = {
|
||||
browser.mode = cmdDetails.commandQualifier & 0x03;
|
||||
|
||||
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);
|
||||
case COMPREHENSIONTLV_TAG_ALPHA_ID:
|
||||
return this.retrieveAlphaId(length);
|
||||
case COMPREHENSIONTLV_TAG_DURATION:
|
||||
return this.retrieveDuration(length);
|
||||
case COMPREHENSIONTLV_TAG_ADDRESS:
|
||||
return this.retrieveAddress(length);
|
||||
case COMPREHENSIONTLV_TAG_TEXT_STRING:
|
||||
return this.retrieveTextString(length);
|
||||
case COMPREHENSIONTLV_TAG_TONE:
|
||||
return this.retrieveTone(length);
|
||||
case COMPREHENSIONTLV_TAG_ITEM:
|
||||
return this.retrieveItem(length);
|
||||
case COMPREHENSIONTLV_TAG_ITEM_ID:
|
||||
return this.retrieveItemId(length);
|
||||
case COMPREHENSIONTLV_TAG_RESPONSE_LENGTH:
|
||||
return this.retrieveResponseLength(length);
|
||||
case COMPREHENSIONTLV_TAG_FILE_LIST:
|
||||
return this.retrieveFileList(length);
|
||||
case COMPREHENSIONTLV_TAG_DEFAULT_TEXT:
|
||||
return this.retrieveDefaultText(length);
|
||||
case COMPREHENSIONTLV_TAG_EVENT_LIST:
|
||||
@ -6398,6 +6570,23 @@ let StkProactiveCmdHelper = {
|
||||
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.
|
||||
*
|
||||
@ -6450,6 +6639,21 @@ let StkProactiveCmdHelper = {
|
||||
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.
|
||||
*
|
||||
@ -6500,6 +6704,30 @@ let StkProactiveCmdHelper = {
|
||||
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.
|
||||
*
|
||||
@ -6669,7 +6897,68 @@ let ComprehensionTlvHelper = {
|
||||
index += tlv.hlen;
|
||||
}
|
||||
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 = {
|
||||
|
@ -142,3 +142,202 @@ add_test(function test_write_dialling_number() {
|
||||
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;
|
||||
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
|
||||
|
@ -30,12 +30,15 @@ public:
|
||||
// will begin at.
|
||||
|
||||
FrameMetrics()
|
||||
: mViewport(0, 0, 0, 0)
|
||||
: mCompositionBounds(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)
|
||||
, mCSSContentRect(0, 0, 0, 0)
|
||||
, mScrollableRect(0, 0, 0, 0)
|
||||
, mResolution(1, 1)
|
||||
, mDevPixelsPerCSSPixel(1)
|
||||
, mMayHaveTouchListeners(false)
|
||||
{}
|
||||
|
||||
@ -44,7 +47,7 @@ public:
|
||||
bool operator==(const FrameMetrics& aOther) const
|
||||
{
|
||||
return (mViewport.IsEqualEdges(aOther.mViewport) &&
|
||||
mViewportScrollOffset == aOther.mViewportScrollOffset &&
|
||||
mScrollOffset == aOther.mScrollOffset &&
|
||||
mDisplayPort.IsEqualEdges(aOther.mDisplayPort) &&
|
||||
mScrollId == aOther.mScrollId);
|
||||
}
|
||||
@ -68,21 +71,152 @@ public:
|
||||
return mScrollId != NULL_SCROLL_ID;
|
||||
}
|
||||
|
||||
// These are all in layer coordinate space.
|
||||
nsIntRect mViewport;
|
||||
gfxSize LayersPixelsPerCSSPixel() const
|
||||
{
|
||||
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;
|
||||
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;
|
||||
|
||||
// Consumers often want to know the origin/size before scaling to pixels
|
||||
// so we record this as well.
|
||||
gfx::Rect mCSSContentRect;
|
||||
// The scrollable bounds of a frame. This is determined by reflow.
|
||||
// For the top-level |window|,
|
||||
// { 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;
|
||||
|
||||
// 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.
|
||||
bool mMayHaveTouchListeners;
|
||||
};
|
||||
|
@ -143,6 +143,17 @@ AppendToString(nsACString& s, const nsIntRect& r,
|
||||
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&
|
||||
AppendToString(nsACString& s, const nsIntRegion& r,
|
||||
const char* pfx="", const char* sfx="")
|
||||
@ -173,7 +184,7 @@ AppendToString(nsACString& s, const FrameMetrics& m,
|
||||
{
|
||||
s += pfx;
|
||||
AppendToString(s, m.mViewport, "{ viewport=");
|
||||
AppendToString(s, m.mViewportScrollOffset, " viewportScroll=");
|
||||
AppendToString(s, m.mScrollOffset, " viewportScroll=");
|
||||
AppendToString(s, m.mDisplayPort, " displayport=");
|
||||
AppendToString(s, m.mScrollId, " scrollId=", " }");
|
||||
return s += sfx;
|
||||
|
@ -253,7 +253,7 @@ BasicTiledThebesLayer::PaintThebes(gfxContext* aContext,
|
||||
Layer* primaryScrollable = BasicManager()->GetPrimaryScrollableLayer();
|
||||
if (primaryScrollable) {
|
||||
const FrameMetrics& metrics = primaryScrollable->AsContainerLayer()->GetFrameMetrics();
|
||||
scrollOffset = metrics.mViewportScrollOffset;
|
||||
scrollOffset = metrics.mScrollOffset;
|
||||
}
|
||||
int32_t scrollDiffX = scrollOffset.x - mLastScrollOffset.x;
|
||||
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
|
||||
* 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.
|
||||
@ -79,17 +79,26 @@ static const double MIN_ZOOM = 0.125;
|
||||
*/
|
||||
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,
|
||||
GestureBehavior aGestures)
|
||||
: mGeckoContentController(aGeckoContentController),
|
||||
mTouchListenerTimeoutTask(nullptr),
|
||||
mX(this),
|
||||
mY(this),
|
||||
mAllowZoom(true),
|
||||
mMinZoom(MIN_ZOOM),
|
||||
mMaxZoom(MAX_ZOOM),
|
||||
mMonitor("AsyncPanZoomController"),
|
||||
mLastSampleTime(TimeStamp::Now()),
|
||||
mState(NOTHING),
|
||||
mDPI(72),
|
||||
mContentPainterStatus(CONTENT_IDLE),
|
||||
mWaitingForContentToPaint(false),
|
||||
mDisableNextTouchBatch(false),
|
||||
mHandlingTouchQueue(false)
|
||||
{
|
||||
@ -137,11 +146,11 @@ AsyncPanZoomController::ReceiveInputEvent(const nsInputEvent& aEvent,
|
||||
gfx::Point currentScrollOffset, lastScrollOffset;
|
||||
{
|
||||
MonitorAutoLock monitor(mMonitor);
|
||||
currentZoom = mFrameMetrics.mResolution.width;
|
||||
currentScrollOffset = gfx::Point(mFrameMetrics.mViewportScrollOffset.x,
|
||||
mFrameMetrics.mViewportScrollOffset.y);
|
||||
lastScrollOffset = gfx::Point(mLastContentPaintMetrics.mViewportScrollOffset.x,
|
||||
mLastContentPaintMetrics.mViewportScrollOffset.y);
|
||||
currentZoom = mFrameMetrics.mZoom.width;
|
||||
currentScrollOffset = gfx::Point(mFrameMetrics.mScrollOffset.x,
|
||||
mFrameMetrics.mScrollOffset.y);
|
||||
lastScrollOffset = gfx::Point(mLastContentPaintMetrics.mScrollOffset.x,
|
||||
mLastContentPaintMetrics.mScrollOffset.y);
|
||||
}
|
||||
|
||||
nsEventStatus status;
|
||||
@ -284,8 +293,13 @@ nsEventStatus AsyncPanZoomController::OnTouchStart(const MultiTouchInput& aEvent
|
||||
case ANIMATING_ZOOM:
|
||||
// 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.
|
||||
RequestContentRepaint();
|
||||
ScheduleComposite();
|
||||
{
|
||||
MonitorAutoLock monitor(mMonitor);
|
||||
// Bring the resolution back in sync with the zoom.
|
||||
SetZoomAndResolution(mFrameMetrics.mZoom.width);
|
||||
RequestContentRepaint();
|
||||
ScheduleComposite();
|
||||
}
|
||||
// Fall through.
|
||||
case FLING:
|
||||
CancelAnimation();
|
||||
@ -404,6 +418,10 @@ nsEventStatus AsyncPanZoomController::OnTouchCancel(const MultiTouchInput& aEven
|
||||
}
|
||||
|
||||
nsEventStatus AsyncPanZoomController::OnScaleBegin(const PinchGestureInput& aEvent) {
|
||||
if (!mAllowZoom) {
|
||||
return nsEventStatus_eConsumeNoDefault;
|
||||
}
|
||||
|
||||
SetState(PINCHING);
|
||||
mLastZoomFocus = aEvent.mFocusPoint;
|
||||
|
||||
@ -411,6 +429,10 @@ nsEventStatus AsyncPanZoomController::OnScaleBegin(const PinchGestureInput& aEve
|
||||
}
|
||||
|
||||
nsEventStatus AsyncPanZoomController::OnScale(const PinchGestureInput& aEvent) {
|
||||
if (mState != PINCHING) {
|
||||
return nsEventStatus_eConsumeNoDefault;
|
||||
}
|
||||
|
||||
float prevSpan = aEvent.mPreviousSpan;
|
||||
if (fabsf(prevSpan) <= EPSILON || fabsf(aEvent.mCurrentSpan) <= EPSILON) {
|
||||
// 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);
|
||||
|
||||
float scale = mFrameMetrics.mResolution.width;
|
||||
float scale = mFrameMetrics.mZoom.width;
|
||||
|
||||
nsIntPoint focusPoint = aEvent.mFocusPoint;
|
||||
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;
|
||||
|
||||
// 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
|
||||
// already there, then normalize it.
|
||||
if (scale * spanRatio > MAX_ZOOM) {
|
||||
spanRatio = scale / MAX_ZOOM;
|
||||
} else if (scale * spanRatio < MIN_ZOOM) {
|
||||
spanRatio = scale / MIN_ZOOM;
|
||||
if (scale * spanRatio > mMaxZoom) {
|
||||
spanRatio = scale / mMaxZoom;
|
||||
} else if (scale * spanRatio < mMinZoom) {
|
||||
spanRatio = scale / mMinZoom;
|
||||
}
|
||||
|
||||
if (doScale) {
|
||||
@ -529,7 +551,7 @@ nsEventStatus AsyncPanZoomController::OnSingleTapUp(const TapGestureInput& aEven
|
||||
|
||||
gfx::Point point = WidgetSpaceToCompensatedViewportSpace(
|
||||
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)));
|
||||
return nsEventStatus_eConsumeNoDefault;
|
||||
}
|
||||
@ -545,10 +567,13 @@ nsEventStatus AsyncPanZoomController::OnDoubleTap(const TapGestureInput& aEvent)
|
||||
if (mGeckoContentController) {
|
||||
MonitorAutoLock monitor(mMonitor);
|
||||
|
||||
gfx::Point point = WidgetSpaceToCompensatedViewportSpace(
|
||||
gfx::Point(aEvent.mPoint.x, aEvent.mPoint.y),
|
||||
mFrameMetrics.mResolution.width);
|
||||
mGeckoContentController->HandleDoubleTap(nsIntPoint(NS_lround(point.x), NS_lround(point.y)));
|
||||
if (mAllowZoom) {
|
||||
gfx::Point point = WidgetSpaceToCompensatedViewportSpace(
|
||||
gfx::Point(aEvent.mPoint.x, aEvent.mPoint.y),
|
||||
mFrameMetrics.mZoom.width);
|
||||
mGeckoContentController->HandleDoubleTap(nsIntPoint(NS_lround(point.x), NS_lround(point.y)));
|
||||
}
|
||||
|
||||
return nsEventStatus_eConsumeNoDefault;
|
||||
}
|
||||
return nsEventStatus_eIgnore;
|
||||
@ -568,6 +593,10 @@ const gfx::Point AsyncPanZoomController::GetVelocityVector() {
|
||||
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) {
|
||||
float dx = mX.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
|
||||
// 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 yDisplacement = mY.GetDisplacementForDuration(inverseScale, timeDelta);
|
||||
@ -642,6 +671,9 @@ bool AsyncPanZoomController::DoFling(const TimeDuration& aDelta) {
|
||||
shouldContinueFlingY = mY.FlingApplyFrictionOrCancel(aDelta);
|
||||
// If we shouldn't continue the fling, let's just stop and repaint.
|
||||
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();
|
||||
mState = NOTHING;
|
||||
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
|
||||
// larger swipe should move you a shorter distance.
|
||||
float inverseScale = 1 / mFrameMetrics.mResolution.width;
|
||||
float inverseScale = 1 / mFrameMetrics.mZoom.width;
|
||||
|
||||
ScrollBy(gfx::Point(
|
||||
mX.GetDisplacementForDuration(inverseScale, aDelta),
|
||||
@ -669,132 +701,167 @@ void AsyncPanZoomController::SetCompositorParent(CompositorParent* aCompositorPa
|
||||
}
|
||||
|
||||
void AsyncPanZoomController::ScrollBy(const gfx::Point& aOffset) {
|
||||
gfx::Point newOffset(mFrameMetrics.mViewportScrollOffset.x + aOffset.x,
|
||||
mFrameMetrics.mViewportScrollOffset.y + aOffset.y);
|
||||
gfx::Point newOffset(mFrameMetrics.mScrollOffset.x + aOffset.x,
|
||||
mFrameMetrics.mScrollOffset.y + aOffset.y);
|
||||
FrameMetrics metrics(mFrameMetrics);
|
||||
metrics.mViewportScrollOffset = newOffset;
|
||||
metrics.mScrollOffset = newOffset;
|
||||
mFrameMetrics = metrics;
|
||||
}
|
||||
|
||||
void AsyncPanZoomController::SetPageRect(const gfx::Rect& aCSSPageRect) {
|
||||
FrameMetrics metrics = mFrameMetrics;
|
||||
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.
|
||||
pageSize.ScaleRoundOut(1 / scale);
|
||||
pageSize.ScaleInverseRoundOut(scale);
|
||||
|
||||
// Round the page rect so we don't get any truncation, then get the nsIntRect
|
||||
// from this.
|
||||
metrics.mContentRect = nsIntRect(pageSize.x, pageSize.y, pageSize.width, pageSize.height);
|
||||
metrics.mCSSContentRect = aCSSPageRect;
|
||||
metrics.mScrollableRect = aCSSPageRect;
|
||||
|
||||
mFrameMetrics = metrics;
|
||||
}
|
||||
|
||||
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.
|
||||
float scaleFactor = aScale / metrics.mResolution.width,
|
||||
oldScale = metrics.mResolution.width;
|
||||
|
||||
metrics.mResolution.width = metrics.mResolution.height = aScale;
|
||||
SetZoomAndResolution(aScale);
|
||||
|
||||
// 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).
|
||||
SetPageRect(mFrameMetrics.mCSSContentRect);
|
||||
SetPageRect(mFrameMetrics.mScrollableRect);
|
||||
|
||||
gfx::Point scrollOffset = metrics.mViewportScrollOffset;
|
||||
|
||||
scrollOffset.x += float(aFocus.x) * (scaleFactor - 1.0f) / oldScale;
|
||||
scrollOffset.y += float(aFocus.y) * (scaleFactor - 1.0f) / oldScale;
|
||||
|
||||
metrics.mViewportScrollOffset = scrollOffset;
|
||||
|
||||
mFrameMetrics = metrics;
|
||||
// If the new scale is very small, we risk multiplying in huge rounding
|
||||
// errors, so don't bother adjusting the scroll offset.
|
||||
if (aScale >= 0.01f) {
|
||||
mFrameMetrics.mScrollOffset.x += float(aFocus.x) * (scaleFactor - 1.0f) / aScale;
|
||||
mFrameMetrics.mScrollOffset.y += float(aFocus.y) * (scaleFactor - 1.0f) / aScale;
|
||||
}
|
||||
}
|
||||
|
||||
bool AsyncPanZoomController::EnlargeDisplayPortAlongAxis(float aViewport,
|
||||
bool AsyncPanZoomController::EnlargeDisplayPortAlongAxis(float aSkateSizeMultiplier,
|
||||
double aEstimatedPaintDuration,
|
||||
float aCompositionBounds,
|
||||
float aVelocity,
|
||||
float aAcceleration,
|
||||
float* aDisplayPortOffset,
|
||||
float* aDisplayPortLength)
|
||||
{
|
||||
const float MIN_SKATE_SIZE_MULTIPLIER = 2.0f;
|
||||
const float MAX_SKATE_SIZE_MULTIPLIER = 4.0f;
|
||||
|
||||
if (fabsf(aVelocity) > MIN_SKATE_SPEED) {
|
||||
*aDisplayPortLength = aViewport * clamped(fabsf(aVelocity),
|
||||
MIN_SKATE_SIZE_MULTIPLIER, MAX_SKATE_SIZE_MULTIPLIER);
|
||||
*aDisplayPortOffset = aVelocity > 0 ? 0 : aViewport - *aDisplayPortLength;
|
||||
// Enlarge the area we paint.
|
||||
*aDisplayPortLength = aCompositionBounds * aSkateSizeMultiplier;
|
||||
// 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 false;
|
||||
}
|
||||
|
||||
const nsIntRect AsyncPanZoomController::CalculatePendingDisplayPort() {
|
||||
float scale = mFrameMetrics.mResolution.width;
|
||||
nsIntRect viewport = mFrameMetrics.mViewport;
|
||||
viewport.ScaleRoundIn(1 / scale);
|
||||
const gfx::Rect AsyncPanZoomController::CalculatePendingDisplayPort(
|
||||
const FrameMetrics& aFrameMetrics,
|
||||
const gfx::Point& aVelocity,
|
||||
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;
|
||||
gfx::Point velocity = GetVelocityVector();
|
||||
// The multiplier we apply to a dimension's length if it is stationary. 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_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,
|
||||
viewport.width * STATIONARY_SIZE_MULTIPLIER,
|
||||
viewport.height * STATIONARY_SIZE_MULTIPLIER);
|
||||
compositionBounds.width * X_STATIONARY_SIZE_MULTIPLIER,
|
||||
compositionBounds.height * Y_STATIONARY_SIZE_MULTIPLIER);
|
||||
|
||||
// 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
|
||||
// it's less likely to checkerboard.
|
||||
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(
|
||||
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) {
|
||||
displayPort.x = -displayPort.width / 4;
|
||||
displayPort.y = -displayPort.height / 4;
|
||||
// Position the x and y such that the screen falls in the middle of the displayport.
|
||||
displayPort.x = -(displayPort.width - compositionBounds.width) / 2;
|
||||
displayPort.y = -(displayPort.height - compositionBounds.height) / 2;
|
||||
} else if (!enlargedX) {
|
||||
displayPort.width = viewport.width;
|
||||
displayPort.width = compositionBounds.width;
|
||||
} 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;
|
||||
shiftedDisplayPort.MoveBy(scrollOffset.x, scrollOffset.y);
|
||||
displayPort = shiftedDisplayPort.Intersect(mFrameMetrics.mCSSContentRect);
|
||||
displayPort = shiftedDisplayPort.Intersect(aFrameMetrics.mScrollableRect);
|
||||
displayPort.MoveBy(-scrollOffset.x, -scrollOffset.y);
|
||||
|
||||
// Round the displayport so we don't get any truncation, then get the nsIntRect
|
||||
// from this.
|
||||
displayPort.Round();
|
||||
return nsIntRect(displayPort.x, displayPort.y, displayPort.width, displayPort.height);
|
||||
return displayPort;
|
||||
}
|
||||
|
||||
void AsyncPanZoomController::SetDPI(int aDPI) {
|
||||
@ -812,24 +879,31 @@ void AsyncPanZoomController::ScheduleComposite() {
|
||||
}
|
||||
|
||||
void AsyncPanZoomController::RequestContentRepaint() {
|
||||
mFrameMetrics.mDisplayPort = CalculatePendingDisplayPort();
|
||||
mPreviousPaintStartTime = TimeStamp::Now();
|
||||
|
||||
gfx::Point oldScrollOffset = mLastPaintRequestMetrics.mViewportScrollOffset,
|
||||
newScrollOffset = mFrameMetrics.mViewportScrollOffset;
|
||||
double estimatedPaintSum = 0.0;
|
||||
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
|
||||
// request since it's a pointless paint.
|
||||
nsRect oldDisplayPort = nsRect(
|
||||
mLastPaintRequestMetrics.mDisplayPort.x,
|
||||
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);
|
||||
gfx::Rect oldDisplayPort = mLastPaintRequestMetrics.mDisplayPort;
|
||||
gfx::Rect newDisplayPort = mFrameMetrics.mDisplayPort;
|
||||
|
||||
oldDisplayPort.MoveBy(oldScrollOffset.x, oldScrollOffset.y);
|
||||
newDisplayPort.MoveBy(newScrollOffset.x, newScrollOffset.y);
|
||||
@ -842,13 +916,27 @@ void AsyncPanZoomController::RequestContentRepaint() {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mContentPainterStatus == CONTENT_IDLE) {
|
||||
mContentPainterStatus = CONTENT_PAINTING;
|
||||
mLastPaintRequestMetrics = mFrameMetrics;
|
||||
mGeckoContentController->RequestContentRepaint(mFrameMetrics);
|
||||
} else {
|
||||
mContentPainterStatus = CONTENT_PAINTING_AND_PAINT_PENDING;
|
||||
}
|
||||
// Cache the resolution since we're temporarily changing it to accomodate
|
||||
// mixed resolution/zoom (normally we make them the same thing).
|
||||
float actualResolution = mFrameMetrics.mResolution.width;
|
||||
// Calculate the factor of acceleration based on the faster of the two axes.
|
||||
float accelerationFactor =
|
||||
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,
|
||||
@ -888,20 +976,22 @@ bool AsyncPanZoomController::SampleContentTransformForFrame(const TimeStamp& aSa
|
||||
}
|
||||
double sampledPosition = gComputedTimingFunction->GetValue(animPosition);
|
||||
|
||||
mFrameMetrics.mResolution.width = mFrameMetrics.mResolution.height =
|
||||
mEndZoomToMetrics.mResolution.width * sampledPosition +
|
||||
mStartZoomToMetrics.mResolution.width * (1 - sampledPosition);
|
||||
mFrameMetrics.mZoom.width = mFrameMetrics.mZoom.height =
|
||||
mEndZoomToMetrics.mZoom.width * sampledPosition +
|
||||
mStartZoomToMetrics.mZoom.width * (1 - sampledPosition);
|
||||
|
||||
mFrameMetrics.mViewportScrollOffset = gfx::Point(
|
||||
mEndZoomToMetrics.mViewportScrollOffset.x * sampledPosition +
|
||||
mStartZoomToMetrics.mViewportScrollOffset.x * (1 - sampledPosition),
|
||||
mEndZoomToMetrics.mViewportScrollOffset.y * sampledPosition +
|
||||
mStartZoomToMetrics.mViewportScrollOffset.y * (1 - sampledPosition)
|
||||
mFrameMetrics.mScrollOffset = gfx::Point(
|
||||
mEndZoomToMetrics.mScrollOffset.x * sampledPosition +
|
||||
mStartZoomToMetrics.mScrollOffset.x * (1 - sampledPosition),
|
||||
mEndZoomToMetrics.mScrollOffset.y * sampledPosition +
|
||||
mStartZoomToMetrics.mScrollOffset.y * (1 - sampledPosition)
|
||||
);
|
||||
|
||||
requestAnimationFrame = true;
|
||||
|
||||
if (aSampleTime - mAnimationStartTime >= ZOOM_TO_DURATION) {
|
||||
// Bring the resolution in sync with the zoom.
|
||||
SetZoomAndResolution(mFrameMetrics.mZoom.width);
|
||||
mState = NOTHING;
|
||||
RequestContentRepaint();
|
||||
}
|
||||
@ -916,14 +1006,14 @@ bool AsyncPanZoomController::SampleContentTransformForFrame(const TimeStamp& aSa
|
||||
// transformed due to touches like panning or pinching. Eventually, the root
|
||||
// layer transform will become this during runtime, but we must wait for Gecko
|
||||
// to repaint.
|
||||
localScaleX = mFrameMetrics.mResolution.width;
|
||||
localScaleY = mFrameMetrics.mResolution.height;
|
||||
localScaleX = mFrameMetrics.mZoom.width;
|
||||
localScaleY = mFrameMetrics.mZoom.height;
|
||||
|
||||
if (frame.IsScrollable()) {
|
||||
metricsScrollOffset = frame.mViewportScrollOffset;
|
||||
metricsScrollOffset = frame.GetScrollOffsetInLayerPixels();
|
||||
}
|
||||
|
||||
scrollOffset = mFrameMetrics.mViewportScrollOffset;
|
||||
scrollOffset = mFrameMetrics.mScrollOffset;
|
||||
}
|
||||
|
||||
nsIntPoint scrollCompensation(
|
||||
@ -953,13 +1043,15 @@ void AsyncPanZoomController::NotifyLayersUpdated(const FrameMetrics& aViewportFr
|
||||
|
||||
mLastContentPaintMetrics = aViewportFrame;
|
||||
|
||||
if (mContentPainterStatus != CONTENT_IDLE) {
|
||||
if (mContentPainterStatus == CONTENT_PAINTING_AND_PAINT_PENDING) {
|
||||
mContentPainterStatus = CONTENT_IDLE;
|
||||
RequestContentRepaint();
|
||||
} else {
|
||||
mContentPainterStatus = CONTENT_IDLE;
|
||||
if (mWaitingForContentToPaint) {
|
||||
// Remove the oldest sample we have if adding a new sample takes us over our
|
||||
// desired number of samples.
|
||||
if (mPreviousPaintDurations.Length() >= NUM_PAINT_DURATION_SAMPLES) {
|
||||
mPreviousPaintDurations.RemoveElementAt(0);
|
||||
}
|
||||
|
||||
mPreviousPaintDurations.AppendElement(
|
||||
TimeStamp::Now() - mPreviousPaintStartTime);
|
||||
} else {
|
||||
// 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
|
||||
@ -972,10 +1064,7 @@ void AsyncPanZoomController::NotifyLayersUpdated(const FrameMetrics& aViewportFr
|
||||
case FLING:
|
||||
case TOUCHING:
|
||||
case WAITING_LISTENERS:
|
||||
// FIXME/bug 784908: Scroll offset is stored in layer pixels in the rest
|
||||
// of the layers code, but we want it in CSS pixels.
|
||||
mFrameMetrics.mViewportScrollOffset =
|
||||
aViewportFrame.mViewportScrollOffset / aViewportFrame.mResolution.width;
|
||||
mFrameMetrics.mScrollOffset = aViewportFrame.mScrollOffset;
|
||||
break;
|
||||
// Don't clobber if we're in other states.
|
||||
default:
|
||||
@ -983,25 +1072,28 @@ void AsyncPanZoomController::NotifyLayersUpdated(const FrameMetrics& aViewportFr
|
||||
}
|
||||
}
|
||||
|
||||
mWaitingForContentToPaint = false;
|
||||
|
||||
if (aIsFirstPaint || mFrameMetrics.IsDefault()) {
|
||||
mContentPainterStatus = CONTENT_IDLE;
|
||||
mPreviousPaintDurations.Clear();
|
||||
|
||||
mX.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
|
||||
// we get a larger displayport. This is very bad because we're wasting a
|
||||
// paint and not initializating the displayport correctly.
|
||||
RequestContentRepaint();
|
||||
// The composition bounds are not stored within the layers code, so we have
|
||||
// to reset them back to what they were every time we overwrite them.
|
||||
nsIntRect compositionBounds = mFrameMetrics.mCompositionBounds;
|
||||
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;
|
||||
} else if (!mFrameMetrics.mCSSContentRect.IsEqualEdges(aViewportFrame.mCSSContentRect)) {
|
||||
mFrameMetrics.mCSSContentRect = aViewportFrame.mCSSContentRect;
|
||||
SetPageRect(mFrameMetrics.mCSSContentRect);
|
||||
} else if (!mFrameMetrics.mScrollableRect.IsEqualEdges(aViewportFrame.mScrollableRect)) {
|
||||
mFrameMetrics.mScrollableRect = aViewportFrame.mScrollableRect;
|
||||
SetPageRect(mFrameMetrics.mScrollableRect);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1010,11 +1102,27 @@ const FrameMetrics& AsyncPanZoomController::GetFrameMetrics() {
|
||||
return mFrameMetrics;
|
||||
}
|
||||
|
||||
void AsyncPanZoomController::UpdateViewportSize(int aWidth, int aHeight) {
|
||||
void AsyncPanZoomController::UpdateCompositionBounds(const nsIntRect& aCompositionBounds) {
|
||||
MonitorAutoLock mon(mMonitor);
|
||||
FrameMetrics metrics = GetFrameMetrics();
|
||||
metrics.mViewport = nsIntRect(0, 0, aWidth, aHeight);
|
||||
mFrameMetrics = metrics;
|
||||
|
||||
nsIntRect oldCompositionBounds = mFrameMetrics.mCompositionBounds;
|
||||
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() {
|
||||
@ -1032,27 +1140,29 @@ void AsyncPanZoomController::ZoomToRect(const gfxRect& aRect) {
|
||||
{
|
||||
MonitorAutoLock mon(mMonitor);
|
||||
|
||||
nsIntRect viewport = mFrameMetrics.mViewport;
|
||||
gfx::Rect cssPageRect = mFrameMetrics.mCSSContentRect;
|
||||
gfx::Point scrollOffset = mFrameMetrics.mViewportScrollOffset;
|
||||
nsIntRect compositionBounds = mFrameMetrics.mCompositionBounds;
|
||||
gfx::Rect cssPageRect = mFrameMetrics.mScrollableRect;
|
||||
gfx::Point scrollOffset = mFrameMetrics.mScrollOffset;
|
||||
|
||||
// If the rect is empty, treat it as a request to zoom out to the full page
|
||||
// size.
|
||||
if (zoomToRect.IsEmpty()) {
|
||||
nsIntRect cssViewport = viewport;
|
||||
cssViewport.ScaleRoundIn(1 / mFrameMetrics.mResolution.width);
|
||||
cssViewport.MoveBy(nsIntPoint(NS_lround(scrollOffset.x), NS_lround(scrollOffset.y)));
|
||||
// composition bounds in CSS coordinates
|
||||
nsIntRect cssCompositionBounds = compositionBounds;
|
||||
cssCompositionBounds.ScaleInverseRoundIn(mFrameMetrics.mZoom.width);
|
||||
cssCompositionBounds.MoveBy(scrollOffset.x, scrollOffset.y);
|
||||
|
||||
float y = mFrameMetrics.mViewportScrollOffset.y;
|
||||
float newHeight = cssViewport.height * cssPageRect.width / cssViewport.width;
|
||||
float dh = cssViewport.height - newHeight;
|
||||
float y = mFrameMetrics.mScrollOffset.y;
|
||||
float newHeight =
|
||||
cssCompositionBounds.height * cssPageRect.width / cssCompositionBounds.width;
|
||||
float dh = cssCompositionBounds.height - newHeight;
|
||||
|
||||
zoomToRect = gfx::Rect(0.0f,
|
||||
y + dh/2,
|
||||
cssPageRect.width,
|
||||
y + dh/2 + newHeight);
|
||||
} else {
|
||||
float targetRatio = float(viewport.width) / float(viewport.height);
|
||||
float targetRatio = float(compositionBounds.width) / float(compositionBounds.height);
|
||||
float rectRatio = zoomToRect.width / zoomToRect.height;
|
||||
|
||||
if (fabsf(targetRatio - rectRatio) < EPSILON) {
|
||||
@ -1072,25 +1182,27 @@ void AsyncPanZoomController::ZoomToRect(const gfxRect& aRect) {
|
||||
zoomToRect = zoomToRect.Intersect(cssPageRect);
|
||||
}
|
||||
|
||||
mEndZoomToMetrics.mResolution.width = mEndZoomToMetrics.mResolution.height =
|
||||
NS_MIN(viewport.width / zoomToRect.width, viewport.height / zoomToRect.height);
|
||||
mEndZoomToMetrics.mZoom.width = mEndZoomToMetrics.mZoom.height =
|
||||
NS_MIN(compositionBounds.width / zoomToRect.width, compositionBounds.height / zoomToRect.height);
|
||||
|
||||
mEndZoomToMetrics.mResolution.width = mEndZoomToMetrics.mResolution.height =
|
||||
clamped(mEndZoomToMetrics.mResolution.width, MIN_ZOOM, MAX_ZOOM);
|
||||
mEndZoomToMetrics.mZoom.width = mEndZoomToMetrics.mZoom.height =
|
||||
clamped(float(mEndZoomToMetrics.mZoom.width),
|
||||
mMinZoom,
|
||||
mMaxZoom);
|
||||
|
||||
// Recalculate the zoom to rect using the new dimensions.
|
||||
zoomToRect.width = viewport.width / mEndZoomToMetrics.mResolution.width;
|
||||
zoomToRect.height = viewport.height / mEndZoomToMetrics.mResolution.height;
|
||||
zoomToRect.width = compositionBounds.width / mEndZoomToMetrics.mZoom.width;
|
||||
zoomToRect.height = compositionBounds.height / mEndZoomToMetrics.mZoom.height;
|
||||
|
||||
// Clamp the zoom to rect to the CSS rect to make sure it fits.
|
||||
zoomToRect = zoomToRect.Intersect(cssPageRect);
|
||||
|
||||
// Do one final recalculation to get the resolution.
|
||||
mEndZoomToMetrics.mResolution.width = mEndZoomToMetrics.mResolution.height =
|
||||
NS_MAX(viewport.width / zoomToRect.width, viewport.height / zoomToRect.height);
|
||||
mEndZoomToMetrics.mZoom.width = mEndZoomToMetrics.mZoom.height =
|
||||
NS_MAX(compositionBounds.width / zoomToRect.width, compositionBounds.height / zoomToRect.height);
|
||||
|
||||
mStartZoomToMetrics = mFrameMetrics;
|
||||
mEndZoomToMetrics.mViewportScrollOffset =
|
||||
mEndZoomToMetrics.mScrollOffset =
|
||||
gfx::Point(zoomToRect.x, zoomToRect.y);
|
||||
|
||||
mAnimationStartTime = TimeStamp::Now();
|
||||
@ -1144,5 +1256,19 @@ void AsyncPanZoomController::TimeoutTouchListeners() {
|
||||
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 "InputData.h"
|
||||
#include "Axis.h"
|
||||
#include "nsContentUtils.h"
|
||||
|
||||
#include "base/message_loop.h"
|
||||
|
||||
@ -97,17 +98,13 @@ public:
|
||||
nsInputEvent* aOutEvent);
|
||||
|
||||
/**
|
||||
* Updates the viewport size, i.e. the dimensions of the frame (not
|
||||
* necessarily the screen) content will actually be rendered onto in device
|
||||
* pixels for example, a subframe will not take the entire screen, but we
|
||||
* still want to know how big it is in device pixels. Ideally we want to be
|
||||
* using CSS pixels everywhere inside here, but in this case we need to know
|
||||
* how large of a displayport to set so we use these dimensions plus some
|
||||
* extra.
|
||||
*
|
||||
* XXX: Use nsIntRect instead.
|
||||
* Updates the composition bounds, i.e. the dimensions of the final size of
|
||||
* the frame this is tied to during composition onto, in device pixels. In
|
||||
* general, this will just be:
|
||||
* { x = 0, y = 0, width = surface.width, height = surface.height }, however
|
||||
* there is no hard requirement for this.
|
||||
*/
|
||||
void UpdateViewportSize(int aWidth, int aHeight);
|
||||
void UpdateCompositionBounds(const nsIntRect& aCompositionBounds);
|
||||
|
||||
/**
|
||||
* We have found a scrollable subframe, so disable our machinery until we hit
|
||||
@ -134,6 +131,13 @@ public:
|
||||
*/
|
||||
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.
|
||||
//
|
||||
@ -193,6 +197,18 @@ public:
|
||||
*/
|
||||
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:
|
||||
/**
|
||||
* Internal handler for ReceiveInputEvent(). Does all the actual work.
|
||||
@ -319,6 +335,11 @@ protected:
|
||||
*/
|
||||
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 only the first one and assumes the rest are either missing or not
|
||||
@ -343,15 +364,6 @@ protected:
|
||||
*/
|
||||
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
|
||||
* 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
|
||||
* metrics.
|
||||
*/
|
||||
bool EnlargeDisplayPortAlongAxis(float aViewport, float aVelocity,
|
||||
float* aDisplayPortOffset, float* aDisplayPortLength);
|
||||
static bool EnlargeDisplayPortAlongAxis(float aSkateSizeMultiplier,
|
||||
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
|
||||
@ -396,6 +413,14 @@ protected:
|
||||
*/
|
||||
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:
|
||||
enum PanZoomState {
|
||||
NOTHING, /* no touch-start events received */
|
||||
@ -409,25 +434,6 @@ private:
|
||||
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
|
||||
* it. If the monitor is already held by the current thread, it is safe to
|
||||
@ -467,10 +473,19 @@ private:
|
||||
AxisX mX;
|
||||
AxisY mY;
|
||||
|
||||
// Protects |mFrameMetrics|, |mLastContentPaintMetrics| and |mState|. 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.
|
||||
// Most up-to-date constraints on zooming. These should always be reasonable
|
||||
// values; for example, allowing a min zoom of 0.0 can cause very bad things
|
||||
// to happen.
|
||||
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;
|
||||
|
||||
// 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.
|
||||
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;
|
||||
|
||||
// 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
|
||||
// this status will not be updated. It is only changed when this class
|
||||
// requests a repaint.
|
||||
ContentPainterStatus mContentPainterStatus;
|
||||
bool mWaitingForContentToPaint;
|
||||
|
||||
// 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.
|
||||
|
@ -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
|
||||
* reason.
|
||||
*/
|
||||
static const float MAX_EVENT_ACCELERATION = 0.5f;
|
||||
static const float MAX_EVENT_ACCELERATION = 999.0f;
|
||||
|
||||
/**
|
||||
* 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 velocityFactor = powf(ACCELERATION_MULTIPLIER,
|
||||
NS_MAX(0, (mAcceleration - 4) * 3));
|
||||
float displacement = mVelocity * aScale * aDelta.ToMilliseconds() * velocityFactor;
|
||||
if (fabsf(mVelocity) < VELOCITY_THRESHOLD) {
|
||||
mAcceleration = 0;
|
||||
}
|
||||
|
||||
float accelerationFactor = GetAccelerationFactor();
|
||||
float displacement = mVelocity * aScale * aDelta.ToMilliseconds() * accelerationFactor;
|
||||
// If this displacement will cause an overscroll, throttle it. Can potentially
|
||||
// bring it to 0 even if the velocity is high.
|
||||
if (DisplacementWillOverscroll(displacement) != OVERSCROLL_NONE) {
|
||||
// No need to have a velocity along this axis anymore; it won't take us
|
||||
// anywhere, so we're just spinning needlessly.
|
||||
mVelocity = 0.0f;
|
||||
mAcceleration = 0;
|
||||
displacement -= DisplacementWillOverscrollAmount(displacement);
|
||||
}
|
||||
return displacement;
|
||||
@ -140,12 +144,12 @@ bool Axis::FlingApplyFrictionOrCancel(const TimeDuration& aDelta) {
|
||||
}
|
||||
|
||||
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.
|
||||
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.
|
||||
bool plus = GetViewportEnd() > GetPageEnd();
|
||||
bool plus = GetCompositionEnd() > GetPageEnd();
|
||||
if (minus && plus) {
|
||||
return OVERSCROLL_BOTH;
|
||||
}
|
||||
@ -161,19 +165,20 @@ Axis::Overscroll Axis::GetOverscroll() {
|
||||
float Axis::GetExcess() {
|
||||
switch (GetOverscroll()) {
|
||||
case OVERSCROLL_MINUS: return GetOrigin() - GetPageStart();
|
||||
case OVERSCROLL_PLUS: return GetViewportEnd() - GetPageEnd();
|
||||
case OVERSCROLL_BOTH: return (GetViewportEnd() - GetPageEnd()) + (GetPageStart() - GetOrigin());
|
||||
case OVERSCROLL_PLUS: return GetCompositionEnd() - GetPageEnd();
|
||||
case OVERSCROLL_BOTH: return (GetCompositionEnd() - GetPageEnd()) +
|
||||
(GetPageStart() - GetOrigin());
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
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.
|
||||
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.
|
||||
bool plus = GetViewportEnd() + aDisplacement > GetPageEnd();
|
||||
bool plus = GetCompositionEnd() + aDisplacement > GetPageEnd();
|
||||
if (minus && plus) {
|
||||
return OVERSCROLL_BOTH;
|
||||
}
|
||||
@ -189,7 +194,7 @@ Axis::Overscroll Axis::DisplacementWillOverscroll(int32_t aDisplacement) {
|
||||
float Axis::DisplacementWillOverscrollAmount(int32_t aDisplacement) {
|
||||
switch (DisplacementWillOverscroll(aDisplacement)) {
|
||||
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
|
||||
// this, it must have already been zoomed out too far.
|
||||
default: return 0;
|
||||
@ -201,7 +206,7 @@ Axis::Overscroll Axis::ScaleWillOverscroll(float aScale, int32_t aFocus) {
|
||||
|
||||
bool both = ScaleWillOverscrollBothSides(aScale);
|
||||
bool minus = originAfterScale < GetPageStart() * aScale;
|
||||
bool plus = (originAfterScale + GetViewportLength()) > GetPageEnd() * aScale;
|
||||
bool plus = (originAfterScale + GetCompositionLength()) > GetPageEnd() * aScale;
|
||||
|
||||
if ((minus && plus) || both) {
|
||||
return OVERSCROLL_BOTH;
|
||||
@ -219,7 +224,8 @@ float Axis::ScaleWillOverscrollAmount(float aScale, int32_t aFocus) {
|
||||
float originAfterScale = (GetOrigin() + aFocus) * aScale - aFocus;
|
||||
switch (ScaleWillOverscroll(aScale, aFocus)) {
|
||||
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.
|
||||
default: return 0;
|
||||
}
|
||||
@ -229,8 +235,12 @@ float Axis::GetVelocity() {
|
||||
return mVelocity;
|
||||
}
|
||||
|
||||
float Axis::GetViewportEnd() {
|
||||
return GetOrigin() + GetViewportLength();
|
||||
float Axis::GetAccelerationFactor() {
|
||||
return powf(ACCELERATION_MULTIPLIER, NS_MAX(0, (mAcceleration - 4) * 3));
|
||||
}
|
||||
|
||||
float Axis::GetCompositionEnd() {
|
||||
return GetOrigin() + GetCompositionLength();
|
||||
}
|
||||
|
||||
float Axis::GetPageEnd() {
|
||||
@ -238,40 +248,44 @@ float Axis::GetPageEnd() {
|
||||
}
|
||||
|
||||
float Axis::GetOrigin() {
|
||||
gfx::Point origin = mAsyncPanZoomController->GetFrameMetrics().mViewportScrollOffset;
|
||||
gfx::Point origin = mAsyncPanZoomController->GetFrameMetrics().mScrollOffset;
|
||||
return GetPointOffset(origin);
|
||||
}
|
||||
|
||||
float Axis::GetViewportLength() {
|
||||
nsIntRect viewport = mAsyncPanZoomController->GetFrameMetrics().mViewport;
|
||||
gfx::Rect scaledViewport = gfx::Rect(viewport.x, viewport.y, viewport.width, viewport.height);
|
||||
scaledViewport.ScaleRoundIn(1 / mAsyncPanZoomController->GetFrameMetrics().mResolution.width);
|
||||
return GetRectLength(scaledViewport);
|
||||
float Axis::GetCompositionLength() {
|
||||
nsIntRect compositionBounds =
|
||||
mAsyncPanZoomController->GetFrameMetrics().mCompositionBounds;
|
||||
gfx::Rect scaledCompositionBounds =
|
||||
gfx::Rect(compositionBounds.x, compositionBounds.y,
|
||||
compositionBounds.width, compositionBounds.height);
|
||||
scaledCompositionBounds.ScaleInverseRoundIn(
|
||||
mAsyncPanZoomController->GetFrameMetrics().mZoom.width);
|
||||
return GetRectLength(scaledCompositionBounds);
|
||||
}
|
||||
|
||||
float Axis::GetPageStart() {
|
||||
gfx::Rect pageRect = mAsyncPanZoomController->GetFrameMetrics().mCSSContentRect;
|
||||
gfx::Rect pageRect = mAsyncPanZoomController->GetFrameMetrics().mScrollableRect;
|
||||
return GetRectOffset(pageRect);
|
||||
}
|
||||
|
||||
float Axis::GetPageLength() {
|
||||
gfx::Rect pageRect = mAsyncPanZoomController->GetFrameMetrics().mCSSContentRect;
|
||||
gfx::Rect pageRect = mAsyncPanZoomController->GetFrameMetrics().mScrollableRect;
|
||||
return GetRectLength(pageRect);
|
||||
}
|
||||
|
||||
bool Axis::ScaleWillOverscrollBothSides(float aScale) {
|
||||
const FrameMetrics& metrics = mAsyncPanZoomController->GetFrameMetrics();
|
||||
|
||||
gfx::Rect cssContentRect = metrics.mCSSContentRect;
|
||||
gfx::Rect cssContentRect = metrics.mScrollableRect;
|
||||
|
||||
float currentScale = metrics.mResolution.width;
|
||||
gfx::Rect viewport = gfx::Rect(metrics.mViewport.x,
|
||||
metrics.mViewport.y,
|
||||
metrics.mViewport.width,
|
||||
metrics.mViewport.height);
|
||||
viewport.ScaleRoundIn(1 / (currentScale * aScale));
|
||||
float currentScale = metrics.mZoom.width;
|
||||
nsIntRect compositionBounds = metrics.mCompositionBounds;
|
||||
gfx::Rect scaledCompositionBounds =
|
||||
gfx::Rect(compositionBounds.x, compositionBounds.y,
|
||||
compositionBounds.width, compositionBounds.height);
|
||||
scaledCompositionBounds.ScaleInverseRoundIn(currentScale * aScale);
|
||||
|
||||
return GetRectLength(cssContentRect) < GetRectLength(viewport);
|
||||
return GetRectLength(cssContentRect) < GetRectLength(scaledCompositionBounds);
|
||||
}
|
||||
|
||||
AxisX::AxisX(AsyncPanZoomController* aAsyncPanZoomController)
|
||||
|
@ -116,6 +116,12 @@ public:
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
@ -165,10 +171,10 @@ public:
|
||||
bool ScaleWillOverscrollBothSides(float aScale);
|
||||
|
||||
float GetOrigin();
|
||||
float GetViewportLength();
|
||||
float GetCompositionLength();
|
||||
float GetPageStart();
|
||||
float GetPageLength();
|
||||
float GetViewportEnd();
|
||||
float GetCompositionEnd();
|
||||
float GetPageEnd();
|
||||
|
||||
virtual float GetPointOffset(const gfx::Point& aPoint) = 0;
|
||||
|
@ -467,8 +467,8 @@ private:
|
||||
}
|
||||
const FrameMetrics& fm = c->GetFrameMetrics();
|
||||
gfx3DMatrix m(aContainer->GetTransform());
|
||||
m.Translate(gfxPoint3D(-fm.mViewportScrollOffset.x,
|
||||
-fm.mViewportScrollOffset.y, 0));
|
||||
m.Translate(gfxPoint3D(-fm.GetScrollOffsetInLayerPixels().x,
|
||||
-fm.GetScrollOffsetInLayerPixels().y, 0));
|
||||
|
||||
// The transform already takes the resolution scale into account. Since we
|
||||
// will apply the resolution scale again when computing the effective
|
||||
@ -787,30 +787,43 @@ CompositorParent::TransformShadowTree(TimeStamp aCurrentFrame)
|
||||
|
||||
float rootScaleX = rootTransform.GetXScale(),
|
||||
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) {
|
||||
mContentRect = metrics.mContentRect;
|
||||
const gfx::Point& scrollOffset = metrics.mViewportScrollOffset;
|
||||
SetFirstPaintViewport(nsIntPoint(NS_lround(scrollOffset.x),
|
||||
NS_lround(scrollOffset.y)),
|
||||
SetFirstPaintViewport(scrollOffsetDevPixels,
|
||||
1/rootScaleX,
|
||||
mContentRect,
|
||||
metrics.mCSSContentRect);
|
||||
metrics.mScrollableRect);
|
||||
mIsFirstPaint = false;
|
||||
} else if (!metrics.mContentRect.IsEqualEdges(mContentRect)) {
|
||||
mContentRect = metrics.mContentRect;
|
||||
SetPageRect(metrics.mCSSContentRect);
|
||||
SetPageRect(metrics.mScrollableRect);
|
||||
}
|
||||
|
||||
// We synchronise the viewport information with Java after sending the above
|
||||
// notifications, so that Java can take these into account in its response.
|
||||
// Calculate the absolute display port to send to Java
|
||||
nsIntRect displayPort = metrics.mDisplayPort;
|
||||
gfx::Point scrollOffset = metrics.mViewportScrollOffset;
|
||||
displayPort.x += NS_lround(scrollOffset.x);
|
||||
displayPort.y += NS_lround(scrollOffset.y);
|
||||
gfx::Rect displayPortLayersPixels(metrics.mDisplayPort);
|
||||
nsIntRect displayPortDevPixels(
|
||||
NS_lround(displayPortLayersPixels.x * devPixelRatioX),
|
||||
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);
|
||||
mLayersUpdated = false;
|
||||
|
||||
@ -825,8 +838,7 @@ CompositorParent::TransformShadowTree(TimeStamp aCurrentFrame)
|
||||
|
||||
nsIntPoint metricsScrollOffset(0, 0);
|
||||
if (metrics.IsScrollable()) {
|
||||
metricsScrollOffset =
|
||||
nsIntPoint(NS_lround(scrollOffset.x), NS_lround(scrollOffset.y));
|
||||
metricsScrollOffset = scrollOffsetDevPixels;
|
||||
}
|
||||
|
||||
nsIntPoint scrollCompensation(
|
||||
|
@ -37,7 +37,9 @@ ReusableTileStoreOGL::InvalidateTiles(TiledThebesLayerOGL* aLayer,
|
||||
// This will be incorrect when the transform involves rotation, but
|
||||
// it'd be quite hard to retain invalid tiles correctly in this
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
@ -217,10 +219,14 @@ ReusableTileStoreOGL::DrawTiles(TiledThebesLayerOGL* aLayer,
|
||||
scrollableLayer = parent;
|
||||
if (!parentMetrics.mDisplayPort.IsEmpty() && scrollableLayer) {
|
||||
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 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() -
|
||||
nsIntPoint(NS_lround(scrollOffset.x), NS_lround(scrollOffset.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
|
||||
fCache32[kCache32ClampLower] = SkPackARGB32(fCacheAlpha,
|
||||
SkColorGetR(fOrigColors[0]),
|
||||
SkColorGetG(fOrigColors[0]),
|
||||
SkColorGetB(fOrigColors[0]));
|
||||
fCache32[kCache32ClampLower] = SkPremultiplyARGBInline(SkMulDiv255Round(SkColorGetA(fOrigColors[0]),
|
||||
fCacheAlpha),
|
||||
SkColorGetR(fOrigColors[0]),
|
||||
SkColorGetG(fOrigColors[0]),
|
||||
SkColorGetB(fOrigColors[0]));
|
||||
|
||||
fCache32[kCache32ClampUpper] = SkPackARGB32(fCacheAlpha,
|
||||
SkColorGetR(fOrigColors[fColorCount - 1]),
|
||||
SkColorGetG(fOrigColors[fColorCount - 1]),
|
||||
SkColorGetB(fOrigColors[fColorCount - 1]));
|
||||
fCache32[kCache32ClampUpper] = SkPremultiplyARGBInline(SkMulDiv255Round(SkColorGetA(fOrigColors[fColorCount - 1]),
|
||||
fCacheAlpha),
|
||||
SkColorGetR(fOrigColors[fColorCount - 1]),
|
||||
SkColorGetG(fOrigColors[fColorCount - 1]),
|
||||
SkColorGetB(fOrigColors[fColorCount - 1]));
|
||||
|
||||
return fCache32;
|
||||
}
|
||||
|
@ -960,25 +960,31 @@ struct ParamTraits<mozilla::layers::FrameMetrics>
|
||||
|
||||
static void Write(Message* aMsg, const paramType& aParam)
|
||||
{
|
||||
WriteParam(aMsg, aParam.mCSSContentRect);
|
||||
WriteParam(aMsg, aParam.mScrollableRect);
|
||||
WriteParam(aMsg, aParam.mViewport);
|
||||
WriteParam(aMsg, aParam.mContentRect);
|
||||
WriteParam(aMsg, aParam.mViewportScrollOffset);
|
||||
WriteParam(aMsg, aParam.mScrollOffset);
|
||||
WriteParam(aMsg, aParam.mDisplayPort);
|
||||
WriteParam(aMsg, aParam.mCompositionBounds);
|
||||
WriteParam(aMsg, aParam.mScrollId);
|
||||
WriteParam(aMsg, aParam.mResolution);
|
||||
WriteParam(aMsg, aParam.mZoom);
|
||||
WriteParam(aMsg, aParam.mDevPixelsPerCSSPixel);
|
||||
WriteParam(aMsg, aParam.mMayHaveTouchListeners);
|
||||
}
|
||||
|
||||
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->mContentRect) &&
|
||||
ReadParam(aMsg, aIter, &aResult->mViewportScrollOffset) &&
|
||||
ReadParam(aMsg, aIter, &aResult->mScrollOffset) &&
|
||||
ReadParam(aMsg, aIter, &aResult->mDisplayPort) &&
|
||||
ReadParam(aMsg, aIter, &aResult->mCompositionBounds) &&
|
||||
ReadParam(aMsg, aIter, &aResult->mScrollId) &&
|
||||
ReadParam(aMsg, aIter, &aResult->mResolution) &&
|
||||
ReadParam(aMsg, aIter, &aResult->mZoom) &&
|
||||
ReadParam(aMsg, aIter, &aResult->mDevPixelsPerCSSPixel) &&
|
||||
ReadParam(aMsg, aIter, &aResult->mMayHaveTouchListeners));
|
||||
}
|
||||
};
|
||||
|
@ -5914,24 +5914,7 @@ IonBuilder::jsop_getprop(HandlePropertyName name)
|
||||
return makeCallBarrier(getter, 0, false, types, barrier);
|
||||
}
|
||||
|
||||
// If the input is guaranteed to be an object, then we want
|
||||
// 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) {
|
||||
if (unary.ival == MIRType_Object) {
|
||||
MIRType rvalType = MIRType_Value;
|
||||
if (!barrier && !IsNullOrUndefined(unary.rval))
|
||||
rvalType = unary.rval;
|
||||
|
@ -373,16 +373,6 @@ TypeInferenceOracle::elementReadGeneric(JSScript *script, jsbytecode *pc, bool *
|
||||
|
||||
*cacheable = (obj == MIRType_Object &&
|
||||
(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)
|
||||
*monitorResult = (id == MIRType_String || script->analysis()->getCode(pc).getStringElement);
|
||||
else
|
||||
|
@ -111,11 +111,10 @@ class Bytecode
|
||||
* Dynamically observed state about the execution of this opcode. These are
|
||||
* hints about the script for use during compilation.
|
||||
*/
|
||||
bool arrayWriteHole: 1; /* SETELEM which has written to an array hole. */
|
||||
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 notIdempotent: 1; /* Don't use an idempotent cache for this property read. */
|
||||
bool arrayWriteHole: 1; /* SETELEM which has written to an array hole. */
|
||||
bool getStringElement:1; /* GETELEM which has accessed string properties. */
|
||||
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. */
|
||||
|
||||
/* Stack depth before this opcode. */
|
||||
uint32_t stackDepth;
|
||||
|
@ -571,19 +571,6 @@ class StackTypeSet : public TypeSet
|
||||
/* Whether this value may be an object. */
|
||||
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. */
|
||||
bool hasObjectFlags(JSContext *cx, TypeObjectFlags flags);
|
||||
|
||||
|
@ -686,19 +686,6 @@ GetObjectElementOperation(JSContext *cx, JSOp op, HandleObject obj, const Value
|
||||
}
|
||||
#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;
|
||||
if (IsDefinitelyIndex(rref, &index)) {
|
||||
do {
|
||||
@ -716,8 +703,16 @@ GetObjectElementOperation(JSContext *cx, JSOp op, HandleObject obj, const Value
|
||||
return false;
|
||||
} while(0);
|
||||
} else {
|
||||
if (updateAnalysis)
|
||||
script->analysis()->getCode(pc).getStringElement = true;
|
||||
if (!cx->fp()->beginsIonActivation()) {
|
||||
// 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;
|
||||
res.set(rref);
|
||||
|
@ -21,7 +21,8 @@ dictionaries = [
|
||||
[ 'CameraRegion', 'nsIDOMCameraManager.idl' ],
|
||||
[ 'CameraPosition', 'nsIDOMCameraManager.idl' ],
|
||||
[ 'CameraSelector', 'nsIDOMCameraManager.idl' ],
|
||||
[ 'CameraPictureOptions', 'nsIDOMCameraManager.idl' ]
|
||||
[ 'CameraPictureOptions', 'nsIDOMCameraManager.idl' ],
|
||||
[ 'CameraRecordingOptions', 'nsIDOMCameraManager.idl' ]
|
||||
]
|
||||
|
||||
# include file names
|
||||
|
@ -575,6 +575,7 @@ static void RecordFrameMetrics(nsIFrame* aForFrame,
|
||||
bool aMayHaveTouchListeners) {
|
||||
nsPresContext* presContext = aForFrame->PresContext();
|
||||
int32_t auPerDevPixel = presContext->AppUnitsPerDevPixel();
|
||||
float auPerCSSPixel = nsPresContext::AppUnitsPerCSSPixel();
|
||||
|
||||
nsIntRect visible = aVisibleRect.ScaleToNearestPixels(
|
||||
aContainerParameters.mXScale, aContainerParameters.mYScale, auPerDevPixel);
|
||||
@ -582,12 +583,18 @@ static void RecordFrameMetrics(nsIFrame* aForFrame,
|
||||
|
||||
FrameMetrics metrics;
|
||||
|
||||
metrics.mViewport = aViewport.ScaleToNearestPixels(
|
||||
aContainerParameters.mXScale, aContainerParameters.mYScale, auPerDevPixel);
|
||||
metrics.mViewport = mozilla::gfx::Rect(
|
||||
NSAppUnitsToDoublePixels(aViewport.x, auPerDevPixel),
|
||||
NSAppUnitsToDoublePixels(aViewport.y, auPerDevPixel),
|
||||
NSAppUnitsToDoublePixels(aViewport.width, auPerDevPixel),
|
||||
NSAppUnitsToDoublePixels(aViewport.height, auPerDevPixel));
|
||||
|
||||
if (aDisplayPort) {
|
||||
metrics.mDisplayPort = aDisplayPort->ScaleToNearestPixels(
|
||||
aContainerParameters.mXScale, aContainerParameters.mYScale, auPerDevPixel);
|
||||
metrics.mDisplayPort = mozilla::gfx::Rect(
|
||||
NSAppUnitsToDoublePixels(aDisplayPort->x, auPerDevPixel),
|
||||
NSAppUnitsToDoublePixels(aDisplayPort->y, auPerDevPixel),
|
||||
NSAppUnitsToDoublePixels(aDisplayPort->width, auPerDevPixel),
|
||||
NSAppUnitsToDoublePixels(aDisplayPort->height, auPerDevPixel));
|
||||
}
|
||||
|
||||
nsIScrollableFrame* scrollableFrame = nullptr;
|
||||
@ -598,7 +605,7 @@ static void RecordFrameMetrics(nsIFrame* aForFrame,
|
||||
nsRect contentBounds = scrollableFrame->GetScrollRange();
|
||||
contentBounds.width += scrollableFrame->GetScrollPortRect().width;
|
||||
contentBounds.height += scrollableFrame->GetScrollPortRect().height;
|
||||
metrics.mCSSContentRect =
|
||||
metrics.mScrollableRect =
|
||||
mozilla::gfx::Rect(nsPresContext::AppUnitsToFloatCSSPixels(contentBounds.x),
|
||||
nsPresContext::AppUnitsToFloatCSSPixels(contentBounds.y),
|
||||
nsPresContext::AppUnitsToFloatCSSPixels(contentBounds.width),
|
||||
@ -606,13 +613,13 @@ static void RecordFrameMetrics(nsIFrame* aForFrame,
|
||||
metrics.mContentRect = contentBounds.ScaleToNearestPixels(
|
||||
aContainerParameters.mXScale, aContainerParameters.mYScale, auPerDevPixel);
|
||||
nsPoint scrollPosition = scrollableFrame->GetScrollPosition();
|
||||
metrics.mViewportScrollOffset = mozilla::gfx::Point(
|
||||
NSAppUnitsToDoublePixels(scrollPosition.x, auPerDevPixel) * aContainerParameters.mXScale,
|
||||
NSAppUnitsToDoublePixels(scrollPosition.y, auPerDevPixel) * aContainerParameters.mYScale);
|
||||
metrics.mScrollOffset = mozilla::gfx::Point(
|
||||
NSAppUnitsToDoublePixels(scrollPosition.x, auPerCSSPixel),
|
||||
NSAppUnitsToDoublePixels(scrollPosition.y, auPerCSSPixel));
|
||||
}
|
||||
else {
|
||||
nsRect contentBounds = aForFrame->GetRect();
|
||||
metrics.mCSSContentRect =
|
||||
metrics.mScrollableRect =
|
||||
mozilla::gfx::Rect(nsPresContext::AppUnitsToFloatCSSPixels(contentBounds.x),
|
||||
nsPresContext::AppUnitsToFloatCSSPixels(contentBounds.y),
|
||||
nsPresContext::AppUnitsToFloatCSSPixels(contentBounds.width),
|
||||
@ -626,6 +633,8 @@ static void RecordFrameMetrics(nsIFrame* aForFrame,
|
||||
nsIPresShell* presShell = presContext->GetPresShell();
|
||||
metrics.mResolution = gfxSize(presShell->GetXResolution(), presShell->GetYResolution());
|
||||
|
||||
metrics.mDevPixelsPerCSSPixel = auPerCSSPixel / auPerDevPixel;
|
||||
|
||||
metrics.mMayHaveTouchListeners = aMayHaveTouchListeners;
|
||||
|
||||
aRoot->SetFrameMetrics(metrics);
|
||||
@ -1070,8 +1079,10 @@ void nsDisplayList::PaintForFrame(nsDisplayListBuilder* aBuilder,
|
||||
}
|
||||
}
|
||||
|
||||
nsRect viewport(aBuilder->ToReferenceFrame(aForFrame), aForFrame->GetSize());
|
||||
|
||||
RecordFrameMetrics(aForFrame, rootScrollFrame,
|
||||
root, mVisibleRect, mVisibleRect,
|
||||
root, mVisibleRect, viewport,
|
||||
(usingDisplayport ? &displayport : nullptr), id,
|
||||
containerParameters, mayHaveTouchListeners);
|
||||
if (usingDisplayport &&
|
||||
|
@ -158,7 +158,7 @@ ComputeShadowTreeTransform(nsIFrame* aContainerFrame,
|
||||
nsIntPoint scrollOffset =
|
||||
aConfig.mScrollOffset.ToNearestPixels(auPerDevPixel);
|
||||
// metricsScrollOffset is in layer coordinates.
|
||||
gfx::Point metricsScrollOffset = aMetrics->mViewportScrollOffset;
|
||||
gfx::Point metricsScrollOffset = aMetrics->GetScrollOffsetInLayerPixels();
|
||||
nsIntPoint roundedMetricsScrollOffset =
|
||||
nsIntPoint(NS_lround(metricsScrollOffset.x), NS_lround(metricsScrollOffset.y));
|
||||
|
||||
@ -217,7 +217,9 @@ BuildListForLayer(Layer* aLayer,
|
||||
nsRect bounds;
|
||||
{
|
||||
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);
|
||||
|
||||
}
|
||||
@ -362,6 +364,7 @@ BuildViewMap(ViewMap& oldContentViews, ViewMap& newContentViews,
|
||||
if (metrics.IsScrollable()) {
|
||||
nscoord auPerDevPixel = aFrameLoader->GetPrimaryFrameOfOwningContent()
|
||||
->PresContext()->AppUnitsPerDevPixel();
|
||||
nscoord auPerCSSPixel = auPerDevPixel * metrics.mDevPixelsPerCSSPixel;
|
||||
nsContentView* view = FindViewForId(oldContentViews, scrollId);
|
||||
if (view) {
|
||||
// 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.
|
||||
ViewConfig config;
|
||||
config.mScrollOffset = nsPoint(
|
||||
NSIntPixelsToAppUnits(metrics.mViewportScrollOffset.x, auPerDevPixel) * aXScale,
|
||||
NSIntPixelsToAppUnits(metrics.mViewportScrollOffset.y, auPerDevPixel) * aYScale);
|
||||
NSIntPixelsToAppUnits(metrics.mScrollOffset.x, auPerCSSPixel) * aXScale,
|
||||
NSIntPixelsToAppUnits(metrics.mScrollOffset.y, auPerCSSPixel) * aYScale);
|
||||
view = new nsContentView(aFrameLoader, scrollId, config);
|
||||
view->mParentScaleX = aAccConfigXScale;
|
||||
view->mParentScaleY = aAccConfigYScale;
|
||||
@ -728,7 +731,8 @@ void
|
||||
RenderFrameParent::NotifyDimensionsChanged(int width, int height)
|
||||
{
|
||||
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 mozilla
|
||||
|
||||
|
@ -101,6 +101,8 @@ public:
|
||||
|
||||
void ContentReceivedTouch(bool aPreventDefault);
|
||||
|
||||
void UpdateZoomConstraints(bool aAllowZoom, float aMinZoom, float aMaxZoom);
|
||||
|
||||
protected:
|
||||
void ActorDestroy(ActorDestroyReason why) MOZ_OVERRIDE;
|
||||
|
||||
|
@ -156,6 +156,7 @@ abstract public class GeckoApp
|
||||
public static int mOrientation;
|
||||
private boolean mIsRestoringActivity;
|
||||
private String mCurrentResponse = "";
|
||||
public static boolean sIsUsingCustomProfile = false;
|
||||
|
||||
private PromptService mPromptService;
|
||||
private Favicons mFavicons;
|
||||
@ -1554,6 +1555,7 @@ abstract public class GeckoApp
|
||||
if (profileName == null)
|
||||
profileName = "default";
|
||||
}
|
||||
GeckoApp.sIsUsingCustomProfile = true;
|
||||
}
|
||||
if (profileName != null || profilePath != null) {
|
||||
mProfile = GeckoProfile.get(this, profileName, profilePath);
|
||||
@ -2252,7 +2254,8 @@ abstract public class GeckoApp
|
||||
ProfileMigrator profileMigrator = new ProfileMigrator(app);
|
||||
|
||||
// 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
|
||||
// a while.
|
||||
final SetupScreen setupScreen = new SetupScreen(app);
|
||||
@ -2296,7 +2299,7 @@ abstract public class GeckoApp
|
||||
|
||||
private void checkMigrateSync() {
|
||||
final File profileDir = getProfile().getDir();
|
||||
if (profileDir != null) {
|
||||
if (!GeckoApp.sIsUsingCustomProfile && profileDir != null) {
|
||||
final GeckoApp app = GeckoApp.mAppContext;
|
||||
ProfileMigrator profileMigrator = new ProfileMigrator(app);
|
||||
if (!profileMigrator.hasSyncMigrated()) {
|
||||
|
@ -148,7 +148,8 @@ public final class GeckoProfile {
|
||||
try {
|
||||
// Check for old profiles that may need migration.
|
||||
ProfileMigrator profileMigrator = new ProfileMigrator(mContext);
|
||||
if (!profileMigrator.isProfileMoved()) {
|
||||
if (!GeckoApp.sIsUsingCustomProfile &&
|
||||
!profileMigrator.isProfileMoved()) {
|
||||
Log.i(LOGTAG, "New installation or update, checking for old profiles.");
|
||||
profileMigrator.launchMoveProfile();
|
||||
}
|
||||
|
@ -687,6 +687,15 @@ nsDNSService::Resolve(const nsACString &hostname,
|
||||
uint32_t flags,
|
||||
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
|
||||
// simultaneous shutdown!!
|
||||
nsRefPtr<nsHostResolver> res;
|
||||
|
@ -59,9 +59,8 @@ interface nsIDNSService : nsISupports
|
||||
in nsresult aReason);
|
||||
|
||||
/**
|
||||
* called to synchronously resolve a hostname. warning this method may
|
||||
* block the calling thread for a long period of time. it is extremely
|
||||
* unwise to call this function on the UI thread of an application.
|
||||
* Called to synchronously resolve a hostname. This method will fail
|
||||
* if called from the main thread.
|
||||
*
|
||||
* @param aHostName
|
||||
* the hostname or IP-address-literal to resolve.
|
||||
|
@ -118,6 +118,10 @@ ifeq (gonk,$(MOZ_WIDGET_TOOLKIT))
|
||||
STATIC_LIBS += moznetd_s
|
||||
endif
|
||||
|
||||
ifdef MOZ_B2G_CAMERA #{
|
||||
OS_LIBS += -lstagefright -lstagefright_omx
|
||||
endif #}
|
||||
|
||||
ifdef MOZ_IPDL_TESTS
|
||||
STATIC_LIBS += ipdlunittest_s
|
||||
endif
|
||||
|
Loading…
Reference in New Issue
Block a user