mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-01-31 19:10:36 +00:00
Merge mozilla-central into birch
This commit is contained in:
commit
4e4e1bcb9b
@ -198,6 +198,9 @@ build_all_dep: alldep
|
||||
build_all_depend: alldep
|
||||
clobber clobber_all: clean
|
||||
|
||||
# helper target for mobile
|
||||
build_and_deploy: build package install
|
||||
|
||||
# Do everything from scratch
|
||||
everything: clean build
|
||||
|
||||
|
@ -44,9 +44,15 @@ namespace dom {
|
||||
|
||||
enum StructuredCloneTags {
|
||||
SCTAG_BASE = JS_SCTAG_USER_MIN,
|
||||
|
||||
// These tags are used only for main thread structured clone.
|
||||
SCTAG_DOM_BLOB,
|
||||
SCTAG_DOM_FILE,
|
||||
SCTAG_DOM_FILELIST,
|
||||
|
||||
// These tags are used for both main thread and workers.
|
||||
SCTAG_DOM_IMAGEDATA,
|
||||
|
||||
SCTAG_DOM_MAX
|
||||
};
|
||||
|
||||
|
@ -86,6 +86,8 @@
|
||||
#include "WrapperFactory.h"
|
||||
#include "nsGlobalWindow.h"
|
||||
#include "nsScriptNameSpaceManager.h"
|
||||
#include "StructuredCloneTags.h"
|
||||
#include "mozilla/dom/ImageData.h"
|
||||
|
||||
#include "nsJSPrincipals.h"
|
||||
|
||||
@ -113,6 +115,7 @@
|
||||
#include "sampler.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::dom;
|
||||
|
||||
const size_t gStackSize = 8192;
|
||||
|
||||
@ -3610,7 +3613,36 @@ NS_DOMReadStructuredClone(JSContext* cx,
|
||||
uint32_t data,
|
||||
void* closure)
|
||||
{
|
||||
// We don't currently support any extensions to structured cloning.
|
||||
if (tag == SCTAG_DOM_IMAGEDATA) {
|
||||
// Read the information out of the stream.
|
||||
uint32_t width, height;
|
||||
JS::Value dataArray;
|
||||
if (!JS_ReadUint32Pair(reader, &width, &height) ||
|
||||
!JS_ReadTypedArray(reader, &dataArray)) {
|
||||
return nsnull;
|
||||
}
|
||||
MOZ_ASSERT(dataArray.isObject());
|
||||
|
||||
// Construct the ImageData.
|
||||
nsCOMPtr<nsIDOMImageData> imageData = new ImageData(width, height,
|
||||
dataArray.toObject());
|
||||
// Wrap it in a jsval.
|
||||
JSObject* global = JS_GetGlobalForScopeChain(cx);
|
||||
if (!global) {
|
||||
return nsnull;
|
||||
}
|
||||
nsCOMPtr<nsIXPConnectJSObjectHolder> wrapper;
|
||||
JS::Value val;
|
||||
nsresult rv =
|
||||
nsContentUtils::WrapNative(cx, global, imageData, &val,
|
||||
getter_AddRefs(wrapper));
|
||||
if (NS_FAILED(rv)) {
|
||||
return nsnull;
|
||||
}
|
||||
return val.toObjectOrNull();
|
||||
}
|
||||
|
||||
// Don't know what this is. Bail.
|
||||
nsDOMClassInfo::ThrowJSException(cx, NS_ERROR_DOM_DATA_CLONE_ERR);
|
||||
return nsnull;
|
||||
}
|
||||
@ -3621,7 +3653,30 @@ NS_DOMWriteStructuredClone(JSContext* cx,
|
||||
JSObject* obj,
|
||||
void *closure)
|
||||
{
|
||||
// We don't currently support any extensions to structured cloning.
|
||||
nsCOMPtr<nsIXPConnectWrappedNative> wrappedNative;
|
||||
nsContentUtils::XPConnect()->
|
||||
GetWrappedNativeOfJSObject(cx, obj, getter_AddRefs(wrappedNative));
|
||||
nsISupports *native = wrappedNative ? wrappedNative->Native() : nsnull;
|
||||
|
||||
nsCOMPtr<nsIDOMImageData> imageData = do_QueryInterface(native);
|
||||
if (imageData) {
|
||||
// Prepare the ImageData internals.
|
||||
PRUint32 width, height;
|
||||
JS::Value dataArray;
|
||||
if (NS_FAILED(imageData->GetWidth(&width)) ||
|
||||
NS_FAILED(imageData->GetHeight(&height)) ||
|
||||
NS_FAILED(imageData->GetData(cx, &dataArray)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Write the internals to the stream.
|
||||
return JS_WriteUint32Pair(writer, SCTAG_DOM_IMAGEDATA, 0) &&
|
||||
JS_WriteUint32Pair(writer, width, height) &&
|
||||
JS_WriteTypedArray(writer, dataArray);
|
||||
}
|
||||
|
||||
// Don't know what this is. Bail.
|
||||
nsDOMClassInfo::ThrowJSException(cx, NS_ERROR_DOM_DATA_CLONE_ERR);
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
@ -157,6 +157,9 @@ _TEST_FILES = \
|
||||
test_bug735237.html \
|
||||
test_bug739038.html \
|
||||
test_bug740811.html \
|
||||
test_bug743615.html \
|
||||
utils_bug743615.js \
|
||||
worker_bug743615.js \
|
||||
$(NULL)
|
||||
|
||||
libs:: $(_TEST_FILES)
|
||||
|
84
dom/tests/mochitest/bugs/test_bug743615.html
Normal file
84
dom/tests/mochitest/bugs/test_bug743615.html
Normal file
@ -0,0 +1,84 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=743615
|
||||
-->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for Bug 743615</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="application/javascript" src="utils_bug743615.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=743615">Mozilla Bug 743615</a>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
<canvas id="c" width="200" height="200"><canvas>
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
|
||||
/** Test for structured cloning ImageData. **/
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
window.addEventListener('message', windowMessage);
|
||||
startTest();
|
||||
|
||||
function startTest() {
|
||||
// Make an ImageData.
|
||||
var ctx = document.getElementById('c').getContext('2d');
|
||||
ctx.fillStyle = 'rgb(';
|
||||
ctx.fillRect(30, 30, 50, 50);
|
||||
|
||||
// Make a blank ImageData.
|
||||
var imageData = ctx.createImageData(200, 200);
|
||||
is(imageData.data.length, imageData.width * imageData.height * 4,
|
||||
'right size for data');
|
||||
|
||||
// Write some things into it.
|
||||
var pattern = makePattern(imageData.data.length, 42, 7);
|
||||
setPattern(imageData, pattern);
|
||||
ok(checkPattern(imageData, pattern), 'Can read it back before sending');
|
||||
|
||||
// PostMessage it to ourselves.
|
||||
window.postMessage({ imageData: imageData,
|
||||
pattern: pattern,
|
||||
dataRef: imageData.data }, '*');
|
||||
}
|
||||
|
||||
function windowMessage(evt) {
|
||||
// Check the pattern we received.
|
||||
var imageData = evt.data.imageData;
|
||||
var pattern = evt.data.pattern;
|
||||
ok(checkPattern(imageData, pattern),
|
||||
'postMessage from self worked correctly');
|
||||
|
||||
// We're not spec compliant on this yet.
|
||||
todo_is(imageData.data, evt.data.dataRef,
|
||||
'Should have backrefs for imagedata buffer');
|
||||
|
||||
// Make a new pattern, and send it to a worker.
|
||||
pattern = makePattern(imageData.data.length, 4, 3);
|
||||
setPattern(imageData, pattern);
|
||||
var worker = new Worker('worker_bug743615.js');
|
||||
worker.onmessage = workerMessage;
|
||||
worker.postMessage( {imageData: imageData, pattern: pattern });
|
||||
}
|
||||
|
||||
function workerMessage(evt) {
|
||||
// Relay the results of the worker-side tests.
|
||||
is(evt.data.statusMessage, 'PASS', evt.data.statusMessage);
|
||||
|
||||
// Test what the worker sent us.
|
||||
ok(checkPattern(evt.data.imageData, evt.data.pattern),
|
||||
'postMessage from worker worked correctly');
|
||||
|
||||
// All done.
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
25
dom/tests/mochitest/bugs/utils_bug743615.js
Normal file
25
dom/tests/mochitest/bugs/utils_bug743615.js
Normal file
@ -0,0 +1,25 @@
|
||||
function makePattern(len, start, inc) {
|
||||
var pattern = [];
|
||||
while(len) {
|
||||
pattern.push(start);
|
||||
start = (start + inc) % 256;
|
||||
--len;
|
||||
}
|
||||
return pattern;
|
||||
}
|
||||
|
||||
function setPattern(imageData, pattern) {
|
||||
if (pattern.length != imageData.data.length)
|
||||
throw Error('Invalid pattern');
|
||||
for (var i = 0; i < pattern.length; ++i)
|
||||
imageData.data[i] = pattern[i];
|
||||
}
|
||||
|
||||
function checkPattern(imageData, pattern) {
|
||||
if (pattern.length != imageData.data.length)
|
||||
throw Error('Invalid pattern');
|
||||
for (var i = 0; i < pattern.length; ++i)
|
||||
if (imageData.data[i] != pattern[i])
|
||||
return false;
|
||||
return true;
|
||||
}
|
38
dom/tests/mochitest/bugs/worker_bug743615.js
Normal file
38
dom/tests/mochitest/bugs/worker_bug743615.js
Normal file
@ -0,0 +1,38 @@
|
||||
importScripts('utils_bug743615.js');
|
||||
|
||||
self.onmessage = function onMessage(evt) {
|
||||
// Check the pattern that was sent.
|
||||
var imageData = evt.data.imageData;
|
||||
var pattern = evt.data.pattern;
|
||||
var statusMessage = checkPattern(imageData, pattern)
|
||||
? 'PASS' : 'Got corrupt typed array in worker';
|
||||
|
||||
// Check against the interface object.
|
||||
if (!(imageData instanceof ImageData))
|
||||
statusMessage += ", Bad interface object in worker";
|
||||
|
||||
// Check the getters.
|
||||
if (imageData.width * imageData.height != imageData.data.length / 4) {
|
||||
statusMessage += ", Bad ImageData getters in worker: "
|
||||
statusMessage += [imageData.width, imageData.height].join(', ');
|
||||
}
|
||||
|
||||
// Make sure that writing to .data is a no-op when not in strict mode.
|
||||
var origData = imageData.data;
|
||||
var threw = false;
|
||||
try {
|
||||
imageData.data = [];
|
||||
imageData.width = 2;
|
||||
imageData.height = 2;
|
||||
} catch(e) { threw = true; }
|
||||
if (threw || imageData.data !== origData)
|
||||
statusMessage = statusMessage + ", Should silently ignore sets";
|
||||
|
||||
|
||||
|
||||
// Send back a new pattern.
|
||||
pattern = makePattern(imageData.data.length, 99, 2);
|
||||
setPattern(imageData, pattern);
|
||||
self.postMessage({ statusMessage: statusMessage, imageData: imageData,
|
||||
pattern: pattern });
|
||||
}
|
202
dom/workers/ImageData.cpp
Normal file
202
dom/workers/ImageData.cpp
Normal file
@ -0,0 +1,202 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "ImageData.h"
|
||||
|
||||
#include "jsfriendapi.h"
|
||||
|
||||
#include "nsTraceRefcnt.h"
|
||||
|
||||
#define PROPERTY_FLAGS \
|
||||
(JSPROP_ENUMERATE | JSPROP_SHARED)
|
||||
|
||||
USING_WORKERS_NAMESPACE
|
||||
|
||||
namespace {
|
||||
|
||||
class ImageData
|
||||
{
|
||||
static JSClass sClass;
|
||||
static JSPropertySpec sProperties[];
|
||||
|
||||
enum SLOT {
|
||||
SLOT_width = 0,
|
||||
SLOT_height,
|
||||
SLOT_data,
|
||||
|
||||
SLOT_COUNT
|
||||
};
|
||||
|
||||
public:
|
||||
static JSObject*
|
||||
InitClass(JSContext* aCx, JSObject* aObj)
|
||||
{
|
||||
return JS_InitClass(aCx, aObj, NULL, &sClass, Construct, 0, sProperties,
|
||||
NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
static JSObject*
|
||||
Create(JSContext* aCx, uint32_t aWidth, uint32_t aHeight, JSObject *aData)
|
||||
{
|
||||
MOZ_ASSERT(aData);
|
||||
MOZ_ASSERT(JS_IsTypedArrayObject(aData, aCx));
|
||||
MOZ_ASSERT(JS_IsUint8ClampedArray(aData, aCx));
|
||||
|
||||
JSObject* obj = JS_NewObject(aCx, &sClass, NULL, NULL);
|
||||
if (!obj) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
JS_SetReservedSlot(obj, SLOT_width, UINT_TO_JSVAL(aWidth));
|
||||
JS_SetReservedSlot(obj, SLOT_height, UINT_TO_JSVAL(aHeight));
|
||||
JS_SetReservedSlot(obj, SLOT_data, OBJECT_TO_JSVAL(aData));
|
||||
|
||||
// This is an empty object. The point is just to differentiate instances
|
||||
// from the interface object.
|
||||
ImageData* priv = new ImageData();
|
||||
JS_SetPrivate(obj, priv);
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
static bool
|
||||
IsInstance(JSObject* aObj)
|
||||
{
|
||||
return JS_GetClass(aObj) == &sClass;
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
GetWidth(JSObject* aObj)
|
||||
{
|
||||
MOZ_ASSERT(IsInstance(aObj));
|
||||
return JS_DoubleToUint32(JS_GetReservedSlot(aObj, SLOT_width).toNumber());
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
GetHeight(JSObject* aObj)
|
||||
{
|
||||
MOZ_ASSERT(IsInstance(aObj));
|
||||
return JS_DoubleToUint32(JS_GetReservedSlot(aObj, SLOT_height).toNumber());
|
||||
}
|
||||
|
||||
static
|
||||
JSObject* GetData(JSObject* aObj)
|
||||
{
|
||||
MOZ_ASSERT(IsInstance(aObj));
|
||||
return &JS_GetReservedSlot(aObj, SLOT_data).toObject();
|
||||
}
|
||||
|
||||
private:
|
||||
ImageData()
|
||||
{
|
||||
MOZ_COUNT_CTOR(mozilla::dom::workers::ImageData);
|
||||
}
|
||||
|
||||
~ImageData()
|
||||
{
|
||||
MOZ_COUNT_DTOR(mozilla::dom::workers::ImageData);
|
||||
}
|
||||
|
||||
static JSBool
|
||||
Construct(JSContext* aCx, unsigned aArgc, jsval* aVp)
|
||||
{
|
||||
JS_ReportErrorNumber(aCx, js_GetErrorMessage, NULL, JSMSG_WRONG_CONSTRUCTOR,
|
||||
sClass.name);
|
||||
return false;
|
||||
}
|
||||
|
||||
static void
|
||||
Finalize(JSFreeOp* aFop, JSObject* aObj)
|
||||
{
|
||||
MOZ_ASSERT(JS_GetClass(aObj) == &sClass);
|
||||
delete static_cast<ImageData*>(JS_GetPrivate(aObj));
|
||||
}
|
||||
|
||||
static JSBool
|
||||
GetProperty(JSContext* aCx, JSObject* aObj, jsid aIdval, jsval* aVp)
|
||||
{
|
||||
JSClass* classPtr = JS_GetClass(aObj);
|
||||
if (classPtr != &sClass) {
|
||||
JS_ReportErrorNumber(aCx, js_GetErrorMessage, NULL,
|
||||
JSMSG_INCOMPATIBLE_PROTO, sClass.name, "GetProperty",
|
||||
classPtr->name);
|
||||
return false;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(JSID_IS_INT(aIdval));
|
||||
MOZ_ASSERT(JSID_TO_INT(aIdval) >= 0 && JSID_TO_INT(aIdval) < SLOT_COUNT);
|
||||
|
||||
*aVp = JS_GetReservedSlot(aObj, JSID_TO_INT(aIdval));
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
JSClass ImageData::sClass = {
|
||||
"ImageData",
|
||||
JSCLASS_HAS_PRIVATE | JSCLASS_HAS_RESERVED_SLOTS(SLOT_COUNT),
|
||||
JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
|
||||
JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, Finalize
|
||||
};
|
||||
|
||||
JSPropertySpec ImageData::sProperties[] = {
|
||||
// These properties are read-only per spec, which means that sets must throw
|
||||
// in strict mode and silently fail otherwise. This is a problem for workers
|
||||
// in general (because js_GetterOnlyPropertyStub throws unconditionally). The
|
||||
// general plan for fixing this involves the new DOM bindings. But Peace
|
||||
// Keeper breaks if we throw when setting these properties, so we need to do
|
||||
// something about it in the mean time. So we use NULL, which defaults to the
|
||||
// class setter (JS_StrictPropertyStub), which is always a silent no-op,
|
||||
// regardless of strict mode. Not ideal, but good enough for now.
|
||||
{ "width", SLOT_width, PROPERTY_FLAGS, GetProperty, NULL },
|
||||
{ "height", SLOT_height, PROPERTY_FLAGS, GetProperty, NULL },
|
||||
{ "data", SLOT_data, PROPERTY_FLAGS, GetProperty, NULL },
|
||||
{ 0, 0, 0, NULL, NULL }
|
||||
};
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
BEGIN_WORKERS_NAMESPACE
|
||||
|
||||
namespace imagedata {
|
||||
|
||||
bool
|
||||
InitClass(JSContext* aCx, JSObject* aGlobal)
|
||||
{
|
||||
return !!ImageData::InitClass(aCx, aGlobal);
|
||||
}
|
||||
|
||||
JSObject*
|
||||
Create(JSContext* aCx, uint32_t aWidth, uint32_t aHeight, JSObject* aData)
|
||||
{
|
||||
return ImageData::Create(aCx, aWidth, aHeight, aData);
|
||||
}
|
||||
|
||||
bool
|
||||
IsImageData(JSObject* aObj)
|
||||
{
|
||||
return ImageData::IsInstance(aObj);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
GetWidth(JSObject* aObj)
|
||||
{
|
||||
return ImageData::GetWidth(aObj);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
GetHeight(JSObject* aObj)
|
||||
{
|
||||
return ImageData::GetHeight(aObj);
|
||||
}
|
||||
|
||||
JSObject*
|
||||
GetData(JSObject* aObj)
|
||||
{
|
||||
return ImageData::GetData(aObj);
|
||||
}
|
||||
|
||||
|
||||
} // namespace imagedata
|
||||
|
||||
END_WORKERS_NAMESPACE
|
41
dom/workers/ImageData.h
Normal file
41
dom/workers/ImageData.h
Normal file
@ -0,0 +1,41 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_dom_workers_imagedata_h__
|
||||
#define mozilla_dom_workers_imagedata_h__
|
||||
|
||||
#include "Workers.h"
|
||||
|
||||
BEGIN_WORKERS_NAMESPACE
|
||||
|
||||
namespace imagedata {
|
||||
|
||||
bool
|
||||
InitClass(JSContext* aCx, JSObject* aGlobal);
|
||||
|
||||
JSObject*
|
||||
Create(JSContext* aCx, uint32_t aWidth, uint32_t aHeight, JSObject* aData);
|
||||
|
||||
/*
|
||||
* All data members live in private slots on the JS Object. Callers must
|
||||
* first check IsImageData, after which they may call the data accessors.
|
||||
*/
|
||||
|
||||
bool
|
||||
IsImageData(JSObject* aObj);
|
||||
|
||||
uint32_t
|
||||
GetWidth(JSObject* aObj);
|
||||
|
||||
uint32_t
|
||||
GetHeight(JSObject* aObj);
|
||||
|
||||
JSObject*
|
||||
GetData(JSObject* aObj);
|
||||
|
||||
} // namespace imagedata
|
||||
|
||||
END_WORKERS_NAMESPACE
|
||||
|
||||
#endif // mozilla_dom_workers_imagedata_h__
|
@ -24,6 +24,7 @@ CPPSRCS = \
|
||||
File.cpp \
|
||||
FileReaderSync.cpp \
|
||||
FileReaderSyncPrivate.cpp \
|
||||
ImageData.cpp \
|
||||
Location.cpp \
|
||||
Navigator.cpp \
|
||||
Principal.cpp \
|
||||
|
@ -79,6 +79,7 @@
|
||||
#include "Events.h"
|
||||
#include "Exceptions.h"
|
||||
#include "File.h"
|
||||
#include "ImageData.h"
|
||||
#include "Principal.h"
|
||||
#include "RuntimeService.h"
|
||||
#include "ScriptLoader.h"
|
||||
@ -103,6 +104,7 @@ using mozilla::dom::workers::exceptions::ThrowDOMExceptionForCode;
|
||||
|
||||
USING_WORKERS_NAMESPACE
|
||||
using namespace mozilla::dom::workers::events;
|
||||
using namespace mozilla::dom;
|
||||
|
||||
namespace {
|
||||
|
||||
@ -333,6 +335,25 @@ struct WorkerStructuredCloneCallbacks
|
||||
return jsBlob;
|
||||
}
|
||||
}
|
||||
// See if the object is an ImageData.
|
||||
else if (aTag == SCTAG_DOM_IMAGEDATA) {
|
||||
JS_ASSERT(!aData);
|
||||
|
||||
// Read the information out of the stream.
|
||||
uint32_t width, height;
|
||||
jsval dataArray;
|
||||
if (!JS_ReadUint32Pair(aReader, &width, &height) ||
|
||||
!JS_ReadTypedArray(aReader, &dataArray))
|
||||
{
|
||||
return nsnull;
|
||||
}
|
||||
MOZ_ASSERT(dataArray.isObject());
|
||||
|
||||
// Construct the ImageData.
|
||||
JSObject* obj = imagedata::Create(aCx, width, height,
|
||||
JSVAL_TO_OBJECT(dataArray));
|
||||
return obj;
|
||||
}
|
||||
|
||||
Error(aCx, 0);
|
||||
return nsnull;
|
||||
@ -374,6 +395,19 @@ struct WorkerStructuredCloneCallbacks
|
||||
}
|
||||
}
|
||||
|
||||
// See if this is an ImageData object.
|
||||
if (imagedata::IsImageData(aObj)) {
|
||||
// Pull the properties off the object.
|
||||
uint32_t width = imagedata::GetWidth(aObj);
|
||||
uint32_t height = imagedata::GetHeight(aObj);
|
||||
JSObject* data = imagedata::GetData(aObj);
|
||||
|
||||
// Write the structured clone.
|
||||
return JS_WriteUint32Pair(aWriter, SCTAG_DOM_IMAGEDATA, 0) &&
|
||||
JS_WriteUint32Pair(aWriter, width, height) &&
|
||||
JS_WriteTypedArray(aWriter, OBJECT_TO_JSVAL(data));
|
||||
}
|
||||
|
||||
Error(aCx, 0);
|
||||
return false;
|
||||
}
|
||||
@ -466,12 +500,6 @@ struct MainThreadWorkerStructuredCloneCallbacks
|
||||
}
|
||||
}
|
||||
|
||||
JSObject* clone =
|
||||
WorkerStructuredCloneCallbacks::Read(aCx, aReader, aTag, aData, aClosure);
|
||||
if (clone) {
|
||||
return clone;
|
||||
}
|
||||
|
||||
JS_ClearPendingException(aCx);
|
||||
return NS_DOMReadStructuredClone(aCx, aReader, aTag, aData, nsnull);
|
||||
}
|
||||
@ -527,12 +555,6 @@ struct MainThreadWorkerStructuredCloneCallbacks
|
||||
}
|
||||
}
|
||||
|
||||
JSBool ok =
|
||||
WorkerStructuredCloneCallbacks::Write(aCx, aWriter, aObj, aClosure);
|
||||
if (ok) {
|
||||
return ok;
|
||||
}
|
||||
|
||||
JS_ClearPendingException(aCx);
|
||||
return NS_DOMWriteStructuredClone(aCx, aWriter, aObj, nsnull);
|
||||
}
|
||||
|
@ -55,6 +55,7 @@
|
||||
#include "nsStringGlue.h"
|
||||
#include "nsTArray.h"
|
||||
#include "nsTPriorityQueue.h"
|
||||
#include "StructuredCloneTags.h"
|
||||
|
||||
#include "EventTarget.h"
|
||||
#include "Queue.h"
|
||||
@ -812,7 +813,7 @@ GetWorkerPrivateFromContext(JSContext* aCx);
|
||||
|
||||
enum WorkerStructuredDataType
|
||||
{
|
||||
DOMWORKER_SCTAG_FILE = JS_SCTAG_USER_MIN + 0x1000,
|
||||
DOMWORKER_SCTAG_FILE = SCTAG_DOM_MAX,
|
||||
DOMWORKER_SCTAG_BLOB,
|
||||
|
||||
DOMWORKER_SCTAG_END
|
||||
|
@ -62,6 +62,7 @@
|
||||
#include "File.h"
|
||||
#include "FileReaderSync.h"
|
||||
#include "Location.h"
|
||||
#include "ImageData.h"
|
||||
#include "Navigator.h"
|
||||
#include "Principal.h"
|
||||
#include "ScriptLoader.h"
|
||||
@ -996,6 +997,7 @@ CreateDedicatedWorkerGlobalScope(JSContext* aCx)
|
||||
!filereadersync::InitClass(aCx, global) ||
|
||||
!exceptions::InitClasses(aCx, global) ||
|
||||
!location::InitClass(aCx, global) ||
|
||||
!imagedata::InitClass(aCx, global) ||
|
||||
!navigator::InitClass(aCx, global)) {
|
||||
return NULL;
|
||||
}
|
||||
|
@ -61,6 +61,8 @@ endif
|
||||
|
||||
EXPORTS = \
|
||||
BasicLayers.h \
|
||||
BasicTiledThebesLayer.h \
|
||||
BasicImplData.h \
|
||||
ImageLayers.h \
|
||||
Layers.h \
|
||||
LayerManagerOGL.h \
|
||||
@ -72,6 +74,7 @@ EXPORTS = \
|
||||
CPPSRCS = \
|
||||
BasicImages.cpp \
|
||||
BasicLayers.cpp \
|
||||
BasicTiledThebesLayer.cpp \
|
||||
Layers.cpp \
|
||||
RenderTrace.cpp \
|
||||
ReadbackProcessor.cpp \
|
||||
@ -82,6 +85,7 @@ CPPSRCS = \
|
||||
ImageLayerOGL.cpp \
|
||||
LayerManagerOGL.cpp \
|
||||
ThebesLayerOGL.cpp \
|
||||
TiledThebesLayerOGL.cpp \
|
||||
LayerSorter.cpp \
|
||||
ImageLayers.cpp \
|
||||
$(NULL)
|
||||
|
@ -8,7 +8,11 @@
|
||||
#define TILEDLAYERBUFFER_TILE_SIZE 256
|
||||
|
||||
// Debug defines
|
||||
//#define FORCE_BASICTILEDTHEBESLAYER
|
||||
#ifdef MOZ_JAVA_COMPOSITOR
|
||||
// This needs to go away as we enabled tiled
|
||||
// layers everywhere.
|
||||
#define FORCE_BASICTILEDTHEBESLAYER
|
||||
#endif
|
||||
//#define GFX_TILEDLAYER_DEBUG_OVERLAY
|
||||
//#define GFX_TILEDLAYER_PREF_WARNINGS
|
||||
|
||||
@ -116,8 +120,6 @@ protected:
|
||||
int mRetainedHeight; // in tiles
|
||||
|
||||
private:
|
||||
TiledLayerBuffer(const TiledLayerBuffer&) MOZ_DELETE;
|
||||
|
||||
const Derived& AsDerived() const { return *static_cast<const Derived*>(this); }
|
||||
Derived& AsDerived() { return *static_cast<Derived*>(this); }
|
||||
|
||||
|
@ -49,6 +49,7 @@
|
||||
|
||||
#include "BasicLayers.h"
|
||||
#include "BasicImplData.h"
|
||||
#include "BasicTiledThebesLayer.h"
|
||||
#include "ImageLayers.h"
|
||||
#include "RenderTrace.h"
|
||||
|
||||
@ -3126,10 +3127,23 @@ already_AddRefed<ThebesLayer>
|
||||
BasicShadowLayerManager::CreateThebesLayer()
|
||||
{
|
||||
NS_ASSERTION(InConstruction(), "Only allowed in construction phase");
|
||||
nsRefPtr<BasicShadowableThebesLayer> layer =
|
||||
new BasicShadowableThebesLayer(this);
|
||||
MAYBE_CREATE_SHADOW(Thebes);
|
||||
return layer.forget();
|
||||
#ifdef FORCE_BASICTILEDTHEBESLAYER
|
||||
if (HasShadowManager() && GetParentBackendType() == LayerManager::LAYERS_OPENGL) {
|
||||
// BasicTiledThebesLayer doesn't support main
|
||||
// thread compositing so only return this layer
|
||||
// type if we have a shadow manager.
|
||||
nsRefPtr<BasicTiledThebesLayer> layer =
|
||||
new BasicTiledThebesLayer(this);
|
||||
MAYBE_CREATE_SHADOW(Thebes);
|
||||
return layer.forget();
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
nsRefPtr<BasicShadowableThebesLayer> layer =
|
||||
new BasicShadowableThebesLayer(this);
|
||||
MAYBE_CREATE_SHADOW(Thebes);
|
||||
return layer.forget();
|
||||
}
|
||||
}
|
||||
|
||||
already_AddRefed<ContainerLayer>
|
||||
|
243
gfx/layers/basic/BasicTiledThebesLayer.cpp
Normal file
243
gfx/layers/basic/BasicTiledThebesLayer.cpp
Normal file
@ -0,0 +1,243 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "mozilla/layers/PLayersChild.h"
|
||||
#include "BasicTiledThebesLayer.h"
|
||||
#include "gfxImageSurface.h"
|
||||
#include "sampler.h"
|
||||
|
||||
#ifdef GFX_TILEDLAYER_DEBUG_OVERLAY
|
||||
#include "cairo.h"
|
||||
#include <sstream>
|
||||
using mozilla::layers::Layer;
|
||||
static void DrawDebugOverlay(gfxImageSurface* imgSurf, int x, int y)
|
||||
{
|
||||
gfxContext c(imgSurf);
|
||||
|
||||
// Draw border
|
||||
c.NewPath();
|
||||
c.SetDeviceColor(gfxRGBA(0.0, 0.0, 0.0, 1.0));
|
||||
c.Rectangle(gfxRect(gfxPoint(0,0),imgSurf->GetSize()));
|
||||
c.Stroke();
|
||||
|
||||
// Build tile description
|
||||
std::stringstream ss;
|
||||
ss << x << ", " << y;
|
||||
|
||||
// Draw text using cairo toy text API
|
||||
cairo_t* cr = c.GetCairo();
|
||||
cairo_set_font_size(cr, 10);
|
||||
cairo_text_extents_t extents;
|
||||
cairo_text_extents(cr, ss.str().c_str(), &extents);
|
||||
|
||||
int textWidth = extents.width + 6;
|
||||
|
||||
c.NewPath();
|
||||
c.SetDeviceColor(gfxRGBA(0.0, 0.0, 0.0, 1.0));
|
||||
c.Rectangle(gfxRect(gfxPoint(2,2),gfxSize(textWidth, 15)));
|
||||
c.Fill();
|
||||
|
||||
c.NewPath();
|
||||
c.SetDeviceColor(gfxRGBA(1.0, 0.0, 0.0, 1.0));
|
||||
c.Rectangle(gfxRect(gfxPoint(2,2),gfxSize(textWidth, 15)));
|
||||
c.Stroke();
|
||||
|
||||
c.NewPath();
|
||||
cairo_move_to(cr, 4, 13);
|
||||
cairo_show_text(cr, ss.str().c_str());
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
gfxASurface::gfxImageFormat
|
||||
BasicTiledLayerBuffer::GetFormat() const
|
||||
{
|
||||
if (mThebesLayer->CanUseOpaqueSurface()) {
|
||||
return gfxASurface::ImageFormatRGB16_565;
|
||||
} else {
|
||||
return gfxASurface::ImageFormatARGB32;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
BasicTiledLayerBuffer::PaintThebes(BasicTiledThebesLayer* aLayer,
|
||||
const nsIntRegion& aNewValidRegion,
|
||||
const nsIntRegion& aPaintRegion,
|
||||
LayerManager::DrawThebesLayerCallback aCallback,
|
||||
void* aCallbackData)
|
||||
{
|
||||
mThebesLayer = aLayer;
|
||||
mCallback = aCallback;
|
||||
mCallbackData = aCallbackData;
|
||||
|
||||
#ifdef GFX_TILEDLAYER_PREF_WARNINGS
|
||||
long start = PR_IntervalNow();
|
||||
#endif
|
||||
if (UseSinglePaintBuffer()) {
|
||||
const nsIntRect bounds = aPaintRegion.GetBounds();
|
||||
{
|
||||
SAMPLE_LABEL("BasicTiledLayerBuffer", "PaintThebesSingleBufferAlloc");
|
||||
mSinglePaintBuffer = new gfxImageSurface(gfxIntSize(bounds.width, bounds.height), GetFormat(), !aLayer->CanUseOpaqueSurface());
|
||||
mSinglePaintBufferOffset = nsIntPoint(bounds.x, bounds.y);
|
||||
}
|
||||
nsRefPtr<gfxContext> ctxt = new gfxContext(mSinglePaintBuffer);
|
||||
ctxt->NewPath();
|
||||
ctxt->Translate(gfxPoint(-bounds.x, -bounds.y));
|
||||
#ifdef GFX_TILEDLAYER_PREF_WARNINGS
|
||||
if (PR_IntervalNow() - start > 3) {
|
||||
printf_stderr("Slow alloc %i\n", PR_IntervalNow() - start);
|
||||
}
|
||||
start = PR_IntervalNow();
|
||||
#endif
|
||||
SAMPLE_LABEL("BasicTiledLayerBuffer", "PaintThebesSingleBufferDraw");
|
||||
mCallback(mThebesLayer, ctxt, aPaintRegion, aPaintRegion, mCallbackData);
|
||||
}
|
||||
|
||||
#ifdef GFX_TILEDLAYER_PREF_WARNINGS
|
||||
if (PR_IntervalNow() - start > 30) {
|
||||
const nsIntRect bounds = aPaintRegion.GetBounds();
|
||||
printf_stderr("Time to draw %i: %i, %i, %i, %i\n", PR_IntervalNow() - start, bounds.x, bounds.y, bounds.width, bounds.height);
|
||||
if (aPaintRegion.IsComplex()) {
|
||||
printf_stderr("Complex region\n");
|
||||
nsIntRegionRectIterator it(aPaintRegion);
|
||||
for (const nsIntRect* rect = it.Next(); rect != nsnull; rect = it.Next()) {
|
||||
printf_stderr(" rect %i, %i, %i, %i\n", rect->x, rect->y, rect->width, rect->height);
|
||||
}
|
||||
}
|
||||
}
|
||||
start = PR_IntervalNow();
|
||||
#endif
|
||||
|
||||
SAMPLE_LABEL("BasicTiledLayerBuffer", "PaintThebesUpdate");
|
||||
Update(aNewValidRegion, aPaintRegion);
|
||||
|
||||
#ifdef GFX_TILEDLAYER_PREF_WARNINGS
|
||||
if (PR_IntervalNow() - start > 10) {
|
||||
const nsIntRect bounds = aPaintRegion.GetBounds();
|
||||
printf_stderr("Time to tile %i: %i, %i, %i, %i\n", PR_IntervalNow() - start, bounds.x, bounds.y, bounds.width, bounds.height);
|
||||
}
|
||||
#endif
|
||||
|
||||
mThebesLayer = nsnull;
|
||||
mCallback = nsnull;
|
||||
mCallbackData = nsnull;
|
||||
mSinglePaintBuffer = nsnull;
|
||||
}
|
||||
|
||||
BasicTiledLayerTile
|
||||
BasicTiledLayerBuffer::ValidateTileInternal(BasicTiledLayerTile aTile,
|
||||
const nsIntPoint& aTileOrigin,
|
||||
const nsIntRect& aDirtyRect)
|
||||
{
|
||||
if (aTile == GetPlaceholderTile()) {
|
||||
gfxImageSurface* tmpTile = new gfxImageSurface(gfxIntSize(GetTileLength(), GetTileLength()),
|
||||
GetFormat(), !mThebesLayer->CanUseOpaqueSurface());
|
||||
aTile = BasicTiledLayerTile(tmpTile);
|
||||
}
|
||||
|
||||
gfxRect drawRect(aDirtyRect.x - aTileOrigin.x, aDirtyRect.y - aTileOrigin.y,
|
||||
aDirtyRect.width, aDirtyRect.height);
|
||||
|
||||
// Use the gfxReusableSurfaceWrapper, which will reuse the surface
|
||||
// if the compositor no longer has a read lock, otherwise the surface
|
||||
// will be copied into a new writable surface.
|
||||
gfxImageSurface* writableSurface;
|
||||
aTile.mSurface = aTile.mSurface->GetWritable(&writableSurface);
|
||||
|
||||
// Bug 742100, this gfxContext really should live on the stack.
|
||||
nsRefPtr<gfxContext> ctxt = new gfxContext(writableSurface);
|
||||
if (!mThebesLayer->CanUseOpaqueSurface()) {
|
||||
ctxt->NewPath();
|
||||
ctxt->SetOperator(gfxContext::OPERATOR_CLEAR);
|
||||
ctxt->Rectangle(drawRect, true);
|
||||
ctxt->Fill();
|
||||
ctxt->SetOperator(gfxContext::OPERATOR_OVER);
|
||||
}
|
||||
if (mSinglePaintBuffer) {
|
||||
ctxt->NewPath();
|
||||
ctxt->SetSource(mSinglePaintBuffer.get(),
|
||||
gfxPoint(mSinglePaintBufferOffset.x - aDirtyRect.x + drawRect.x,
|
||||
mSinglePaintBufferOffset.y - aDirtyRect.y + drawRect.y));
|
||||
ctxt->Rectangle(drawRect, true);
|
||||
ctxt->Fill();
|
||||
} else {
|
||||
ctxt->NewPath();
|
||||
ctxt->Translate(gfxPoint(-aTileOrigin.x, -aTileOrigin.y));
|
||||
nsIntPoint a = aTileOrigin;
|
||||
mCallback(mThebesLayer, ctxt, nsIntRegion(nsIntRect(a, nsIntSize(GetTileLength(), GetTileLength()))), aDirtyRect, mCallbackData);
|
||||
}
|
||||
|
||||
#ifdef GFX_TILEDLAYER_DEBUG_OVERLAY
|
||||
DrawDebugOverlay(writableSurface, aTileOrigin.x, aTileOrigin.y);
|
||||
//aTile->DumpAsDataURL();
|
||||
#endif
|
||||
|
||||
return aTile;
|
||||
}
|
||||
|
||||
BasicTiledLayerTile
|
||||
BasicTiledLayerBuffer::ValidateTile(BasicTiledLayerTile aTile,
|
||||
const nsIntPoint& aTileOrigin,
|
||||
const nsIntRegion& aDirtyRegion)
|
||||
{
|
||||
|
||||
SAMPLE_LABEL("BasicTiledLayerBuffer", "ValidateTile");
|
||||
|
||||
#ifdef GFX_TILEDLAYER_PREF_WARNINGS
|
||||
if (aDirtyRegion.IsComplex()) {
|
||||
printf_stderr("Complex region\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
nsIntRegionRectIterator it(aDirtyRegion);
|
||||
for (const nsIntRect* rect = it.Next(); rect != nsnull; rect = it.Next()) {
|
||||
#ifdef GFX_TILEDLAYER_PREF_WARNINGS
|
||||
printf_stderr(" break into subrect %i, %i, %i, %i\n", rect->x, rect->y, rect->width, rect->height);
|
||||
#endif
|
||||
aTile = ValidateTileInternal(aTile, aTileOrigin, *rect);
|
||||
}
|
||||
|
||||
return aTile;
|
||||
}
|
||||
|
||||
void
|
||||
BasicTiledThebesLayer::FillSpecificAttributes(SpecificLayerAttributes& aAttrs)
|
||||
{
|
||||
aAttrs = ThebesLayerAttributes(GetValidRegion());
|
||||
}
|
||||
|
||||
void
|
||||
BasicTiledThebesLayer::PaintThebes(gfxContext* aContext,
|
||||
LayerManager::DrawThebesLayerCallback aCallback,
|
||||
void* aCallbackData,
|
||||
ReadbackProcessor* aReadback)
|
||||
{
|
||||
if (!aCallback) {
|
||||
BasicManager()->SetTransactionIncomplete();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!HasShadow()) {
|
||||
NS_ASSERTION(false, "Shadow requested for painting\n");
|
||||
return;
|
||||
}
|
||||
|
||||
nsIntRegion regionToPaint = mVisibleRegion;
|
||||
regionToPaint.Sub(regionToPaint, mValidRegion);
|
||||
if (regionToPaint.IsEmpty())
|
||||
return;
|
||||
|
||||
mTiledBuffer.PaintThebes(this, mVisibleRegion, regionToPaint, aCallback, aCallbackData);
|
||||
mTiledBuffer.ReadLock();
|
||||
mValidRegion = mVisibleRegion;
|
||||
|
||||
BasicManager()->PaintedTiledLayerBuffer(BasicManager()->Hold(this), &mTiledBuffer);
|
||||
}
|
||||
|
||||
} // mozilla
|
||||
} // layers
|
215
gfx/layers/basic/BasicTiledThebesLayer.h
Normal file
215
gfx/layers/basic/BasicTiledThebesLayer.h
Normal file
@ -0,0 +1,215 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef GFX_BASICTILEDTHEBESLAYER_H
|
||||
#define GFX_BASICTILEDTHEBESLAYER_H
|
||||
|
||||
#include "TiledLayerBuffer.h"
|
||||
#include "gfxReusableSurfaceWrapper.h"
|
||||
#include "mozilla/layers/ShadowLayers.h"
|
||||
#include "BasicLayers.h"
|
||||
#include "BasicImplData.h"
|
||||
#include <algorithm>
|
||||
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
/**
|
||||
* Represent a single tile in tiled buffer. It's backed
|
||||
* by a gfxReusableSurfaceWrapper that implements a
|
||||
* copy-on-write mechanism while locked. The tile should be
|
||||
* locked before being sent to the compositor and unlocked
|
||||
* as soon as it is uploaded to prevent a copy.
|
||||
* Ideal place to store per tile debug information.
|
||||
*/
|
||||
struct BasicTiledLayerTile {
|
||||
nsRefPtr<gfxReusableSurfaceWrapper> mSurface;
|
||||
#ifdef GFX_TILEDLAYER_DEBUG_OVERLAY
|
||||
TimeStamp mLastUpdate;
|
||||
#endif
|
||||
|
||||
// Placeholder
|
||||
BasicTiledLayerTile()
|
||||
: mSurface(NULL)
|
||||
{}
|
||||
explicit BasicTiledLayerTile(gfxImageSurface* aSurface)
|
||||
: mSurface(new gfxReusableSurfaceWrapper(aSurface))
|
||||
{
|
||||
}
|
||||
BasicTiledLayerTile(const BasicTiledLayerTile& o) {
|
||||
mSurface = o.mSurface;
|
||||
#ifdef GFX_TILEDLAYER_DEBUG_OVERLAY
|
||||
mLastUpdate = o.mLastUpdate;
|
||||
#endif
|
||||
}
|
||||
BasicTiledLayerTile& operator=(const BasicTiledLayerTile& o) {
|
||||
if (this == &o) return *this;
|
||||
mSurface = o.mSurface;
|
||||
#ifdef GFX_TILEDLAYER_DEBUG_OVERLAY
|
||||
mLastUpdate = o.mLastUpdate;
|
||||
#endif
|
||||
return *this;
|
||||
}
|
||||
bool operator== (const BasicTiledLayerTile& o) const {
|
||||
return mSurface == o.mSurface;
|
||||
}
|
||||
bool operator!= (const BasicTiledLayerTile& o) const {
|
||||
return mSurface != o.mSurface;
|
||||
}
|
||||
void ReadUnlock() {
|
||||
mSurface->ReadUnlock();
|
||||
}
|
||||
void ReadLock() {
|
||||
mSurface->ReadLock();
|
||||
}
|
||||
};
|
||||
|
||||
class BasicTiledThebesLayer;
|
||||
|
||||
/**
|
||||
* Provide an instance of TiledLayerBuffer backed by image surfaces.
|
||||
* This buffer provides an implementation to ValidateTile using a
|
||||
* thebes callback and can support painting using a single paint buffer
|
||||
* which is much faster then painting directly into the tiles.
|
||||
*/
|
||||
|
||||
class BasicTiledLayerBuffer : public TiledLayerBuffer<BasicTiledLayerBuffer, BasicTiledLayerTile>
|
||||
{
|
||||
friend class TiledLayerBuffer<BasicTiledLayerBuffer, BasicTiledLayerTile>;
|
||||
|
||||
public:
|
||||
BasicTiledLayerBuffer()
|
||||
{}
|
||||
|
||||
void PaintThebes(BasicTiledThebesLayer* aLayer,
|
||||
const nsIntRegion& aNewValidRegion,
|
||||
const nsIntRegion& aPaintRegion,
|
||||
LayerManager::DrawThebesLayerCallback aCallback,
|
||||
void* aCallbackData);
|
||||
|
||||
BasicTiledLayerTile GetPlaceholderTile() const {
|
||||
return mPlaceholder;
|
||||
}
|
||||
|
||||
void ReadUnlock() {
|
||||
for (size_t i = 0; i < mRetainedTiles.Length(); i++) {
|
||||
if (mRetainedTiles[i] == GetPlaceholderTile()) continue;
|
||||
mRetainedTiles[i].ReadUnlock();
|
||||
}
|
||||
}
|
||||
|
||||
void ReadLock() {
|
||||
for (size_t i = 0; i < mRetainedTiles.Length(); i++) {
|
||||
if (mRetainedTiles[i] == GetPlaceholderTile()) continue;
|
||||
mRetainedTiles[i].ReadLock();
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
BasicTiledLayerTile ValidateTile(BasicTiledLayerTile aTile,
|
||||
const nsIntPoint& aTileRect,
|
||||
const nsIntRegion& dirtyRect);
|
||||
|
||||
// If this returns true, we perform the paint operation into a single large
|
||||
// buffer and copy it out to the tiles instead of calling PaintThebes() on
|
||||
// each tile individually. Somewhat surprisingly, this turns out to be faster
|
||||
// on Android.
|
||||
bool UseSinglePaintBuffer() { return true; }
|
||||
|
||||
void ReleaseTile(BasicTiledLayerTile aTile) { /* No-op. */ }
|
||||
|
||||
void SwapTiles(BasicTiledLayerTile& aTileA, BasicTiledLayerTile& aTileB) {
|
||||
std::swap(aTileA, aTileB);
|
||||
}
|
||||
|
||||
private:
|
||||
gfxASurface::gfxImageFormat GetFormat() const;
|
||||
BasicTiledThebesLayer* mThebesLayer;
|
||||
LayerManager::DrawThebesLayerCallback mCallback;
|
||||
void* mCallbackData;
|
||||
|
||||
// The buffer we use when UseSinglePaintBuffer() above is true.
|
||||
nsRefPtr<gfxImageSurface> mSinglePaintBuffer;
|
||||
nsIntPoint mSinglePaintBufferOffset;
|
||||
|
||||
BasicTiledLayerTile mPlaceholder;
|
||||
|
||||
BasicTiledLayerTile ValidateTileInternal(BasicTiledLayerTile aTile,
|
||||
const nsIntPoint& aTileOrigin,
|
||||
const nsIntRect& aDirtyRect);
|
||||
};
|
||||
|
||||
/**
|
||||
* An implementation of ThebesLayer that ONLY supports remote
|
||||
* composition that is backed by tiles. This thebes layer implementation
|
||||
* is better suited to mobile hardware to work around slow implementation
|
||||
* of glTexImage2D (for OGL compositors), and restrait memory bandwidth.
|
||||
*/
|
||||
class BasicTiledThebesLayer : public ThebesLayer,
|
||||
public BasicImplData,
|
||||
public BasicShadowableLayer
|
||||
{
|
||||
typedef ThebesLayer Base;
|
||||
|
||||
public:
|
||||
BasicTiledThebesLayer(BasicShadowLayerManager* const aManager)
|
||||
: ThebesLayer(aManager, static_cast<BasicImplData*>(this))
|
||||
{
|
||||
MOZ_COUNT_CTOR(BasicTiledThebesLayer);
|
||||
}
|
||||
|
||||
~BasicTiledThebesLayer()
|
||||
{
|
||||
MOZ_COUNT_DTOR(BasicTiledThebesLayer);
|
||||
}
|
||||
|
||||
|
||||
// Thebes Layer
|
||||
virtual Layer* AsLayer() { return this; }
|
||||
virtual void InvalidateRegion(const nsIntRegion& aRegion) {
|
||||
mValidRegion.Sub(mValidRegion, aRegion);
|
||||
}
|
||||
|
||||
// BasicImplData
|
||||
virtual bool MustRetainContent() { return HasShadow(); }
|
||||
|
||||
// Shadow methods
|
||||
virtual void FillSpecificAttributes(SpecificLayerAttributes& aAttrs);
|
||||
virtual ShadowableLayer* AsShadowableLayer() { return this; }
|
||||
|
||||
virtual void Disconnect()
|
||||
{
|
||||
BasicShadowableLayer::Disconnect();
|
||||
}
|
||||
|
||||
virtual void PaintThebes(gfxContext* aContext,
|
||||
LayerManager::DrawThebesLayerCallback aCallback,
|
||||
void* aCallbackData,
|
||||
ReadbackProcessor* aReadback);
|
||||
|
||||
private:
|
||||
BasicShadowLayerManager* BasicManager()
|
||||
{
|
||||
return static_cast<BasicShadowLayerManager*>(mManager);
|
||||
}
|
||||
|
||||
// BasicImplData
|
||||
virtual void
|
||||
PaintBuffer(gfxContext* aContext,
|
||||
const nsIntRegion& aRegionToDraw,
|
||||
const nsIntRegion& aExtendedRegionToDraw,
|
||||
const nsIntRegion& aRegionToInvalidate,
|
||||
bool aDidSelfCopy,
|
||||
LayerManager::DrawThebesLayerCallback aCallback,
|
||||
void* aCallbackData)
|
||||
{ NS_RUNTIMEABORT("Not reached."); }
|
||||
|
||||
// Members
|
||||
BasicTiledLayerBuffer mTiledBuffer;
|
||||
};
|
||||
|
||||
} // layers
|
||||
} // mozilla
|
||||
|
||||
#endif
|
@ -162,6 +162,13 @@ struct OpPaintThebesBuffer {
|
||||
nsIntRegion updatedRegion;
|
||||
};
|
||||
|
||||
struct OpPaintTiledLayerBuffer {
|
||||
PLayer layer;
|
||||
// Bug 747811
|
||||
// FIXME: We need to support sharing tile across process.
|
||||
uintptr_t tiledLayerBuffer;
|
||||
};
|
||||
|
||||
struct OpPaintCanvas {
|
||||
PLayer layer;
|
||||
CanvasSurface newFrontBuffer;
|
||||
@ -190,6 +197,7 @@ union Edit {
|
||||
OpRemoveChild;
|
||||
|
||||
OpPaintThebesBuffer;
|
||||
OpPaintTiledLayerBuffer;
|
||||
OpPaintCanvas;
|
||||
OpPaintImage;
|
||||
};
|
||||
|
@ -52,6 +52,7 @@
|
||||
#include "gfxipc/ShadowLayerUtils.h"
|
||||
#include "RenderTrace.h"
|
||||
#include "sampler.h"
|
||||
#include "nsXULAppAPI.h"
|
||||
|
||||
using namespace mozilla::ipc;
|
||||
|
||||
@ -239,6 +240,17 @@ ShadowLayerForwarder::PaintedThebesBuffer(ShadowableLayer* aThebes,
|
||||
aBufferRotation),
|
||||
aUpdatedRegion));
|
||||
}
|
||||
|
||||
void
|
||||
ShadowLayerForwarder::PaintedTiledLayerBuffer(ShadowableLayer* aLayer,
|
||||
BasicTiledLayerBuffer* aTiledLayerBuffer)
|
||||
{
|
||||
if (XRE_GetProcessType() != GeckoProcessType_Default)
|
||||
NS_RUNTIMEABORT("PaintedTiledLayerBuffer must be made IPC safe (not share pointers)");
|
||||
mTxn->AddPaint(OpPaintTiledLayerBuffer(NULL, Shadow(aLayer),
|
||||
uintptr_t(aTiledLayerBuffer)));
|
||||
}
|
||||
|
||||
void
|
||||
ShadowLayerForwarder::PaintedImage(ShadowableLayer* aImage,
|
||||
const SharedImage& aNewFrontImage)
|
||||
|
@ -65,9 +65,11 @@ class ShadowColorLayer;
|
||||
class ShadowCanvasLayer;
|
||||
class SurfaceDescriptor;
|
||||
class ThebesBuffer;
|
||||
class TiledLayerComposer;
|
||||
class Transaction;
|
||||
class SharedImage;
|
||||
class CanvasSurface;
|
||||
class BasicTiledLayerBuffer;
|
||||
|
||||
/**
|
||||
* We want to share layer trees across thread contexts and address
|
||||
@ -187,6 +189,17 @@ public:
|
||||
const nsIntRect& aBufferRect,
|
||||
const nsIntPoint& aBufferRotation,
|
||||
const SurfaceDescriptor& aNewFrontBuffer);
|
||||
|
||||
/**
|
||||
* Notify the compositor that a tiled layer buffer has changed
|
||||
* that needs to be synced to the shadow retained copy. The tiled
|
||||
* layer buffer will operate directly on the shadow retained buffer
|
||||
* and is free to choose it's own internal representation (double buffering,
|
||||
* copy on write, tiling).
|
||||
*/
|
||||
void PaintedTiledLayerBuffer(ShadowableLayer* aThebes,
|
||||
BasicTiledLayerBuffer* aTiledLayerBuffer);
|
||||
|
||||
/**
|
||||
* NB: this initial implementation only forwards RGBA data for
|
||||
* ImageLayers. This is slow, and will be optimized.
|
||||
@ -468,6 +481,8 @@ public:
|
||||
const nsIntRegion& GetShadowVisibleRegion() { return mShadowVisibleRegion; }
|
||||
const gfx3DMatrix& GetShadowTransform() { return mShadowTransform; }
|
||||
|
||||
virtual TiledLayerComposer* AsTiledLayerComposer() { return NULL; }
|
||||
|
||||
protected:
|
||||
ShadowLayer()
|
||||
: mAllocator(nsnull)
|
||||
|
@ -52,6 +52,7 @@
|
||||
|
||||
#include "gfxSharedImageSurface.h"
|
||||
|
||||
#include "TiledLayerBuffer.h"
|
||||
#include "ImageLayers.h"
|
||||
|
||||
typedef std::vector<mozilla::layers::EditReply> EditReplyVector;
|
||||
@ -314,6 +315,20 @@ ShadowLayersParent::RecvUpdate(const InfallibleTArray<Edit>& cset,
|
||||
break;
|
||||
}
|
||||
|
||||
case Edit::TOpPaintTiledLayerBuffer: {
|
||||
MOZ_LAYERS_LOG(("[ParentSide] Paint TiledLayerBuffer"));
|
||||
const OpPaintTiledLayerBuffer& op = edit.get_OpPaintTiledLayerBuffer();
|
||||
ShadowLayerParent* shadow = AsShadowLayer(op);
|
||||
|
||||
ShadowThebesLayer* shadowLayer = static_cast<ShadowThebesLayer*>(shadow->AsLayer());
|
||||
TiledLayerComposer* tileComposer = shadowLayer->AsTiledLayerComposer();
|
||||
|
||||
NS_ASSERTION(tileComposer, "shadowLayer is not a tile composer");
|
||||
|
||||
BasicTiledLayerBuffer* p = (BasicTiledLayerBuffer*)op.tiledLayerBuffer();
|
||||
tileComposer->PaintedTiledLayerBuffer(p);
|
||||
break;
|
||||
}
|
||||
case Edit::TOpPaintThebesBuffer: {
|
||||
MOZ_LAYERS_LOG(("[ParentSide] Paint ThebesLayer"));
|
||||
|
||||
|
@ -48,6 +48,7 @@
|
||||
#include "ImageLayerOGL.h"
|
||||
#include "ColorLayerOGL.h"
|
||||
#include "CanvasLayerOGL.h"
|
||||
#include "TiledThebesLayerOGL.h"
|
||||
#include "mozilla/TimeStamp.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
|
||||
@ -1264,7 +1265,11 @@ LayerManagerOGL::CreateShadowThebesLayer()
|
||||
NS_WARNING("Call on destroyed layer manager");
|
||||
return nsnull;
|
||||
}
|
||||
#ifdef FORCE_BASICTILEDTHEBESLAYER
|
||||
return nsRefPtr<ShadowThebesLayer>(new TiledThebesLayerOGL(this)).forget();
|
||||
#else
|
||||
return nsRefPtr<ShadowThebesLayerOGL>(new ShadowThebesLayerOGL(this)).forget();
|
||||
#endif
|
||||
}
|
||||
|
||||
already_AddRefed<ShadowContainerLayer>
|
||||
|
@ -37,6 +37,7 @@
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "mozilla/layers/PLayers.h"
|
||||
#include "TiledLayerBuffer.h"
|
||||
|
||||
/* This must occur *after* layers/PLayers.h to avoid typedefs conflicts. */
|
||||
#include "mozilla/Util.h"
|
||||
@ -986,6 +987,9 @@ ShadowThebesLayerOGL::ShadowThebesLayerOGL(LayerManagerOGL *aManager)
|
||||
, LayerOGL(aManager)
|
||||
, mUploadTask(nsnull)
|
||||
{
|
||||
#ifdef FORCE_BASICTILEDTHEBESLAYER
|
||||
NS_ABORT();
|
||||
#endif
|
||||
mImplData = static_cast<LayerOGL*>(this);
|
||||
}
|
||||
|
||||
|
203
gfx/layers/opengl/TiledThebesLayerOGL.cpp
Normal file
203
gfx/layers/opengl/TiledThebesLayerOGL.cpp
Normal file
@ -0,0 +1,203 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "mozilla/layers/PLayersChild.h"
|
||||
#include "TiledThebesLayerOGL.h"
|
||||
#include "BasicTiledThebesLayer.h"
|
||||
#include "gfxImageSurface.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
using mozilla::gl::GLContext;
|
||||
|
||||
TiledLayerBufferOGL::~TiledLayerBufferOGL()
|
||||
{
|
||||
if (mRetainedTiles.Length() == 0)
|
||||
return;
|
||||
|
||||
mContext->MakeCurrent();
|
||||
for (size_t i = 0; i < mRetainedTiles.Length(); i++) {
|
||||
if (mRetainedTiles[i] == GetPlaceholderTile())
|
||||
continue;
|
||||
mContext->fDeleteTextures(1, &mRetainedTiles[i].mTextureHandle);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
TiledLayerBufferOGL::ReleaseTile(TiledTexture aTile)
|
||||
{
|
||||
// We've made current prior to calling TiledLayerBufferOGL::Update
|
||||
if (aTile == GetPlaceholderTile())
|
||||
return;
|
||||
mContext->fDeleteTextures(1, &aTile.mTextureHandle);
|
||||
}
|
||||
|
||||
void
|
||||
TiledLayerBufferOGL::Upload(const BasicTiledLayerBuffer* aMainMemoryTiledBuffer,
|
||||
const nsIntRegion& aNewValidRegion,
|
||||
const nsIntRegion& aInvalidateRegion)
|
||||
{
|
||||
#ifdef GFX_TILEDLAYER_PREF_WARNINGS
|
||||
printf_stderr("Upload %i, %i, %i, %i\n", aInvalidateRegion.GetBounds().x, aInvalidateRegion.GetBounds().y, aInvalidateRegion.GetBounds().width, aInvalidateRegion.GetBounds().height);
|
||||
long start = PR_IntervalNow();
|
||||
#endif
|
||||
mMainMemoryTiledBuffer = aMainMemoryTiledBuffer;
|
||||
mContext->MakeCurrent();
|
||||
Update(aNewValidRegion, aInvalidateRegion);
|
||||
mMainMemoryTiledBuffer = nsnull;
|
||||
#ifdef GFX_TILEDLAYER_PREF_WARNINGS
|
||||
if (PR_IntervalNow() - start > 10) {
|
||||
printf_stderr("Time to upload %i\n", PR_IntervalNow() - start);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
TiledLayerBufferOGL::GetFormatAndTileForImageFormat(gfxASurface::gfxImageFormat aFormat,
|
||||
GLenum& aOutFormat,
|
||||
GLenum& aOutType)
|
||||
{
|
||||
if (aFormat == gfxASurface::ImageFormatRGB16_565) {
|
||||
aOutFormat = LOCAL_GL_RGB;
|
||||
aOutType = LOCAL_GL_UNSIGNED_SHORT_5_6_5;
|
||||
} else {
|
||||
aOutFormat = LOCAL_GL_RGBA;
|
||||
aOutType = LOCAL_GL_UNSIGNED_BYTE;
|
||||
}
|
||||
}
|
||||
|
||||
TiledTexture
|
||||
TiledLayerBufferOGL::ValidateTile(TiledTexture aTile,
|
||||
const nsIntPoint& aTileOrigin,
|
||||
const nsIntRegion& aDirtyRect)
|
||||
{
|
||||
#ifdef GFX_TILEDLAYER_PREF_WARNINGS
|
||||
printf_stderr("Upload tile %i, %i\n", aTileOrigin.x, aTileOrigin.y);
|
||||
long start = PR_IntervalNow();
|
||||
#endif
|
||||
if (aTile == GetPlaceholderTile()) {
|
||||
mContext->fGenTextures(1, &aTile.mTextureHandle);
|
||||
mContext->fBindTexture(LOCAL_GL_TEXTURE_2D, aTile.mTextureHandle);
|
||||
mContext->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MIN_FILTER, LOCAL_GL_LINEAR);
|
||||
mContext->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MAG_FILTER, LOCAL_GL_LINEAR);
|
||||
mContext->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_S, LOCAL_GL_CLAMP_TO_EDGE);
|
||||
mContext->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_T, LOCAL_GL_CLAMP_TO_EDGE);
|
||||
} else {
|
||||
mContext->fBindTexture(LOCAL_GL_TEXTURE_2D, aTile.mTextureHandle);
|
||||
}
|
||||
|
||||
nsRefPtr<gfxReusableSurfaceWrapper> reusableSurface = mMainMemoryTiledBuffer->GetTile(aTileOrigin).mSurface.get();
|
||||
GLenum format, type;
|
||||
GetFormatAndTileForImageFormat(reusableSurface->Format(), format, type);
|
||||
|
||||
const unsigned char* buf = reusableSurface->GetReadOnlyData();
|
||||
mContext->fTexImage2D(LOCAL_GL_TEXTURE_2D, 0, format,
|
||||
GetTileLength(), GetTileLength(), 0,
|
||||
format, type, buf);
|
||||
|
||||
aTile.mFormat = format;
|
||||
|
||||
#ifdef GFX_TILEDLAYER_PREF_WARNINGS
|
||||
if (PR_IntervalNow() - start > 1) {
|
||||
printf_stderr("Tile Time to upload %i\n", PR_IntervalNow() - start);
|
||||
}
|
||||
#endif
|
||||
return aTile;
|
||||
}
|
||||
|
||||
TiledThebesLayerOGL::TiledThebesLayerOGL(LayerManagerOGL *aManager)
|
||||
: ShadowThebesLayer(aManager, nsnull)
|
||||
, LayerOGL(aManager)
|
||||
, mVideoMemoryTiledBuffer(aManager->gl())
|
||||
{
|
||||
mImplData = static_cast<LayerOGL*>(this);
|
||||
}
|
||||
|
||||
void
|
||||
TiledThebesLayerOGL::PaintedTiledLayerBuffer(const BasicTiledLayerBuffer* mTiledBuffer)
|
||||
{
|
||||
mMainMemoryTiledBuffer = *mTiledBuffer;
|
||||
mRegionToUpload.Or(mRegionToUpload, mMainMemoryTiledBuffer.GetLastPaintRegion());
|
||||
|
||||
gl()->MakeCurrent();
|
||||
|
||||
ProcessUploadQueue(); // TODO: Remove me; this should be unnecessary.
|
||||
}
|
||||
|
||||
void
|
||||
TiledThebesLayerOGL::ProcessUploadQueue()
|
||||
{
|
||||
if (mRegionToUpload.IsEmpty())
|
||||
return;
|
||||
|
||||
mVideoMemoryTiledBuffer.Upload(&mMainMemoryTiledBuffer, mMainMemoryTiledBuffer.GetValidRegion(), mRegionToUpload);
|
||||
mValidRegion = mVideoMemoryTiledBuffer.GetValidRegion();
|
||||
|
||||
mMainMemoryTiledBuffer.ReadUnlock();
|
||||
// Release all the tiles by replacing the tile buffer with an empty
|
||||
// tiled buffer. This will prevent us from doing a double unlock when
|
||||
// calling ~TiledThebesLayerOGL.
|
||||
// FIXME: This wont be needed when we do progressive upload and lock
|
||||
// tile by tile.
|
||||
mMainMemoryTiledBuffer = BasicTiledLayerBuffer();
|
||||
mRegionToUpload = nsIntRegion();
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
TiledThebesLayerOGL::RenderLayer(int aPreviousFrameBuffer, const nsIntPoint& aOffset)
|
||||
{
|
||||
gl()->MakeCurrent();
|
||||
ProcessUploadQueue();
|
||||
|
||||
const nsIntRegion& visibleRegion = GetEffectiveVisibleRegion();
|
||||
const nsIntRect visibleRect = visibleRegion.GetBounds();
|
||||
unsigned int rowCount = 0;
|
||||
int tileX = 0;
|
||||
for (size_t x = visibleRect.x; x < visibleRect.x + visibleRect.width;) {
|
||||
rowCount++;
|
||||
uint16_t tileStartX = x % mVideoMemoryTiledBuffer.GetTileLength();
|
||||
uint16_t w = mVideoMemoryTiledBuffer.GetTileLength() - tileStartX;
|
||||
if (x + w > visibleRect.x + visibleRect.width)
|
||||
w = visibleRect.x + visibleRect.width - x;
|
||||
int tileY = 0;
|
||||
for( size_t y = visibleRect.y; y < visibleRect.y + visibleRect.height;) {
|
||||
uint16_t tileStartY = y % mVideoMemoryTiledBuffer.GetTileLength();
|
||||
uint16_t h = mVideoMemoryTiledBuffer.GetTileLength() - tileStartY;
|
||||
if (y + h > visibleRect.y + visibleRect.height)
|
||||
h = visibleRect.y + visibleRect.height - y;
|
||||
|
||||
TiledTexture tileTexture = mVideoMemoryTiledBuffer.
|
||||
GetTile(nsIntPoint(mVideoMemoryTiledBuffer.RoundDownToTileEdge(x),
|
||||
mVideoMemoryTiledBuffer.RoundDownToTileEdge(y)));
|
||||
if (tileTexture != mVideoMemoryTiledBuffer.GetPlaceholderTile()) {
|
||||
|
||||
gl()->fBindTexture(LOCAL_GL_TEXTURE_2D, tileTexture.mTextureHandle);
|
||||
ColorTextureLayerProgram *program;
|
||||
if (tileTexture.mFormat == LOCAL_GL_RGB) {
|
||||
program = mOGLManager->GetRGBXLayerProgram();
|
||||
} else {
|
||||
program = mOGLManager->GetBGRALayerProgram();
|
||||
}
|
||||
program->Activate();
|
||||
program->SetTextureUnit(0);
|
||||
program->SetLayerOpacity(GetEffectiveOpacity());
|
||||
program->SetLayerTransform(GetEffectiveTransform());
|
||||
program->SetRenderOffset(aOffset);
|
||||
program->SetLayerQuadRect(nsIntRect(x,y,w,h)); // screen
|
||||
mOGLManager->BindAndDrawQuadWithTextureRect(program, nsIntRect(tileStartX, tileStartY, w, h), nsIntSize(mVideoMemoryTiledBuffer.GetTileLength(), mVideoMemoryTiledBuffer.GetTileLength())); // texture bounds
|
||||
|
||||
}
|
||||
tileY++;
|
||||
y += h;
|
||||
}
|
||||
tileX++;
|
||||
x += w;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} // mozilla
|
||||
} // layers
|
138
gfx/layers/opengl/TiledThebesLayerOGL.h
Normal file
138
gfx/layers/opengl/TiledThebesLayerOGL.h
Normal file
@ -0,0 +1,138 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef GFX_TILEDTHEBESLAYEROGL_H
|
||||
#define GFX_TILEDTHEBESLAYEROGL_H
|
||||
|
||||
#include "mozilla/layers/ShadowLayers.h"
|
||||
#include "TiledLayerBuffer.h"
|
||||
#include "Layers.h"
|
||||
#include "LayerManagerOGL.h"
|
||||
#include "BasicTiledThebesLayer.h"
|
||||
#include <algorithm>
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
namespace gl {
|
||||
class GLContext;
|
||||
}
|
||||
|
||||
namespace layers {
|
||||
|
||||
class TiledTexture {
|
||||
public:
|
||||
// Constructs a placeholder TiledTexture. See the comments above
|
||||
// TiledLayerBuffer for more information on what this is used for;
|
||||
// essentially, this is a sentinel used to represent an invalid or blank
|
||||
// tile.
|
||||
//
|
||||
// Note that we assume that zero is not a valid GL texture handle here.
|
||||
TiledTexture()
|
||||
: mTextureHandle(0)
|
||||
, mFormat(0)
|
||||
{}
|
||||
|
||||
// Constructs a TiledTexture from a GL texture handle and an image format.
|
||||
TiledTexture(GLuint aTextureHandle, GLenum aFormat)
|
||||
: mTextureHandle(aTextureHandle)
|
||||
, mFormat(aFormat)
|
||||
{}
|
||||
|
||||
TiledTexture(const TiledTexture& o) {
|
||||
mTextureHandle = o.mTextureHandle;
|
||||
mFormat = o.mFormat;
|
||||
}
|
||||
TiledTexture& operator=(const TiledTexture& o) {
|
||||
if (this == &o) return *this;
|
||||
mTextureHandle = o.mTextureHandle;
|
||||
mFormat = o.mFormat;
|
||||
return *this;
|
||||
}
|
||||
bool operator== (const TiledTexture& o) const {
|
||||
return mTextureHandle == o.mTextureHandle;
|
||||
}
|
||||
bool operator!= (const TiledTexture& o) const {
|
||||
return mTextureHandle != o.mTextureHandle;
|
||||
}
|
||||
|
||||
GLuint mTextureHandle;
|
||||
GLenum mFormat;
|
||||
};
|
||||
|
||||
class TiledLayerBufferOGL : public TiledLayerBuffer<TiledLayerBufferOGL, TiledTexture>
|
||||
{
|
||||
friend class TiledLayerBuffer<TiledLayerBufferOGL, TiledTexture>;
|
||||
|
||||
public:
|
||||
TiledLayerBufferOGL(gl::GLContext* aContext)
|
||||
: mContext(aContext)
|
||||
{}
|
||||
|
||||
~TiledLayerBufferOGL();
|
||||
|
||||
void Upload(const BasicTiledLayerBuffer* aMainMemoryTiledBuffer,
|
||||
const nsIntRegion& aNewValidRegion,
|
||||
const nsIntRegion& aInvalidateRegion);
|
||||
|
||||
TiledTexture GetPlaceholderTile() const { return TiledTexture(); }
|
||||
|
||||
protected:
|
||||
TiledTexture ValidateTile(TiledTexture aTile,
|
||||
const nsIntPoint& aTileRect,
|
||||
const nsIntRegion& dirtyRect);
|
||||
|
||||
void ReleaseTile(TiledTexture aTile);
|
||||
|
||||
void SwapTiles(TiledTexture& aTileA, TiledTexture& aTileB) {
|
||||
std::swap(aTileA, aTileB);
|
||||
}
|
||||
|
||||
private:
|
||||
nsRefPtr<gl::GLContext> mContext;
|
||||
const BasicTiledLayerBuffer* mMainMemoryTiledBuffer;
|
||||
|
||||
void GetFormatAndTileForImageFormat(gfxASurface::gfxImageFormat aFormat,
|
||||
GLenum& aOutFormat,
|
||||
GLenum& aOutType);
|
||||
};
|
||||
|
||||
class TiledThebesLayerOGL : public ShadowThebesLayer,
|
||||
public LayerOGL,
|
||||
public TiledLayerComposer
|
||||
{
|
||||
public:
|
||||
TiledThebesLayerOGL(LayerManagerOGL *aManager);
|
||||
virtual ~TiledThebesLayerOGL()
|
||||
{
|
||||
mMainMemoryTiledBuffer.ReadUnlock();
|
||||
}
|
||||
|
||||
// LayerOGL impl
|
||||
void Destroy() {}
|
||||
Layer* GetLayer() { return this; }
|
||||
virtual void RenderLayer(int aPreviousFrameBuffer,
|
||||
const nsIntPoint& aOffset);
|
||||
virtual void CleanupResources() { }
|
||||
|
||||
// Shadow
|
||||
virtual TiledLayerComposer* AsTiledLayerComposer() { return this; }
|
||||
virtual void DestroyFrontBuffer() {}
|
||||
void Swap(const ThebesBuffer& aNewFront, const nsIntRegion& aUpdatedRegion,
|
||||
OptionalThebesBuffer* aNewBack, nsIntRegion* aNewBackValidRegion,
|
||||
OptionalThebesBuffer* aReadOnlyFront, nsIntRegion* aFrontUpdatedRegion)
|
||||
{
|
||||
NS_ABORT_IF_FALSE(false, "Not supported");
|
||||
}
|
||||
void PaintedTiledLayerBuffer(const BasicTiledLayerBuffer* mTiledBuffer);
|
||||
void ProcessUploadQueue();
|
||||
private:
|
||||
nsIntRegion mRegionToUpload;
|
||||
BasicTiledLayerBuffer mMainMemoryTiledBuffer;
|
||||
TiledLayerBufferOGL mVideoMemoryTiledBuffer;
|
||||
};
|
||||
|
||||
} // layers
|
||||
} // mozilla
|
||||
|
||||
#endif
|
@ -9,6 +9,7 @@
|
||||
gfxReusableSurfaceWrapper::gfxReusableSurfaceWrapper(gfxImageSurface* aSurface)
|
||||
: mSurface(aSurface)
|
||||
, mSurfaceData(aSurface->Data())
|
||||
, mFormat(aSurface->Format())
|
||||
, mReadCount(0)
|
||||
{
|
||||
MOZ_COUNT_CTOR(gfxReusableSurfaceWrapper);
|
||||
@ -47,6 +48,7 @@ void
|
||||
gfxReusableSurfaceWrapper::ReadUnlock()
|
||||
{
|
||||
PR_ATOMIC_DECREMENT(&mReadCount);
|
||||
NS_ABORT_IF_FALSE(mReadCount >= 0, "Should not be negative");
|
||||
}
|
||||
|
||||
gfxReusableSurfaceWrapper*
|
||||
@ -60,7 +62,7 @@ gfxReusableSurfaceWrapper::GetWritable(gfxImageSurface** aSurface)
|
||||
}
|
||||
|
||||
// Something else is reading the surface, copy it
|
||||
gfxImageSurface* copySurface = new gfxImageSurface(mSurface->GetSize(), mSurface->Format());
|
||||
gfxImageSurface* copySurface = new gfxImageSurface(mSurface->GetSize(), mSurface->Format(), false);
|
||||
copySurface->CopyFrom(mSurface);
|
||||
*aSurface = copySurface;
|
||||
|
||||
|
@ -5,6 +5,7 @@
|
||||
#ifndef GFXCOWSURFACEWRAPPER
|
||||
#define GFXCOWSURFACEWRAPPER
|
||||
|
||||
#include "gfxASurface.h"
|
||||
#include "nsISupportsImpl.h"
|
||||
#include "nsAutoPtr.h"
|
||||
|
||||
@ -43,6 +44,8 @@ public:
|
||||
return mSurfaceData;
|
||||
}
|
||||
|
||||
const gfxASurface::gfxImageFormat& Format() { return mFormat; }
|
||||
|
||||
/**
|
||||
* Get a writable copy of the image.
|
||||
* If necessary this will copy the wrapper. If there are no contention
|
||||
@ -60,9 +63,10 @@ public:
|
||||
|
||||
private:
|
||||
NS_DECL_OWNINGTHREAD
|
||||
nsRefPtr<gfxImageSurface> mSurface;
|
||||
const unsigned char* mSurfaceData;
|
||||
PRInt32 mReadCount;
|
||||
nsRefPtr<gfxImageSurface> mSurface;
|
||||
const gfxASurface::gfxImageFormat mFormat;
|
||||
const unsigned char* mSurfaceData;
|
||||
PRInt32 mReadCount;
|
||||
};
|
||||
|
||||
#endif // GFXCOWSURFACEWRAPPER
|
||||
|
@ -5183,12 +5183,18 @@ JS_ReadUint32Pair(JSStructuredCloneReader *r, uint32_t *p1, uint32_t *p2);
|
||||
JS_PUBLIC_API(JSBool)
|
||||
JS_ReadBytes(JSStructuredCloneReader *r, void *p, size_t len);
|
||||
|
||||
JS_PUBLIC_API(JSBool)
|
||||
JS_ReadTypedArray(JSStructuredCloneReader *r, jsval *vp);
|
||||
|
||||
JS_PUBLIC_API(JSBool)
|
||||
JS_WriteUint32Pair(JSStructuredCloneWriter *w, uint32_t tag, uint32_t data);
|
||||
|
||||
JS_PUBLIC_API(JSBool)
|
||||
JS_WriteBytes(JSStructuredCloneWriter *w, const void *p, size_t len);
|
||||
|
||||
JS_PUBLIC_API(JSBool)
|
||||
JS_WriteTypedArray(JSStructuredCloneWriter *w, jsval v);
|
||||
|
||||
/************************************************************************/
|
||||
|
||||
/*
|
||||
|
@ -424,6 +424,13 @@ JSStructuredCloneWriter::checkStack()
|
||||
#endif
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(JSBool)
|
||||
JS_WriteTypedArray(JSStructuredCloneWriter *w, jsval v)
|
||||
{
|
||||
JS_ASSERT(v.isObject());
|
||||
return w->writeTypedArray(&v.toObject());
|
||||
}
|
||||
|
||||
bool
|
||||
JSStructuredCloneWriter::writeTypedArray(JSObject *obj)
|
||||
{
|
||||
@ -689,6 +696,16 @@ JSStructuredCloneReader::readString(uint32_t nchars)
|
||||
return str;
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(JSBool)
|
||||
JS_ReadTypedArray(JSStructuredCloneReader *r, jsval *vp)
|
||||
{
|
||||
uint32_t tag, nelems;
|
||||
if (!r->input().readPair(&tag, &nelems))
|
||||
return false;
|
||||
JS_ASSERT(tag >= SCTAG_TYPED_ARRAY_MIN && tag <= SCTAG_TYPED_ARRAY_MAX);
|
||||
return r->readTypedArray(tag, nelems, vp);
|
||||
}
|
||||
|
||||
bool
|
||||
JSStructuredCloneReader::readTypedArray(uint32_t tag, uint32_t nelems, Value *vp)
|
||||
{
|
||||
|
@ -143,6 +143,8 @@ struct JSStructuredCloneReader {
|
||||
|
||||
// Any value passed to JS_ReadStructuredClone.
|
||||
void *closure;
|
||||
|
||||
friend JSBool JS_ReadTypedArray(JSStructuredCloneReader *r, jsval *vp);
|
||||
};
|
||||
|
||||
struct JSStructuredCloneWriter {
|
||||
@ -196,6 +198,8 @@ struct JSStructuredCloneWriter {
|
||||
|
||||
// Any value passed to JS_WriteStructuredClone.
|
||||
void *closure;
|
||||
|
||||
friend JSBool JS_WriteTypedArray(JSStructuredCloneWriter *w, jsval v);
|
||||
};
|
||||
|
||||
#endif /* jsclone_h___ */
|
||||
|
@ -168,6 +168,20 @@ nsLayoutUtils::Are3DTransformsEnabled()
|
||||
return s3DTransformsEnabled;
|
||||
}
|
||||
|
||||
bool
|
||||
nsLayoutUtils::UseBackgroundNearestFiltering()
|
||||
{
|
||||
static bool sUseBackgroundNearestFilteringEnabled;
|
||||
static bool sUseBackgroundNearestFilteringPrefInitialised = false;
|
||||
|
||||
if (!sUseBackgroundNearestFilteringPrefInitialised) {
|
||||
sUseBackgroundNearestFilteringPrefInitialised = true;
|
||||
sUseBackgroundNearestFilteringEnabled = mozilla::Preferences::GetBool("gfx.filter.nearest.force-enabled", false);
|
||||
}
|
||||
|
||||
return sUseBackgroundNearestFilteringEnabled;
|
||||
}
|
||||
|
||||
void
|
||||
nsLayoutUtils::UnionChildOverflow(nsIFrame* aFrame,
|
||||
nsOverflowAreas& aOverflowAreas)
|
||||
@ -3734,6 +3748,11 @@ nsLayoutUtils::DrawBackgroundImage(nsRenderingContext* aRenderingContext,
|
||||
PRUint32 aImageFlags)
|
||||
{
|
||||
SAMPLE_LABEL("layout", "nsLayoutUtils::DrawBackgroundImage");
|
||||
|
||||
if (UseBackgroundNearestFiltering()) {
|
||||
aGraphicsFilter = gfxPattern::FILTER_NEAREST;
|
||||
}
|
||||
|
||||
return DrawImageInternal(aRenderingContext, aImage, aGraphicsFilter,
|
||||
aDest, aFill, aAnchor, aDirty,
|
||||
aImageSize, aImageFlags);
|
||||
|
@ -1496,6 +1496,12 @@ public:
|
||||
*/
|
||||
static bool Are3DTransformsEnabled();
|
||||
|
||||
/**
|
||||
* Checks if we should forcibly use nearest pixel filtering for the
|
||||
* background.
|
||||
*/
|
||||
static bool UseBackgroundNearestFiltering();
|
||||
|
||||
/**
|
||||
* Unions the overflow areas of all non-popup children of aFrame with
|
||||
* aOverflowAreas.
|
||||
|
@ -117,7 +117,8 @@ fails-if(Android) == viewport-translucent-color-3.html viewport-translucent-colo
|
||||
# the image aren't the issue, because they're being obscured to avoid sampling
|
||||
# algorithm dependencies (at least assuming the sampling algorithm in use
|
||||
# doesn't sample too far astray from the boundaries).
|
||||
fails == background-size-zoom-repeat.html background-size-zoom-repeat-ref.html
|
||||
# Android uses FILTER_NEAREST which doesn't suffer from this issue.
|
||||
fails-if(!Android) == background-size-zoom-repeat.html background-size-zoom-repeat-ref.html
|
||||
|
||||
# -moz-default-background-color and -moz-default-color (bug 591341)
|
||||
== background-moz-default-background-color.html background-moz-default-background-color-ref.html
|
||||
|
@ -86,8 +86,9 @@ include empty/reftest.list
|
||||
== tall--contain--percent-width-percent-height-viewbox.html ref-tall-lime48x384-aqua48x384.html
|
||||
|
||||
# We smear the background image when scaling it in these two tests...
|
||||
fails == tall--cover--nonpercent-width-nonpercent-height.html ref-tall-lime256x512-aqua256x256.html
|
||||
fails == tall--cover--nonpercent-width-nonpercent-height-viewbox.html ref-tall-lime256x512-aqua256x256.html
|
||||
# Android uses FILTER_NEAREST for background images so the smear doesn't occur
|
||||
fails-if(!Android) == tall--cover--nonpercent-width-nonpercent-height.html ref-tall-lime256x512-aqua256x256.html
|
||||
fails-if(!Android) == tall--cover--nonpercent-width-nonpercent-height-viewbox.html ref-tall-lime256x512-aqua256x256.html
|
||||
|
||||
# ...but we don't in identical tests with image-rendering: -moz-crisp-edges.
|
||||
== tall--cover--nonpercent-width-nonpercent-height--crisp.html ref-tall-lime256x512-aqua256x256.html
|
||||
|
@ -212,6 +212,12 @@ pref("gfx.downloadable_fonts.enabled", true);
|
||||
pref("gfx.downloadable_fonts.fallback_delay", 3000);
|
||||
pref("gfx.downloadable_fonts.sanitize", true);
|
||||
|
||||
#ifdef ANDROID
|
||||
pref("gfx.filter.nearest.force-enabled", true);
|
||||
#else
|
||||
pref("gfx.filter.nearest.force-enabled", false);
|
||||
#endif
|
||||
|
||||
// whether to always search all font cmaps during system font fallback
|
||||
pref("gfx.font_rendering.fallback.always_use_cmaps", false);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user