mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 387132. Implement native canvas comparisons to speed up reftest running. r+sr=roc
This commit is contained in:
parent
38bbc69620
commit
6a4c51d780
@ -46,6 +46,7 @@
|
||||
*/
|
||||
|
||||
interface nsIDOMElement;
|
||||
interface nsIDOMHTMLCanvasElement;
|
||||
|
||||
[scriptable, uuid(440D036F-0879-4497-9364-35DE49F6849F)]
|
||||
interface nsIDOMWindowUtils : nsISupports {
|
||||
@ -275,4 +276,15 @@ interface nsIDOMWindowUtils : nsISupports {
|
||||
in long aY,
|
||||
in boolean aIgnoreRootScrollFrame,
|
||||
in boolean aFlushLayout);
|
||||
|
||||
/**
|
||||
* Compare the two canvases, returning the number of differing pixels and
|
||||
* the maximum difference in a channel. This will throw an error if
|
||||
* the dimensions of the two canvases are different.
|
||||
*
|
||||
* This method requires UniversalXPConnect privileges.
|
||||
*/
|
||||
PRUint32 compareCanvases(in nsIDOMHTMLCanvasElement aCanvas1,
|
||||
in nsIDOMHTMLCanvasElement aCanvas2,
|
||||
out unsigned long aMaxDifference);
|
||||
};
|
||||
|
@ -57,6 +57,11 @@
|
||||
|
||||
#include "nsIViewManager.h"
|
||||
|
||||
#include "nsIDOMHTMLCanvasElement.h"
|
||||
#include "nsICanvasElement.h"
|
||||
#include "gfxContext.h"
|
||||
#include "gfxImageSurface.h"
|
||||
|
||||
#if defined(MOZ_X11) && defined(MOZ_WIDGET_GTK2)
|
||||
#include <gdk/gdk.h>
|
||||
#include <gdk/gdkx.h>
|
||||
@ -565,3 +570,106 @@ nsDOMWindowUtils::ElementFromPoint(PRInt32 aX, PRInt32 aY,
|
||||
return doc->ElementFromPointHelper(aX, aY, aIgnoreRootScrollFrame, aFlushLayout,
|
||||
aReturn);
|
||||
}
|
||||
|
||||
static already_AddRefed<gfxImageSurface>
|
||||
CanvasToImageSurface(nsIDOMHTMLCanvasElement *canvas)
|
||||
{
|
||||
PRUint32 w, h;
|
||||
nsresult rv;
|
||||
|
||||
nsCOMPtr<nsICanvasElement> elt = do_QueryInterface(canvas);
|
||||
rv = elt->GetSize(&w, &h);
|
||||
if (NS_FAILED(rv))
|
||||
return nsnull;
|
||||
|
||||
nsRefPtr<gfxImageSurface> img = new gfxImageSurface(gfxIntSize(w, h), gfxASurface::ImageFormatARGB32);
|
||||
if (img == nsnull)
|
||||
return nsnull;
|
||||
|
||||
nsRefPtr<gfxContext> ctx = new gfxContext(img);
|
||||
if (ctx == nsnull)
|
||||
return nsnull;
|
||||
|
||||
ctx->SetOperator(gfxContext::OPERATOR_CLEAR);
|
||||
ctx->Paint();
|
||||
|
||||
ctx->SetOperator(gfxContext::OPERATOR_OVER);
|
||||
rv = elt->RenderContexts(ctx);
|
||||
if (NS_FAILED(rv))
|
||||
return nsnull;
|
||||
|
||||
ctx = nsnull;
|
||||
|
||||
return img.forget();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDOMWindowUtils::CompareCanvases(nsIDOMHTMLCanvasElement *aCanvas1,
|
||||
nsIDOMHTMLCanvasElement *aCanvas2,
|
||||
PRUint32* aMaxDifference,
|
||||
PRUint32* retVal)
|
||||
{
|
||||
PRBool hasCap = PR_FALSE;
|
||||
if (NS_FAILED(nsContentUtils::GetSecurityManager()->IsCapabilityEnabled("UniversalXPConnect", &hasCap)) || !hasCap)
|
||||
return NS_ERROR_DOM_SECURITY_ERR;
|
||||
|
||||
if (aCanvas1 == nsnull ||
|
||||
aCanvas2 == nsnull ||
|
||||
retVal == nsnull)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
nsRefPtr<gfxImageSurface> img1 = CanvasToImageSurface(aCanvas1);
|
||||
nsRefPtr<gfxImageSurface> img2 = CanvasToImageSurface(aCanvas2);
|
||||
|
||||
if (img1 == nsnull || img2 == nsnull ||
|
||||
img1->GetSize() != img2->GetSize() ||
|
||||
img1->Stride() != img2->Stride())
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
int v;
|
||||
gfxIntSize size = img1->GetSize();
|
||||
PRUint32 stride = img1->Stride();
|
||||
|
||||
// we can optimize for the common all-pass case
|
||||
if (stride == (PRUint32) size.width * 4) {
|
||||
v = memcmp(img1->Data(), img2->Data(), size.width * size.height * 4);
|
||||
if (v == 0) {
|
||||
if (aMaxDifference)
|
||||
*aMaxDifference = 0;
|
||||
*retVal = 0;
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
PRUint32 dc = 0;
|
||||
PRUint32 different = 0;
|
||||
|
||||
for (int j = 0; j < size.height; j++) {
|
||||
unsigned char *p1 = img1->Data() + j*stride;
|
||||
unsigned char *p2 = img2->Data() + j*stride;
|
||||
v = memcmp(p1, p2, stride);
|
||||
|
||||
if (v) {
|
||||
for (int i = 0; i < size.width; i++) {
|
||||
if (*(PRUint32*) p1 != *(PRUint32*) p2) {
|
||||
|
||||
different++;
|
||||
|
||||
dc = PR_MAX(abs(p1[0] - p2[0]), dc);
|
||||
dc = PR_MAX(abs(p1[1] - p2[1]), dc);
|
||||
dc = PR_MAX(abs(p1[2] - p2[2]), dc);
|
||||
dc = PR_MAX(abs(p1[3] - p2[3]), dc);
|
||||
}
|
||||
|
||||
p1 += 4;
|
||||
p2 += 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (aMaxDifference)
|
||||
*aMaxDifference = dc;
|
||||
|
||||
*retVal = different;
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -44,65 +44,6 @@ include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
MODULE = reftest
|
||||
|
||||
ifdef DISABLED_SEE_BUG_387132
|
||||
|
||||
LIBRARY_NAME = reftest
|
||||
IS_COMPONENT = 1
|
||||
MODULE_NAME = nsReftestModule
|
||||
|
||||
REQUIRES = \
|
||||
xpcom \
|
||||
string \
|
||||
gfx \
|
||||
layout \
|
||||
widget \
|
||||
dom \
|
||||
js \
|
||||
locale \
|
||||
unicharutil \
|
||||
webshell \
|
||||
uriloader \
|
||||
htmlparser \
|
||||
necko \
|
||||
view \
|
||||
pref \
|
||||
docshell \
|
||||
xpconnect \
|
||||
xuldoc \
|
||||
caps \
|
||||
editor \
|
||||
imglib2 \
|
||||
mimetype \
|
||||
exthandler \
|
||||
uconv \
|
||||
intl \
|
||||
content \
|
||||
thebes \
|
||||
zlib \
|
||||
$(NULL)
|
||||
|
||||
ifndef MOZ_ENABLE_LIBXUL
|
||||
EXTRA_DSO_LIBS = thebes
|
||||
PLEASE_LINK_KTHX = $(XPCOM_GLUE_LDOPTS)
|
||||
else
|
||||
PLEASE_LINK_KTHX = $(DIST)/lib/$(LIB_PREFIX)xpcomglue_s.$(LIB_SUFFIX)
|
||||
endif
|
||||
|
||||
|
||||
EXTRA_DSO_LDOPTS = \
|
||||
$(LIBS_DIR) \
|
||||
$(EXTRA_DSO_LIBS) \
|
||||
$(MOZ_COMPONENT_LIBS) \
|
||||
$(PLEASE_LINK_KTHX) \
|
||||
$(ZLIB_LIBS) \
|
||||
$(NULL)
|
||||
|
||||
XPIDLSRCS = nsIReftestHelper.idl
|
||||
|
||||
CPPSRCS = nsReftestHelper.cpp
|
||||
|
||||
endif # DISABLED_SEE_BUG_387132
|
||||
|
||||
EXTRA_COMPONENTS= \
|
||||
reftest-cmdline.js \
|
||||
$(NULL)
|
||||
|
@ -1,54 +0,0 @@
|
||||
/* -*- Mode: idl; tab-width: 20; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is layout reftest.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla Corporation
|
||||
* Portions created by the Initial Developer are Copyright (C) 2007
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Vladimir Vukicevic <vladimir@pobox.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "nsISupports.idl"
|
||||
|
||||
interface nsIDOMHTMLCanvasElement;
|
||||
|
||||
[scriptable, uuid(25f2e32c-5d5d-4f5f-95e0-8fd3e2c9905b)]
|
||||
interface nsIReftestHelper : nsISupports {
|
||||
/*
|
||||
* Compare the two given canvas elements, and return the number of
|
||||
* pixels that differ.
|
||||
*
|
||||
* The given canvas elements must have the same dimensions, or an
|
||||
* exception will be thrown.
|
||||
*/
|
||||
unsigned long compareCanvas (in nsIDOMHTMLCanvasElement canvas1,
|
||||
in nsIDOMHTMLCanvasElement canvas2);
|
||||
};
|
@ -1,170 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is layout reftest.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla Corporation
|
||||
* Portions created by the Initial Developer are Copyright (C) 2007
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Vladimir Vukicevic <vladimir@pobox.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "nsIFactory.h"
|
||||
#include "nsIGenericFactory.h"
|
||||
#include "nsISupports.h"
|
||||
|
||||
#include "nsIDOMHTMLCanvasElement.h"
|
||||
#include "nsIDOMCanvasRenderingContext2D.h"
|
||||
#include "nsICanvasRenderingContextInternal.h"
|
||||
|
||||
#include "nsIReftestHelper.h"
|
||||
|
||||
#include "gfxContext.h"
|
||||
#include "gfxImageSurface.h"
|
||||
|
||||
#include "nsStringGlue.h"
|
||||
|
||||
class nsReftestHelper :
|
||||
public nsIReftestHelper
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIREFTESTHELPER
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS1(nsReftestHelper, nsIReftestHelper)
|
||||
|
||||
static already_AddRefed<gfxImageSurface>
|
||||
CanvasToImageSurface(nsIDOMHTMLCanvasElement *canvas)
|
||||
{
|
||||
PRUint32 w, h;
|
||||
nsresult rv;
|
||||
|
||||
nsCOMPtr<nsICanvasElement> elt = do_QueryInterface(canvas);
|
||||
rv = elt->GetSize(&w, &h);
|
||||
if (NS_FAILED(rv))
|
||||
return nsnull;
|
||||
|
||||
nsCOMPtr<nsISupports> ctxg;
|
||||
rv = canvas->GetContext(NS_LITERAL_STRING("2d"), getter_AddRefs(ctxg));
|
||||
if (NS_FAILED(rv))
|
||||
return nsnull;
|
||||
|
||||
nsCOMPtr<nsICanvasRenderingContextInternal> ctx = do_QueryInterface(ctxg);
|
||||
if (ctx == nsnull)
|
||||
return nsnull;
|
||||
|
||||
nsRefPtr<gfxImageSurface> img = new gfxImageSurface(gfxIntSize(w, h), gfxASurface::ImageFormatARGB32);
|
||||
if (img == nsnull)
|
||||
return nsnull;
|
||||
|
||||
nsRefPtr<gfxContext> t = new gfxContext(img);
|
||||
if (t == nsnull)
|
||||
return nsnull;
|
||||
|
||||
t->SetOperator(gfxContext::OPERATOR_CLEAR);
|
||||
t->Paint();
|
||||
|
||||
t->SetOperator(gfxContext::OPERATOR_OVER);
|
||||
rv = ctx->Render(t);
|
||||
if (NS_FAILED(rv))
|
||||
return nsnull;
|
||||
|
||||
NS_ADDREF(img.get());
|
||||
return img.get();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsReftestHelper::CompareCanvas(nsIDOMHTMLCanvasElement *canvas1,
|
||||
nsIDOMHTMLCanvasElement *canvas2,
|
||||
PRUint32 *result)
|
||||
{
|
||||
if (canvas1 == nsnull ||
|
||||
canvas2 == nsnull ||
|
||||
result == nsnull)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
nsRefPtr<gfxImageSurface> img1 = CanvasToImageSurface(canvas1);
|
||||
nsRefPtr<gfxImageSurface> img2 = CanvasToImageSurface(canvas2);
|
||||
|
||||
if (img1 == nsnull || img2 == nsnull ||
|
||||
img1->GetSize() != img2->GetSize() ||
|
||||
img1->Stride() != img2->Stride())
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
int v;
|
||||
gfxIntSize size = img1->GetSize();
|
||||
PRUint32 stride = img1->Stride();
|
||||
|
||||
// we can optimize for the common all-pass case
|
||||
if (stride == size.width * 4) {
|
||||
v = memcmp(img1->Data(), img2->Data(), size.width * size.height * 4);
|
||||
if (v == 0) {
|
||||
*result = 0;
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
PRUint32 different = 0;
|
||||
for (int j = 0; j < size.height; j++) {
|
||||
unsigned char *p1 = img1->Data() + j*stride;
|
||||
unsigned char *p2 = img2->Data() + j*stride;
|
||||
v = memcmp(p1, p2, stride);
|
||||
|
||||
if (v) {
|
||||
for (int i = 0; i < size.width; i++) {
|
||||
if (*(PRUint32*) p1 != *(PRUint32*) p2)
|
||||
different++;
|
||||
p1 += 4;
|
||||
p2 += 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*result = different;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(nsReftestHelper)
|
||||
|
||||
static const nsModuleComponentInfo components[] =
|
||||
{
|
||||
{ "nsReftestHelper",
|
||||
{ 0x0269F9AD, 0xA2BD, 0x4AEA,
|
||||
{ 0xB9, 0x2F, 0xCB, 0xF2, 0x23, 0x80, 0x94, 0x54 } },
|
||||
"@mozilla.org/reftest-helper;1",
|
||||
nsReftestHelperConstructor },
|
||||
};
|
||||
|
||||
NS_IMPL_NSGETMODULE(nsReftestModule, components)
|
||||
|
@ -81,7 +81,7 @@ var gServer;
|
||||
var gCount = 0;
|
||||
|
||||
var gIOService;
|
||||
var gReftestHelper;
|
||||
var gWindowUtils;
|
||||
|
||||
var gCurrentTestStartTime;
|
||||
var gSlowestTestTime = 0;
|
||||
@ -102,10 +102,12 @@ function OnRefTestLoad()
|
||||
|
||||
gBrowser.addEventListener("load", OnDocumentLoad, true);
|
||||
|
||||
try {
|
||||
gReftestHelper = CC[NS_REFTESTHELPER_CONTRACTID].getService(CI.nsIReftestHelper);
|
||||
try {
|
||||
gWindowUtils = window.QueryInterface(CI.nsIInterfaceRequestor).getInterface(CI.nsIDOMWindowUtils);
|
||||
if (gWindowUtils && !gWindowUtils.compareCanvases)
|
||||
gWindowUtils = null;
|
||||
} catch (e) {
|
||||
gReftestHelper = null;
|
||||
gWindowUtils = null;
|
||||
}
|
||||
|
||||
var windowElem = document.documentElement;
|
||||
@ -532,8 +534,8 @@ function DocumentLoaded()
|
||||
// whether the two renderings match:
|
||||
var equal;
|
||||
|
||||
if (gReftestHelper) {
|
||||
differences = gReftestHelper.compareCanvas(gCanvas1, gCanvas2);
|
||||
if (gWindowUtils) {
|
||||
differences = gWindowUtils.compareCanvases(gCanvas1, gCanvas2, {});
|
||||
equal = (differences == 0);
|
||||
} else {
|
||||
differences = -1;
|
||||
|
@ -1,13 +1,13 @@
|
||||
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
|
||||
|
||||
var gWindowSnapshotCompareHelper;
|
||||
var gWindowUtils;
|
||||
|
||||
try {
|
||||
gWindowSnapshotCompareHelper =
|
||||
Components.classes["@mozilla.org/reftest-helper;1"]
|
||||
.getService(Components.interfaces.nsIReftestHelper);
|
||||
gWindowUtils = window.QueryInterface(CI.nsIInterfaceRequestor).getInterface(CI.nsIDOMWindowUtils);
|
||||
if (gWindowUtils && !gWindowUtils.compareCanvases)
|
||||
gWindowUtils = null;
|
||||
} catch (e) {
|
||||
gWindowSnapshotCompareHelper = null;
|
||||
gWindowUtils = null;
|
||||
}
|
||||
|
||||
function snapshotWindow(win) {
|
||||
@ -17,7 +17,7 @@ function snapshotWindow(win) {
|
||||
|
||||
// drawWindow requires privileges
|
||||
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
|
||||
|
||||
|
||||
el.getContext("2d").drawWindow(win, win.scrollX, win.scrollY,
|
||||
win.innerWidth, win.innerHeight,
|
||||
"rgb(255,255,255)");
|
||||
@ -30,15 +30,15 @@ function compareSnapshots(s1, s2) {
|
||||
|
||||
var s1Str, s2Str;
|
||||
var equal = false;
|
||||
if (gWindowSnapshotCompareHelper) {
|
||||
equal = (gWindowSnapshotCompareHelper.compareCanvas(s1, s2) == 0);
|
||||
if (gWindowUtils) {
|
||||
equal = (gWindowUtils.compareCanvases(s1, s2, {}) == 0);
|
||||
}
|
||||
|
||||
if (!equal) {
|
||||
s1Str = s1.toDataURL();
|
||||
s2Str = s2.toDataURL();
|
||||
|
||||
if (!gWindowSnapshotCompareHelper) {
|
||||
if (!gWindowUtils) {
|
||||
equal = (s1Str == s2Str);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user