Merge mozilla-central into birch

This commit is contained in:
Ehsan Akhgari 2012-04-24 10:49:42 -04:00
commit dadbef66ac
36 changed files with 1456 additions and 29 deletions

View File

@ -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

View File

@ -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
};

View File

@ -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;
}

View File

@ -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)

View 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>

View 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;
}

View 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
View 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
View 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__

View File

@ -24,6 +24,7 @@ CPPSRCS = \
File.cpp \
FileReaderSync.cpp \
FileReaderSyncPrivate.cpp \
ImageData.cpp \
Location.cpp \
Navigator.cpp \
Principal.cpp \

View File

@ -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);
}

View File

@ -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

View File

@ -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;
}

View File

@ -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)

View File

@ -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); }

View File

@ -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>

View 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

View 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

View File

@ -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;
};

View File

@ -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)

View File

@ -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)

View File

@ -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"));

View File

@ -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>

View File

@ -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);
}

View 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

View 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

View File

@ -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;

View File

@ -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

View File

@ -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);
/************************************************************************/
/*

View File

@ -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)
{

View File

@ -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___ */

View File

@ -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);

View File

@ -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.

View File

@ -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

View File

@ -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

View File

@ -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);