This commit is contained in:
Ryan VanderMeulen 2013-12-13 16:15:52 -05:00
Родитель 0a96ec2e55 3dadf354c0
Коммит 218cec4598
421 изменённых файлов: 8762 добавлений и 6247 удалений

Просмотреть файл

@ -18,4 +18,9 @@
# Modifying this file will now automatically clobber the buildbot machines \o/
#
Bug 887836 - webidl changes require a Windows clobber.
# Are you updating CLOBBER because you think it's needed for your WebIDL
# changes to stick? As of bug 928195, this shouldn't be necessary! Please
# don't change CLOBBER for WebIDL changes any more.
Bug 928195 rewrote WebIDL build system integration from the ground up. This
will hopefully be the last required clobber due to WebIDLs poorly interacting
with the build system.

Просмотреть файл

@ -548,14 +548,34 @@ HyperTextAccessible::DOMPointToHypertextOffset(nsINode* aNode,
return nullptr;
}
nsresult
HyperTextAccessible::HypertextOffsetsToDOMRange(int32_t aStartHTOffset,
int32_t aEndHTOffset,
nsRange* aRange)
bool
HyperTextAccessible::OffsetsToDOMRange(int32_t aStartOffset, int32_t aEndOffset,
nsRange* aRange)
{
// If the given offsets are 0 and associated editor is empty then return
// collapsed range with editor root element as range container.
if (aStartHTOffset == 0 && aEndHTOffset == 0) {
DOMPoint startPoint = OffsetToDOMPoint(aStartOffset);
if (!startPoint.node)
return false;
aRange->SetStart(startPoint.node, startPoint.idx);
if (aStartOffset == aEndOffset) {
aRange->SetEnd(startPoint.node, startPoint.idx);
return true;
}
DOMPoint endPoint = OffsetToDOMPoint(aEndOffset);
if (!endPoint.node)
return false;
aRange->SetEnd(endPoint.node, endPoint.idx);
return true;
}
DOMPoint
HyperTextAccessible::OffsetToDOMPoint(int32_t aOffset)
{
// 0 offset is valid even if no children. In this case the associated editor
// is empty so return a DOM point for editor root element.
if (aOffset == 0) {
nsCOMPtr<nsIEditor> editor = GetEditor();
if (editor) {
bool isEmpty = false;
@ -565,40 +585,36 @@ HyperTextAccessible::HypertextOffsetsToDOMRange(int32_t aStartHTOffset,
editor->GetRootElement(getter_AddRefs(editorRootElm));
nsCOMPtr<nsINode> editorRoot(do_QueryInterface(editorRootElm));
if (editorRoot) {
aRange->SetStart(editorRoot, 0);
aRange->SetEnd(editorRoot, 0);
return NS_OK;
}
return DOMPoint(editorRoot, 0);
}
}
}
nsRefPtr<Accessible> startAcc, endAcc;
int32_t startOffset = aStartHTOffset, endOffset = aEndHTOffset;
nsIFrame *startFrame = nullptr, *endFrame = nullptr;
int32_t childIdx = GetChildIndexAtOffset(aOffset);
if (childIdx == -1)
return DOMPoint();
startFrame = GetPosAndText(startOffset, endOffset, nullptr, &endFrame,
getter_AddRefs(startAcc), getter_AddRefs(endAcc));
if (!startAcc || !endAcc)
return NS_ERROR_FAILURE;
Accessible* child = GetChildAt(childIdx);
int32_t innerOffset = aOffset - GetChildOffset(childIdx);
DOMPoint startPoint, endPoint;
nsresult rv = GetDOMPointByFrameOffset(startFrame, startOffset, startAcc,
&startPoint);
NS_ENSURE_SUCCESS(rv, rv);
// A text leaf case. The point is inside the text node.
if (child->IsTextLeaf()) {
nsIContent* content = child->GetContent();
int32_t idx = 0;
if (NS_FAILED(RenderedToContentOffset(content->GetPrimaryFrame(),
innerOffset, &idx)))
return DOMPoint();
rv = aRange->SetStart(startPoint.node, startPoint.idx);
NS_ENSURE_SUCCESS(rv, rv);
return DOMPoint(content, idx);
}
if (aStartHTOffset == aEndHTOffset)
return aRange->SetEnd(startPoint.node, startPoint.idx);
rv = GetDOMPointByFrameOffset(endFrame, endOffset, endAcc, &endPoint);
NS_ENSURE_SUCCESS(rv, rv);
return aRange->SetEnd(endPoint.node, endPoint.idx);
// Case of embedded object. The point is either before or after the element.
NS_ASSERTION(innerOffset == 0 || innerOffset == 1, "A wrong inner offset!");
nsINode* node = child->GetNode();
nsINode* parentNode = node->GetParentNode();
return parentNode ?
DOMPoint(parentNode, parentNode->IndexOf(node) + innerOffset) :
DOMPoint();
}
int32_t
@ -1580,7 +1596,8 @@ HyperTextAccessible::SetSelectionBoundsAt(int32_t aSelectionNum,
if (!range)
return false;
HypertextOffsetsToDOMRange(startOffset, endOffset, range);
if (!OffsetsToDOMRange(startOffset, endOffset, range))
return false;
// If new range was created then add it, otherwise notify selection listeners
// that existing selection range was changed.
@ -1610,8 +1627,7 @@ HyperTextAccessible::ScrollSubstringTo(int32_t aStartOffset, int32_t aEndOffset,
uint32_t aScrollType)
{
nsRefPtr<nsRange> range = new nsRange(mContent);
nsresult rv = HypertextOffsetsToDOMRange(aStartOffset, aEndOffset, range);
if (NS_SUCCEEDED(rv))
if (OffsetsToDOMRange(aStartOffset, aEndOffset, range))
nsCoreUtils::ScrollSubstringTo(GetFrame(), range, aScrollType);
}
@ -1629,8 +1645,7 @@ HyperTextAccessible::ScrollSubstringToPoint(int32_t aStartOffset,
this);
nsRefPtr<nsRange> range = new nsRange(mContent);
nsresult rv = HypertextOffsetsToDOMRange(aStartOffset, aEndOffset, range);
if (NS_FAILED(rv))
if (!OffsetsToDOMRange(aStartOffset, aEndOffset, range))
return;
nsPresContext* presContext = frame->PresContext();
@ -1658,7 +1673,7 @@ HyperTextAccessible::ScrollSubstringToPoint(int32_t aStartOffset,
int16_t hPercent = offsetPointX * 100 / size.width;
int16_t vPercent = offsetPointY * 100 / size.height;
rv = nsCoreUtils::ScrollSubstringTo(frame, range, vPercent, hPercent);
nsresult rv = nsCoreUtils::ScrollSubstringTo(frame, range, vPercent, hPercent);
if (NS_FAILED(rv))
return;

Просмотреть файл

@ -17,6 +17,9 @@ namespace mozilla {
namespace a11y {
struct DOMPoint {
DOMPoint() : node(nullptr), idx(0) { }
DOMPoint(nsINode* aNode, int32_t aIdx) : node(aNode), idx(aIdx) { }
nsINode* node;
int32_t idx;
};
@ -128,15 +131,24 @@ public:
bool aIsEndOffset = false) const;
/**
* Turn a start and end hypertext offsets into DOM range.
* Convert start and end hypertext offsets into DOM range.
*
* @param aStartHTOffset [in] the given start hypertext offset
* @param aEndHTOffset [in] the given end hypertext offset
* @param aRange [out] the range whose bounds to set
* @param aStartOffset [in] the given start hypertext offset
* @param aEndOffset [in] the given end hypertext offset
* @param aRange [in, out] the range whose bounds to set
* @return true if conversion was successful
*/
nsresult HypertextOffsetsToDOMRange(int32_t aStartHTOffset,
int32_t aEndHTOffset,
nsRange* aRange);
bool OffsetsToDOMRange(int32_t aStartOffset, int32_t aEndOffset,
nsRange* aRange);
/**
* Convert the given offset into DOM point.
*
* If offset is at text leaf then DOM point is (text node, offsetInTextNode),
* if before embedded object then (parent node, indexInParent), if after then
* (parent node, indexInParent + 1).
*/
DOMPoint OffsetToDOMPoint(int32_t aOffset);
/**
* Return true if the used ARIA role (if any) allows the hypertext accessible

Просмотреть файл

@ -118,8 +118,8 @@ this.AccessFu = {
Output.start();
TouchAdapter.start();
Services.obs.addObserver(this, 'remote-browser-frame-shown', false);
Services.obs.addObserver(this, 'in-process-browser-or-app-frame-shown', false);
Services.obs.addObserver(this, 'remote-browser-shown', false);
Services.obs.addObserver(this, 'inprocess-browser-shown', false);
Services.obs.addObserver(this, 'Accessibility:NextObject', false);
Services.obs.addObserver(this, 'Accessibility:PreviousObject', false);
Services.obs.addObserver(this, 'Accessibility:Focus', false);
@ -162,8 +162,8 @@ this.AccessFu = {
Utils.win.removeEventListener('TabClose', this);
Utils.win.removeEventListener('TabSelect', this);
Services.obs.removeObserver(this, 'remote-browser-frame-shown');
Services.obs.removeObserver(this, 'in-process-browser-or-app-frame-shown');
Services.obs.removeObserver(this, 'remote-browser-shown');
Services.obs.removeObserver(this, 'inprocess-browser-shown');
Services.obs.removeObserver(this, 'Accessibility:NextObject');
Services.obs.removeObserver(this, 'Accessibility:PreviousObject');
Services.obs.removeObserver(this, 'Accessibility:Focus');
@ -304,11 +304,15 @@ this.AccessFu = {
case 'Accessibility:MoveByGranularity':
this.Input.moveByGranularity(JSON.parse(aData));
break;
case 'remote-browser-frame-shown':
case 'in-process-browser-or-app-frame-shown':
case 'remote-browser-shown':
case 'inprocess-browser-shown':
{
let mm = aSubject.QueryInterface(Ci.nsIFrameLoader).messageManager;
this._handleMessageManager(mm);
// Ignore notifications that aren't from a BrowserOrApp
let frameLoader = aSubject.QueryInterface(Ci.nsIFrameLoader);
if (!frameLoader.ownerIsBrowserOrAppFrame) {
return;
}
this._handleMessageManager(frameLoader.messageManager);
break;
}
}

Просмотреть файл

@ -150,12 +150,16 @@ let ErrorPage = {
},
init: function errorPageInit() {
Services.obs.addObserver(this, 'in-process-browser-or-app-frame-shown', false);
Services.obs.addObserver(this, 'remote-browser-frame-shown', false);
Services.obs.addObserver(this, 'inprocess-browser-shown', false);
Services.obs.addObserver(this, 'remote-browser-shown', false);
},
observe: function errorPageObserve(aSubject, aTopic, aData) {
let frameLoader = aSubject.QueryInterface(Ci.nsIFrameLoader);
// Ignore notifications that aren't from a BrowserOrApp
if (!frameLoader.ownerIsBrowserOrAppFrame) {
return;
}
let mm = frameLoader.messageManager;
// This won't happen from dom/ipc/preload.js in non-OOP builds.

Просмотреть файл

@ -752,10 +752,9 @@ WriteBitmap(nsIFile* aFile, imgIContainer* aImage)
{
nsresult rv;
nsRefPtr<gfxASurface> surface;
aImage->GetFrame(imgIContainer::FRAME_FIRST,
imgIContainer::FLAG_SYNC_DECODE,
getter_AddRefs(surface));
nsRefPtr<gfxASurface> surface =
aImage->GetFrame(imgIContainer::FRAME_FIRST,
imgIContainer::FLAG_SYNC_DECODE);
NS_ENSURE_TRUE(surface, NS_ERROR_FAILURE);
nsRefPtr<gfxImageSurface> image(surface->GetAsReadableARGB32ImageSurface());

Просмотреть файл

@ -14,13 +14,13 @@ function test() {
let events = win.EVENTS;
let variables = win.DebuggerView.Variables;
// Allow this generator function to yield first.
executeSoon(() => debuggee.test());
yield waitForSourceAndCaretAndScopes(panel, ".html", 23);
// Wait for the hierarchy to be committed by the VariablesViewController.
let committed = promise.defer();
variables.oncommit = committed.resolve;
// Allow this generator function to yield first.
executeSoon(() => debuggee.test());
yield waitForSourceAndCaretAndScopes(panel, ".html", 23);
yield committed.promise;
let firstScope = variables.getScopeAtIndex(0);

Просмотреть файл

@ -13,6 +13,8 @@ mock.pth:python/mock-1.0.0
mozilla.pth:build
mozilla.pth:config
mozilla.pth:xpcom/typelib/xpt/tools
mozilla.pth:dom/bindings
mozilla.pth:dom/bindings/parser
moztreedocs.pth:tools/docs
copy:build/buildconfig.py
packages.txt:testing/mozbase/packages.txt

Просмотреть файл

@ -111,7 +111,7 @@ interface nsIContentViewManager : nsISupports
readonly attribute nsIContentView rootContentView;
};
[scriptable, builtinclass, uuid(5b9949dc-56f1-47b6-b6d2-3785bb90ed6d)]
[scriptable, builtinclass, uuid(a723673b-a26e-4cc6-ae23-ec70df9d97c9)]
interface nsIFrameLoader : nsISupports
{
/**
@ -272,6 +272,11 @@ interface nsIFrameLoader : nsISupports
* have a notion of visibility in the parent process when frames are OOP.
*/
[infallible] attribute boolean visible;
/**
* Find out whether the owner content really is a browser or app frame
*/
readonly attribute boolean ownerIsBrowserOrAppFrame;
};
%{C++

Просмотреть файл

@ -948,9 +948,9 @@ nsFrameLoader::ShowRemoteFrame(const nsIntSize& size,
EnsureMessageManager();
nsCOMPtr<nsIObserverService> os = services::GetObserverService();
if (OwnerIsBrowserOrAppFrame() && os && !mRemoteBrowserInitialized) {
if (os && !mRemoteBrowserInitialized) {
os->NotifyObservers(NS_ISUPPORTS_CAST(nsIFrameLoader*, this),
"remote-browser-frame-shown", nullptr);
"remote-browser-shown", nullptr);
mRemoteBrowserInitialized = true;
}
} else {
@ -1409,6 +1409,14 @@ nsFrameLoader::OwnerIsBrowserOrAppFrame()
return browserFrame ? browserFrame->GetReallyIsBrowserOrApp() : false;
}
// The xpcom getter version
NS_IMETHODIMP
nsFrameLoader::GetOwnerIsBrowserOrAppFrame(bool* aResult)
{
*aResult = OwnerIsBrowserOrAppFrame();
return NS_OK;
}
bool
nsFrameLoader::OwnerIsAppFrame()
{
@ -1677,18 +1685,16 @@ nsFrameLoader::MaybeCreateDocShell()
mDocShell->SetIsBrowserInsideApp(containingAppId);
}
if (OwnerIsBrowserOrAppFrame()) {
nsCOMPtr<nsIObserverService> os = services::GetObserverService();
if (os) {
os->NotifyObservers(NS_ISUPPORTS_CAST(nsIFrameLoader*, this),
"in-process-browser-or-app-frame-shown", nullptr);
}
nsCOMPtr<nsIObserverService> os = services::GetObserverService();
if (os) {
os->NotifyObservers(NS_ISUPPORTS_CAST(nsIFrameLoader*, this),
"inprocess-browser-shown", nullptr);
}
if (mMessageManager) {
mMessageManager->LoadFrameScript(
NS_LITERAL_STRING("chrome://global/content/BrowserElementChild.js"),
/* allowDelayedLoad = */ true);
}
if (OwnerIsBrowserOrAppFrame() && mMessageManager) {
mMessageManager->LoadFrameScript(
NS_LITERAL_STRING("chrome://global/content/BrowserElementChild.js"),
/* allowDelayedLoad = */ true);
}
return NS_OK;

Просмотреть файл

@ -1471,13 +1471,6 @@ GK_ATOM(restart, "restart")
GK_ATOM(to, "to")
GK_ATOM(XML, "XML")
// internal MathML attributes: different from columnalign_, columnlines_,
// rowalign_ and rowlines_
GK_ATOM(_moz_math_columnalign_, "_moz-math-columnalign")
GK_ATOM(_moz_math_columnline_, "_moz-math-columnline")
GK_ATOM(_moz_math_rowalign_, "_moz-math-rowalign")
GK_ATOM(_moz_math_rowline_, "_moz-math-rowline")
GK_ATOM(abs_, "abs")
GK_ATOM(accent_, "accent")
GK_ATOM(accentunder_, "accentunder")

Просмотреть файл

@ -789,8 +789,11 @@ nsScriptLoader::AttemptAsyncScriptParse(nsScriptLoadRequest* aRequest)
if (!context) {
return NS_ERROR_FAILURE;
}
AutoPushJSContext cx(context->GetNativeContext());
JS::Rooted<JSObject*> global(cx, unrootedGlobal);
JSContext* unpushedCx = context->GetNativeContext();
JSAutoRequest ar(unpushedCx);
JS::Rooted<JSObject*> global(unpushedCx, unrootedGlobal);
AutoPushJSContext cx(unpushedCx);
JS::CompileOptions options(cx);
FillCompileOptionsForRequest(aRequest, global, &options);
@ -1002,8 +1005,11 @@ nsScriptLoader::EvaluateScript(nsScriptLoadRequest* aRequest,
if (!context) {
return NS_ERROR_FAILURE;
}
AutoPushJSContext cx(context->GetNativeContext());
JS::Rooted<JSObject*> global(cx, unrootedGlobal);
JSContext* unpushedCx = context->GetNativeContext();
JSAutoRequest ar(unpushedCx);
JS::Rooted<JSObject*> global(unpushedCx, unrootedGlobal);
AutoPushJSContext cx(unpushedCx);
bool oldProcessingScriptTag = context->GetProcessingScriptTag();
context->SetProcessingScriptTag(true);

Просмотреть файл

@ -1890,7 +1890,7 @@ CanvasRenderingContext2D::Arc(double x, double y, double r,
EnsureWritablePath();
ArcToBezier(this, Point(x, y), r, startAngle, endAngle, anticlockwise);
ArcToBezier(this, Point(x, y), Size(r, r), startAngle, endAngle, anticlockwise);
}
void

Просмотреть файл

@ -1347,7 +1347,9 @@ nsEventListenerManager::GetScriptGlobalAndDocument(nsIDocument** aDoc)
// XXX sXBL/XBL2 issue -- do we really want the owner here? What
// if that's the XBL document?
doc = node->OwnerDoc();
MOZ_ASSERT(!doc->IsLoadedAsData(), "Should not get in here at all");
if (doc->IsLoadedAsData()) {
return nullptr;
}
// We want to allow compiling an event handler even in an unloaded
// document, so use GetScopeObject here, not GetScriptHandlingObject.

Просмотреть файл

@ -84,6 +84,7 @@ skip-if = true # Disabled due to timeouts.
[test_bug855741.html]
[test_bug864040.html]
[test_bug930374-content.html]
[test_bug944847.html]
skip-if = toolkit == "gonk"
[test_clickevent_on_input.html]
[test_continuous_wheel_events.html]

Просмотреть файл

@ -0,0 +1,42 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=944847
-->
<head>
<meta charset="utf-8">
<title>Test for Bug 944847</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<script type="application/javascript">
/** Test for Bug 944847 **/
var e1 = document.createElement("div");
is(e1.onclick, null);
e1.setAttribute("onclick", "");
isnot(e1.onclick, null);
var e2 = document.implementation.createHTMLDocument(null, null).createElement("div");
is(e2.onclick, null);
e2.setAttribute("onclick", "");
is(e2.onclick, null);
var e3 = document.createElement("div");
is(e3.onclick, null);
e3.setAttribute("onclick", "");
e2.ownerDocument.adoptNode(e3);
is(e3.onclick, null);
</script>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=944847">Mozilla Bug 944847</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
</pre>
</body>
</html>

Просмотреть файл

@ -40,7 +40,7 @@ void VideoFrameContainer::SetCurrentFrame(const gfxIntSize& aIntrinsicSize,
mIntrinsicSizeChanged = true;
}
gfxIntSize oldFrameSize = mImageContainer->GetCurrentSize();
gfx::IntSize oldFrameSize = mImageContainer->GetCurrentSize();
TimeStamp lastPaintTime = mImageContainer->GetPaintTime();
if (!lastPaintTime.IsNull() && !mPaintTarget.IsNull()) {
mPaintDelay = lastPaintTime - mPaintTarget;
@ -57,7 +57,7 @@ void VideoFrameContainer::SetCurrentFrame(const gfxIntSize& aIntrinsicSize,
mImageContainer->UnlockCurrentImage();
mImageContainer->SetCurrentImage(aImage);
gfxIntSize newFrameSize = mImageContainer->GetCurrentSize();
gfx::IntSize newFrameSize = mImageContainer->GetCurrentSize();
if (oldFrameSize != newFrameSize) {
mImageSizeChanged = true;
}

Просмотреть файл

@ -147,7 +147,7 @@ VideoTrackEncoder::NotifyQueuedTrackChanges(MediaStreamGraph* aGraph,
while (!iter.IsEnded()) {
VideoChunk chunk = *iter;
if (!chunk.IsNull()) {
gfxIntSize imgsize = chunk.mFrame.GetImage()->GetSize();
gfx::IntSize imgsize = chunk.mFrame.GetImage()->GetSize();
nsresult rv = Init(imgsize.width, imgsize.height, aTrackRate);
if (NS_FAILED(rv)) {
LOG("[VideoTrackEncoder]: Fail to initialize the encoder!");

Просмотреть файл

@ -6,6 +6,7 @@
#include "MediaPluginReader.h"
#include "mozilla/TimeStamp.h"
#include "mozilla/dom/TimeRanges.h"
#include "mozilla/gfx/Point.h"
#include "MediaResource.h"
#include "VideoUtils.h"
#include "MediaPluginDecoder.h"
@ -172,7 +173,7 @@ bool MediaPluginReader::DecodeVideoFrame(bool &aKeyframeSkip,
nsAutoPtr<VideoData> v;
if (currentImage) {
gfxIntSize frameSize = currentImage->GetSize();
gfx::IntSize frameSize = currentImage->GetSize();
if (frameSize.width != mInitialFrame.width ||
frameSize.height != mInitialFrame.height) {
// Frame size is different from what the container reports. This is legal,

Просмотреть файл

@ -174,8 +174,8 @@ AudioContext::CreateBuffer(JSContext* aJSContext, uint32_t aNumberOfChannels,
uint32_t aLength, float aSampleRate,
ErrorResult& aRv)
{
if (aSampleRate < 8000 || aSampleRate > 96000 || !aLength) {
aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
if (aSampleRate < 8000 || aSampleRate > 192000 || !aLength || !aNumberOfChannels) {
aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
return nullptr;
}

Просмотреть файл

@ -81,15 +81,21 @@ addLoadEvent(function() {
expectException(function() {
context.createBuffer(2, 2048, 7999);
}, DOMException.NOT_SUPPORTED_ERR);
}, DOMException.INDEX_SIZE_ERR);
expectException(function() {
context.createBuffer(2, 2048, 96001);
}, DOMException.NOT_SUPPORTED_ERR);
context.createBuffer(2, 2048, 192001);
}, DOMException.INDEX_SIZE_ERR);
context.createBuffer(2, 2048, 8000); // no exception
context.createBuffer(2, 2048, 96000); // no exception
context.createBuffer(2, 2048, 192000); // no exception
context.createBuffer(32, 2048, 48000); // no exception
// Null length
expectException(function() {
context.createBuffer(2, 0, 48000);
}, DOMException.NOT_SUPPORTED_ERR);
}, DOMException.INDEX_SIZE_ERR);
// Null number of channels
expectException(function() {
context.createBuffer(0, 2048, 48000);
}, DOMException.INDEX_SIZE_ERR);
SimpleTest.finish();
});

Просмотреть файл

@ -21,8 +21,6 @@ var gTest = {
var source = context.createBufferSource();
source.buffer = buffer;
var sp = context.createScriptProcessor(2048 * 4, 1);
source.start(0);
source.loop = true;
source.loopStart = buffer.duration * 0.25;

Просмотреть файл

@ -9,9 +9,12 @@
<pre id="test">
<script class="testbody" type="text/javascript">
var ctx = new AudioContext();
ctx.createBuffer(0, 1, ctx.sampleRate);
ok(true, "The test should not crash during CC");
try {
var ctx = new AudioContext();
ctx.createBuffer(0, 1, ctx.sampleRate);
} catch (e) {
ok(true, "The test should not crash during CC");
}
</script>
</pre>

Просмотреть файл

@ -6,6 +6,7 @@
#include "nsPresContext.h"
#include "gfxImageSurface.h"
#include "gfxContext.h"
#include "gfx2DGlue.h"
#include "ImageContainer.h"
#include "Layers.h"
#include "nsIInterfaceRequestorUtils.h"
@ -154,8 +155,8 @@ NotifyPull(MediaStreamGraph*, SourceMediaStream* aSource, mozilla::TrackID aID,
if (delta > 0) {
// nullptr images are allowed
if (image) {
gfxIntSize size = image->GetSize();
segment.AppendFrame(image.forget(), delta, size);
gfx::IntSize size = image->GetSize();
segment.AppendFrame(image.forget(), delta, gfx::ThebesIntSize(size));
} else {
segment.AppendFrame(nullptr, delta, gfxIntSize(0,0));
}

Просмотреть файл

@ -164,6 +164,15 @@ public:
return (mIsActive || mIsFrozen);
}
/**
* Indicates if the animation is active.
*
* @return true if the animation is active, false otherwise.
*/
bool IsActive() const {
return mIsActive;
}
/**
* Indicates if this animation will replace the passed in result rather than
* adding to it. Animations that replace the underlying value may be called

Просмотреть файл

@ -27,7 +27,11 @@ public:
explicit nsSMILRepeatCount(double aCount)
: mCount(kNotSet) { SetCount(aCount); }
operator double() const { return mCount; }
operator double() const {
MOZ_ASSERT(IsDefinite(),
"Converting indefinite or unset repeat count to double");
return mCount;
}
bool IsDefinite() const {
return mCount != kNotSet && mCount != kIndefinite;
}

Просмотреть файл

@ -112,8 +112,9 @@ namespace
//----------------------------------------------------------------------
// Helper class: AutoIntervalUpdateBatcher
// RAII helper to set the mDeferIntervalUpdates flag on an nsSMILTimedElement
// and perform the UpdateCurrentInterval when the object is destroyed.
// Stack-based helper class to set the mDeferIntervalUpdates flag on an
// nsSMILTimedElement and perform the UpdateCurrentInterval when the object is
// destroyed.
//
// If several of these objects are allocated on the stack, the update will not
// be performed until the last object for a given nsSMILTimedElement is
@ -146,6 +147,31 @@ private:
bool mDidSetFlag;
};
//----------------------------------------------------------------------
// Helper class: AutoIntervalUpdater
// Stack-based helper class to call UpdateCurrentInterval when it is destroyed
// which helps avoid bugs where we forget to call UpdateCurrentInterval in the
// case of early returns (e.g. due to parse errors).
//
// This can be safely used in conjunction with AutoIntervalUpdateBatcher; any
// calls to UpdateCurrentInterval made by this class will simply be deferred if
// there is an AutoIntervalUpdateBatcher on the stack.
class MOZ_STACK_CLASS nsSMILTimedElement::AutoIntervalUpdater
{
public:
AutoIntervalUpdater(nsSMILTimedElement& aTimedElement)
: mTimedElement(aTimedElement) { }
~AutoIntervalUpdater()
{
mTimedElement.UpdateCurrentInterval();
}
private:
nsSMILTimedElement& mTimedElement;
};
//----------------------------------------------------------------------
// Templated helper functions
@ -667,19 +693,32 @@ nsSMILTimedElement::DoSampleAt(nsSMILTime aContainerTime, bool aEndOnly)
NS_ASSERTION(aContainerTime >= beginTime,
"Sample time should not precede current interval");
nsSMILTime activeTime = aContainerTime - beginTime;
SampleSimpleTime(activeTime);
// We register our repeat times as milestones (except when we're
// seeking) so we should get a sample at exactly the time we repeat.
// (And even when we are seeking we want to update
// mCurrentRepeatIteration so we do that first before testing the seek
// state.)
uint32_t prevRepeatIteration = mCurrentRepeatIteration;
if (ActiveTimeToSimpleTime(activeTime, mCurrentRepeatIteration)==0 &&
// The 'min' attribute can cause the active interval to be longer than
// the 'repeating interval'.
// In that extended period we apply the fill mode.
if (GetRepeatDuration() <= nsSMILTimeValue(activeTime)) {
if (mClient && mClient->IsActive()) {
mClient->Inactivate(mFillMode == FILL_FREEZE);
}
SampleFillValue();
} else {
SampleSimpleTime(activeTime);
// We register our repeat times as milestones (except when we're
// seeking) so we should get a sample at exactly the time we repeat.
// (And even when we are seeking we want to update
// mCurrentRepeatIteration so we do that first before testing the
// seek state.)
uint32_t prevRepeatIteration = mCurrentRepeatIteration;
if (
ActiveTimeToSimpleTime(activeTime, mCurrentRepeatIteration)==0 &&
mCurrentRepeatIteration != prevRepeatIteration &&
mCurrentRepeatIteration &&
mSeekState == SEEK_NOT_SEEKING) {
FireTimeEventAsync(NS_SMIL_REPEAT,
static_cast<int32_t>(mCurrentRepeatIteration));
FireTimeEventAsync(NS_SMIL_REPEAT,
static_cast<int32_t>(mCurrentRepeatIteration));
}
}
}
}
@ -905,8 +944,10 @@ nsSMILTimedElement::UnsetEndSpec(RemovalTestFunction aRemove)
nsresult
nsSMILTimedElement::SetSimpleDuration(const nsAString& aDurSpec)
{
nsSMILTimeValue duration;
// Update the current interval before returning
AutoIntervalUpdater updater(*this);
nsSMILTimeValue duration;
const nsAString& dur = nsSMILParserUtils::TrimWhitespace(aDurSpec);
// SVG-specific: "For SVG's animation elements, if "media" is specified, the
@ -926,7 +967,6 @@ nsSMILTimedElement::SetSimpleDuration(const nsAString& aDurSpec)
"Setting unresolved simple duration");
mSimpleDur = duration;
UpdateCurrentInterval();
return NS_OK;
}
@ -941,8 +981,10 @@ nsSMILTimedElement::UnsetSimpleDuration()
nsresult
nsSMILTimedElement::SetMin(const nsAString& aMinSpec)
{
nsSMILTimeValue duration;
// Update the current interval before returning
AutoIntervalUpdater updater(*this);
nsSMILTimeValue duration;
const nsAString& min = nsSMILParserUtils::TrimWhitespace(aMinSpec);
if (min.EqualsLiteral("media")) {
@ -957,7 +999,6 @@ nsSMILTimedElement::SetMin(const nsAString& aMinSpec)
NS_ABORT_IF_FALSE(duration.GetMillis() >= 0L, "Invalid duration");
mMin = duration;
UpdateCurrentInterval();
return NS_OK;
}
@ -972,8 +1013,10 @@ nsSMILTimedElement::UnsetMin()
nsresult
nsSMILTimedElement::SetMax(const nsAString& aMaxSpec)
{
nsSMILTimeValue duration;
// Update the current interval before returning
AutoIntervalUpdater updater(*this);
nsSMILTimeValue duration;
const nsAString& max = nsSMILParserUtils::TrimWhitespace(aMaxSpec);
if (max.EqualsLiteral("media") || max.EqualsLiteral("indefinite")) {
@ -988,7 +1031,6 @@ nsSMILTimedElement::SetMax(const nsAString& aMaxSpec)
}
mMax = duration;
UpdateCurrentInterval();
return NS_OK;
}
@ -1023,15 +1065,16 @@ nsSMILTimedElement::UnsetRestart()
nsresult
nsSMILTimedElement::SetRepeatCount(const nsAString& aRepeatCountSpec)
{
// Update the current interval before returning
AutoIntervalUpdater updater(*this);
nsSMILRepeatCount newRepeatCount;
if (nsSMILParserUtils::ParseRepeatCount(aRepeatCountSpec, newRepeatCount)) {
mRepeatCount = newRepeatCount;
UpdateCurrentInterval();
return NS_OK;
}
mRepeatCount.Unset();
UpdateCurrentInterval();
return NS_ERROR_FAILURE;
}
@ -1045,6 +1088,9 @@ nsSMILTimedElement::UnsetRepeatCount()
nsresult
nsSMILTimedElement::SetRepeatDur(const nsAString& aRepeatDurSpec)
{
// Update the current interval before returning
AutoIntervalUpdater updater(*this);
nsSMILTimeValue duration;
const nsAString& repeatDur =
@ -1060,7 +1106,6 @@ nsSMILTimedElement::SetRepeatDur(const nsAString& aRepeatDurSpec)
}
mRepeatDur = duration;
UpdateCurrentInterval();
return NS_OK;
}
@ -1084,12 +1129,8 @@ nsSMILTimedElement::SetFillMode(const nsAString& aFillModeSpec)
? nsSMILFillMode(temp.GetEnumValue())
: FILL_REMOVE;
// Check if we're in a fill-able state: i.e. we've played at least one
// interval and are now between intervals or at the end of all intervals
bool isFillable = HasPlayed() &&
(mElementState == STATE_WAITING || mElementState == STATE_POSTACTIVE);
if (mClient && mFillMode != previousFillMode && isFillable) {
// Update fill mode of client
if (mFillMode != previousFillMode && HasClientInFillRange()) {
mClient->Inactivate(mFillMode == FILL_FREEZE);
SampleFillValue();
}
@ -1102,9 +1143,9 @@ nsSMILTimedElement::UnsetFillMode()
{
uint16_t previousFillMode = mFillMode;
mFillMode = FILL_REMOVE;
if ((mElementState == STATE_WAITING || mElementState == STATE_POSTACTIVE) &&
previousFillMode == FILL_FREEZE && mClient && HasPlayed())
if (previousFillMode == FILL_FREEZE && HasClientInFillRange()) {
mClient->Inactivate(false);
}
}
void
@ -1803,11 +1844,7 @@ nsSMILTimedElement::CalcActiveEnd(const nsSMILTimeValue& aBegin,
NS_ABORT_IF_FALSE(aBegin.IsDefinite(),
"Indefinite or unresolved begin time in CalcActiveEnd");
if (mRepeatDur.IsIndefinite()) {
result.SetIndefinite();
} else {
result = GetRepeatDuration();
}
result = GetRepeatDuration();
if (aEnd.IsDefinite()) {
nsSMILTime activeDur = aEnd.GetMillis() - aBegin.GetMillis();
@ -1832,29 +1869,25 @@ nsSMILTimedElement::CalcActiveEnd(const nsSMILTimeValue& aBegin,
nsSMILTimeValue
nsSMILTimedElement::GetRepeatDuration() const
{
nsSMILTimeValue result;
if (mRepeatCount.IsDefinite() && mRepeatDur.IsDefinite()) {
if (mSimpleDur.IsDefinite()) {
nsSMILTime activeDur =
nsSMILTime(mRepeatCount * double(mSimpleDur.GetMillis()));
result.SetMillis(std::min(activeDur, mRepeatDur.GetMillis()));
} else {
result = mRepeatDur;
}
} else if (mRepeatCount.IsDefinite() && mSimpleDur.IsDefinite()) {
nsSMILTime activeDur =
nsSMILTime(mRepeatCount * double(mSimpleDur.GetMillis()));
result.SetMillis(activeDur);
} else if (mRepeatDur.IsDefinite()) {
result = mRepeatDur;
} else if (mRepeatCount.IsIndefinite()) {
result.SetIndefinite();
nsSMILTimeValue multipliedDuration;
if (mRepeatCount.IsDefinite() && mSimpleDur.IsDefinite()) {
multipliedDuration.SetMillis(
nsSMILTime(mRepeatCount * double(mSimpleDur.GetMillis())));
} else {
result = mSimpleDur;
multipliedDuration.SetIndefinite();
}
return result;
nsSMILTimeValue repeatDuration;
if (mRepeatDur.IsResolved()) {
repeatDuration = std::min(multipliedDuration, mRepeatDur);
} else if (mRepeatCount.IsSet()) {
repeatDuration = multipliedDuration;
} else {
repeatDuration = mSimpleDur;
}
return repeatDuration;
}
nsSMILTimeValue
@ -1873,8 +1906,7 @@ nsSMILTimedElement::ApplyMinAndMax(const nsSMILTimeValue& aDuration) const
if (aDuration > mMax) {
result = mMax;
} else if (aDuration < mMin) {
nsSMILTimeValue repeatDur = GetRepeatDuration();
result = mMin > repeatDur ? repeatDur : mMin;
result = mMin;
} else {
result = aDuration;
}
@ -2068,16 +2100,35 @@ nsSMILTimedElement::SampleFillValue()
if (mFillMode != FILL_FREEZE || !mClient)
return;
const nsSMILInterval* prevInterval = GetPreviousInterval();
NS_ABORT_IF_FALSE(prevInterval,
"Attempting to sample fill value but there is no previous interval");
NS_ABORT_IF_FALSE(prevInterval->End()->Time().IsDefinite() &&
prevInterval->End()->IsFixedTime(),
"Attempting to sample fill value but the endpoint of the previous "
"interval is not resolved and fixed");
nsSMILTime activeTime;
nsSMILTime activeTime = prevInterval->End()->Time().GetMillis() -
prevInterval->Begin()->Time().GetMillis();
if (mElementState == STATE_WAITING || mElementState == STATE_POSTACTIVE) {
const nsSMILInterval* prevInterval = GetPreviousInterval();
NS_ABORT_IF_FALSE(prevInterval,
"Attempting to sample fill value but there is no previous interval");
NS_ABORT_IF_FALSE(prevInterval->End()->Time().IsDefinite() &&
prevInterval->End()->IsFixedTime(),
"Attempting to sample fill value but the endpoint of the previous "
"interval is not resolved and fixed");
activeTime = prevInterval->End()->Time().GetMillis() -
prevInterval->Begin()->Time().GetMillis();
// If the interval's repeat duration was shorter than its active duration,
// use the end of the repeat duration to determine the frozen animation's
// state.
nsSMILTimeValue repeatDuration = GetRepeatDuration();
if (repeatDuration.IsDefinite()) {
activeTime = std::min(repeatDuration.GetMillis(), activeTime);
}
} else if (mElementState == STATE_ACTIVE) {
// If we are being asked to sample the fill value while active we *must*
// have a repeat duration shorter than the active duration so use that.
MOZ_ASSERT(GetRepeatDuration().IsDefinite(),
"Attempting to sample fill value of an active animation with "
"an indefinite repeat duration");
activeTime = GetRepeatDuration().GetMillis();
}
uint32_t repeatIteration;
nsSMILTime simpleTime =
@ -2173,8 +2224,13 @@ nsSMILTimedElement::GetNextMilestone(nsSMILMilestone& aNextMilestone) const
// Work out what comes next: the interval end or the next repeat iteration
nsSMILTimeValue nextRepeat;
if (mSeekState == SEEK_NOT_SEEKING && mSimpleDur.IsDefinite()) {
nextRepeat.SetMillis(mCurrentInterval->Begin()->Time().GetMillis() +
(mCurrentRepeatIteration + 1) * mSimpleDur.GetMillis());
nsSMILTime nextRepeatActiveTime =
(mCurrentRepeatIteration + 1) * mSimpleDur.GetMillis();
// Check that the repeat fits within the repeat duration
if (nsSMILTimeValue(nextRepeatActiveTime) < GetRepeatDuration()) {
nextRepeat.SetMillis(mCurrentInterval->Begin()->Time().GetMillis() +
nextRepeatActiveTime);
}
}
nsSMILTimeValue nextMilestone =
std::min(mCurrentInterval->End()->Time(), nextRepeat);
@ -2283,6 +2339,15 @@ nsSMILTimedElement::GetPreviousInterval() const
: mOldIntervals[mOldIntervals.Length()-1].get();
}
bool
nsSMILTimedElement::HasClientInFillRange() const
{
// Returns true if we have a client that is in the range where it will fill
return mClient &&
((mElementState != STATE_ACTIVE && HasPlayed()) ||
(mElementState == STATE_ACTIVE && !mClient->IsActive()));
}
bool
nsSMILTimedElement::EndHasEventConditions() const
{

Просмотреть файл

@ -512,6 +512,7 @@ protected:
const nsSMILInstanceTime* GetEffectiveBeginInstance() const;
const nsSMILInterval* GetPreviousInterval() const;
bool HasPlayed() const { return !mOldIntervals.IsEmpty(); }
bool HasClientInFillRange() const;
bool EndHasEventConditions() const;
bool AreEndTimesDependentOn(
const nsSMILInstanceTime* aBase) const;
@ -615,6 +616,9 @@ protected:
bool mDoDeferredUpdate; // Set if an update to the current interval was
// requested while mDeferIntervalUpdates was set
// Stack-based helper class to call UpdateCurrentInterval when it is destroyed
class AutoIntervalUpdater;
// Recursion depth checking
uint8_t mDeleteCount;
uint8_t mUpdateIntervalRecursionDepth;

Просмотреть файл

@ -32,12 +32,15 @@ support-files =
[test_smilGetSimpleDuration.xhtml]
[test_smilGetStartTime.xhtml]
[test_smilHyperlinking.xhtml]
[test_smilInvalidValues.html]
[test_smilKeySplines.xhtml]
[test_smilKeyTimes.xhtml]
[test_smilKeyTimesPacedMode.xhtml]
[test_smilMappedAttrFromBy.xhtml]
[test_smilMappedAttrFromTo.xhtml]
[test_smilMappedAttrPaced.xhtml]
[test_smilMinTiming.html]
[test_smilRepeatDuration.html]
[test_smilRepeatTiming.xhtml]
[test_smilReset.xhtml]
[test_smilRestart.xhtml]

Просмотреть файл

@ -0,0 +1,113 @@
<!doctype html>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=941315
-->
<head>
<meta charset="utf-8">
<title>Test invalid values cause the model to be updated (bug 941315)</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.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=941315">Mozilla Bug 941315</a>
<p id="display"></p>
<div id="content" style="display: none">
<svg width="100%" height="1" onload="this.pauseAnimations()">
<rect>
<animate id="a" dur="100s"/>
<animate id="b" dur="5s" begin="a.end"/>
</rect>
<circle cx="-100" cy="20" r="15" fill="blue" id="circle"/>
</svg>
</div>
<pre id="test">
<script class="testbody" type="text/javascript">
var a = $('a'),
b = $('b');
// Animation doesn't start until onload
SimpleTest.waitForExplicitFinish();
window.addEventListener("load", runTests, false);
// Make testing getStartTime easier
SVGAnimationElement.prototype.safeGetStartTime = function() {
try {
return this.getStartTime();
} catch(e) {
if (e.name == "InvalidStateError" &&
e.code == DOMException.INVALID_STATE_ERR) {
return 'none';
} else {
ok(false, "Unexpected exception: " + e);
return null;
}
}
};
function runTests() {
[testSimpleDuration, testMin, testMax, testRepeatDur, testRepeatCount]
.forEach(function(test) {
ise(b.getStartTime(), 100, "initial state before running " + test.name);
test();
ise(b.getStartTime(), 100, "final state after running " + test.name);
});
SimpleTest.finish();
}
function testSimpleDuration() {
// Verify a valid value updates as expected
a.setAttribute("dur", "50s");
ise(b.safeGetStartTime(), 50, "valid simple duration");
// Check an invalid value also causes the model to be updated
a.setAttribute("dur", "abc"); // -> indefinite
ise(b.safeGetStartTime(), "none", "invalid simple duration");
// Restore state
a.setAttribute("dur", "100s");
}
function testMin() {
a.setAttribute("min", "200s");
ise(b.safeGetStartTime(), 200, "valid min duration");
a.setAttribute("min", "abc"); // -> indefinite
ise(b.safeGetStartTime(), 100, "invalid min duration");
a.removeAttribute("min");
}
function testMax() {
a.setAttribute("max", "50s");
ise(b.safeGetStartTime(), 50, "valid max duration");
a.setAttribute("max", "abc"); // -> indefinite
ise(b.safeGetStartTime(), 100, "invalid max duration");
a.removeAttribute("max");
}
function testRepeatDur() {
a.setAttribute("repeatDur", "200s");
ise(b.safeGetStartTime(), 200, "valid repeatDur duration");
a.setAttribute("repeatDur", "abc"); // -> indefinite
ise(b.safeGetStartTime(), 100, "invalid repeatDur duration");
a.removeAttribute("repeatDur");
}
function testRepeatCount() {
a.setAttribute("repeatCount", "2");
ise(b.safeGetStartTime(), 200, "valid repeatCount duration");
a.setAttribute("repeatCount", "abc"); // -> indefinite
ise(b.safeGetStartTime(), 100, "invalid repeatCount duration");
a.removeAttribute("repeatCount");
}
</script>
</pre>
</body>
</html>

Просмотреть файл

@ -0,0 +1,93 @@
<!doctype html>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=948245
-->
<head>
<meta charset="utf-8">
<title>Test for Bug 948245</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.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=948245">Mozilla Bug 948245</a>
<p id="display"></p>
<div id="content" style="display: none">
<svg id="svg" onload="this.pauseAnimations()">
<rect fill="red" id="rect" x="0">
<animate attributeName="x" to="100" id="animation" dur="100s" min="200s"/>
</rect>
</svg>
</div>
<pre id="test">
<script class="testbody" type="text/javascript">
// The 'min' attribute introduces a kind of additional state into the SMIL
// model. If the 'min' attribute extends the active duration, the additional
// time between the amount of time the animation normally runs for (called the
// 'repeat duration') and the extended active duration is filled using the
// fill mode.
//
// Below we refer to this period of time between the end of the repeat
// duration and the end of the active duration as the 'extended period'.
//
// This test verifies that as we jump in and out of these states we produce
// the correct values.
//
// The test animation above produces an active interval that is longer than
// the 'repeating duration' of the animation.
var rect = $('rect'),
animation = $('animation');
// Animation doesn't start until onload
SimpleTest.waitForExplicitFinish();
window.addEventListener("load", runTests, false);
function runTests() {
ok($('svg').animationsPaused(), "should be paused by <svg> load handler");
// In the extended period (t=150s) we should not be animating or filling
// since the default fill mode is "none".
animation.ownerSVGElement.setCurrentTime(150);
ise(rect.x.animVal.value, 0,
"Shouldn't fill in extended period with fill='none'");
// If we set the fill mode we should start filling.
animation.setAttribute("fill", "freeze");
ise(rect.x.animVal.value, 100,
"Should fill in extended period with fill='freeze'");
// If we unset the fill attribute we should stop filling.
animation.removeAttribute("fill");
ise(rect.x.animVal.value, 0, "Shouldn't fill after unsetting fill");
// If we jump back into the repeated interval (at t=50s) we should be
// animating.
animation.ownerSVGElement.setCurrentTime(50);
ise(rect.x.animVal.value, 50, "Should be active in repeating interval");
// If we jump to the boundary at the start of the extended period we should
// not be filling (since we removed the fill attribute above).
animation.ownerSVGElement.setCurrentTime(100);
ise(rect.x.animVal.value, 0,
"Shouldn't fill after seeking to boundary of extended period");
// If we apply a fill mode at this boundary point we should do regular fill
// behavior of using the last value in the interpolation range.
animation.setAttribute("fill", "freeze");
ise(rect.x.animVal.value, 100,
"Should fill at boundary to extended period");
// Check that if we seek past the interval we fill with the value at the end
// of the _repeat_duration_ not the value at the end of the
// _active_duration_.
animation.setAttribute("repeatCount", "1.5");
animation.ownerSVGElement.setCurrentTime(225);
ise(rect.x.animVal.value, 50,
"Should fill with the end of the repeat duration value");
SimpleTest.finish();
}
</script>
</pre>
</body>
</html>

Просмотреть файл

@ -0,0 +1,139 @@
<!doctype html>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=948245
-->
<head>
<meta charset="utf-8">
<title>Test for repeat duration calculation (Bug 948245)</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.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=948245">Mozilla Bug 948245</a>
<p id="display"></p>
<div id="content" style="display: none">
<svg id="svg" onload="this.pauseAnimations()">
<rect>
<animate id="a"/>
<animate id="b" begin="a.end"/>
</rect>
</svg>
</div>
<pre id="test">
<script class="testbody" type="text/javascript">
// Tests the calculation of the repeat duration which is one of the steps
// towards determining the active duration.
//
// The repeat duration is determined by the following three attributes:
//
// dur: may be definite (e.g. '2s') or 'indefinite' (the default)
// repeatCount: may be definite (e.g. '2.5'), 'indefinite', or not set
// repeatDur: may be definite (e.g. '5s'), 'indefinite', or not set
//
// That leaves 18 combinations to test.
var testCases =
[
// 1. repeatDur: definite, repeatCount: definite, dur: definite
// (Two test cases here to ensure we get the minimum)
{ repeatDur: 15, repeatCount: 2, dur: 10, result: 15 },
{ repeatDur: 25, repeatCount: 2, dur: 10, result: 20 },
// 2. repeatDur: indefinite, repeatCount: definite, dur: definite
{ repeatDur: 'indefinite', repeatCount: 2, dur: 10, result: 20 },
// 3. repeatDur: not set, repeatCount: definite, dur: definite
{ repeatCount: 2, dur: 10, result: 20 },
// 4. repeatDur: definite, repeatCount: indefinite, dur: definite
{ repeatDur: 15, repeatCount: 'indefinite', dur: 10, result: 15 },
// 5. repeatDur: indefinite, repeatCount: indefinite, dur: definite
{ repeatDur: 'indefinite', repeatCount: 'indefinite', dur: 10,
result: 'indefinite' },
// 6. repeatDur: not set, repeatCount: indefinite, dur: definite
{ repeatCount: 'indefinite', dur: 10, result: 'indefinite' },
// 7. repeatDur: definite, repeatCount: not set, dur: definite
{ repeatDur: 15, dur: 10, result: 15 },
// 8. repeatDur: indefinite, repeatCount: not set, dur: definite
{ repeatDur: 'indefinite', dur: 10, result: 'indefinite' },
// 9. repeatDur: not set, repeatCount: not set, dur: definite
{ dur: 10, result: 10 },
// 10. repeatDur: definite, repeatCount: definite, dur: indefinite
{ repeatDur: 15, repeatCount: 2, dur: 'indefinite', result: 15 },
// 11. repeatDur: indefinite, repeatCount: definite, dur: indefinite
{ repeatDur: 'indefinite', repeatCount: 2, dur: 'indefinite',
result: 'indefinite' },
// 12. repeatDur: not set, repeatCount: definite, dur: indefinite
{ repeatCount: 2, dur: 'indefinite', result: 'indefinite' },
// 13. repeatDur: definite, repeatCount: indefinite, dur: indefinite
{ repeatDur: 15, repeatCount: 'indefinite', dur: 'indefinite',
result: 15 },
// 14. repeatDur: indefinite, repeatCount: indefinite, dur: indefinite
{ repeatDur: 'indefinite', repeatCount: 'indefinite', dur: 'indefinite',
result: 'indefinite' },
// 15. repeatDur: not set, repeatCount: indefinite, dur: indefinite
{ repeatCount: 'indefinite', dur: 'indefinite', result: 'indefinite' },
// 16. repeatDur: definite, repeatCount: not set, dur: indefinite
{ repeatDur: 15, dur: 'indefinite', result: 15 },
// 17. repeatDur: indefinite, repeatCount: not set, dur: indefinite
{ repeatDur: 'indefinite', dur: 'indefinite', result: 'indefinite' },
// 18. repeatDur: not set, repeatCount: not set, dur: indefinite
{ dur: 'indefinite', result: 'indefinite' }
];
// We can test the repeat duration by setting these attributes on animation
// 'a' and checking the start time of 'b' which is defined to start when 'a'
// finishes.
//
// Since 'a' has no end/min/max attributes the end of its active interval
// should coincide with the end of its repeat duration.
//
// Sometimes the repeat duration is defined to be 'indefinite'. In this case
// calling getStartTime on b will throw an exception so we need to catch that
// exception and translate it to 'indefinite' as follows:
function getRepeatDuration() {
try {
return $('b').getStartTime();
} catch(e) {
if (e.name == "InvalidStateError" &&
e.code == DOMException.INVALID_STATE_ERR) {
return 'indefinite';
} else {
ok(false, "Unexpected exception: " + e);
return null;
}
}
}
// Animation doesn't start until onload
SimpleTest.waitForExplicitFinish();
window.addEventListener("load", runTests, false);
// Run through each of the test cases
function runTests() {
ok($('svg').animationsPaused(), "should be paused by <svg> load handler");
testCases.forEach(function(test) {
var a = $('a');
// Set the attributes
var msgPieces = [];
[ 'repeatDur', 'repeatCount', 'dur' ].forEach(function(attr) {
if (typeof test[attr] != "undefined") {
a.setAttribute(attr, test[attr].toString());
msgPieces.push(attr + ': ' + test[attr].toString());
} else {
a.removeAttribute(attr);
msgPieces.push(attr + ': <not set>');
}
});
var msg = msgPieces.join(', ');
// Check the result
ise(getRepeatDuration(), test.result, msg);
});
SimpleTest.finish();
}
</script>
</pre>
</body>
</html>

Просмотреть файл

@ -95,6 +95,15 @@ SVGEllipseElement::GetLengthInfo()
void
SVGEllipseElement::ConstructPath(gfxContext *aCtx)
{
if (!aCtx->IsCairo()) {
RefPtr<Path> path = BuildPath();
if (path) {
gfxPath gfxpath(path);
aCtx->SetPath(&gfxpath);
}
return;
}
float x, y, rx, ry;
GetAnimatedLengthValues(&x, &y, &rx, &ry, nullptr);
@ -116,7 +125,7 @@ SVGEllipseElement::BuildPath()
RefPtr<PathBuilder> pathBuilder = CreatePathBuilder();
AppendEllipseToPath(pathBuilder, Point(x, y), Size(2.0*rx, 2.0*ry));
ArcToBezier(pathBuilder.get(), Point(x, y), Size(rx, ry), 0, Float(2*M_PI), false);
return pathBuilder->Finish();
}

Просмотреть файл

@ -211,9 +211,9 @@ SVGFEImageElement::GetPrimitiveDescription(nsSVGFilterInstance* aInstance,
nsRefPtr<gfxASurface> currentFrame;
if (imageContainer) {
imageContainer->GetFrame(imgIContainer::FRAME_CURRENT,
imgIContainer::FLAG_SYNC_DECODE,
getter_AddRefs(currentFrame));
currentFrame =
imageContainer->GetFrame(imgIContainer::FRAME_CURRENT,
imgIContainer::FLAG_SYNC_DECODE);
}
if (!currentFrame) {

Просмотреть файл

@ -1082,28 +1082,7 @@ nsXBLBinding::DoInitJSClass(JSContext *cx, JS::Handle<JSObject*> global,
bool
nsXBLBinding::AllowScripts()
{
if (!mPrototypeBinding->GetAllowScripts())
return false;
// Nasty hack. Use the JSContext of the bound node, since the
// security manager API expects to get the docshell type from
// that. But use the nsIPrincipal of our document.
nsIScriptSecurityManager* mgr = nsContentUtils::GetSecurityManager();
if (!mgr) {
return false;
}
nsIDocument* doc = mBoundElement ? mBoundElement->OwnerDoc() : nullptr;
if (!doc) {
return false;
}
nsCOMPtr<nsIScriptGlobalObject> global = do_QueryInterface(doc->GetInnerWindow());
if (!global || !global->GetGlobalJSObject()) {
return false;
}
return mgr->ScriptAllowed(global->GetGlobalJSObject());
return mPrototypeBinding->GetAllowScripts();
}
nsXBLBinding*

Просмотреть файл

@ -141,7 +141,7 @@ public:
JS::MutableHandle<JSObject*> aClassObject,
bool* aNew);
bool AllowScripts(); // XXX make const
bool AllowScripts();
mozilla::dom::XBLChildrenElement* FindInsertionPointFor(nsIContent* aChild);

Просмотреть файл

@ -403,6 +403,24 @@ nsXBLDocumentInfo::nsXBLDocumentInfo(nsIDocument* aDocument)
mScriptAccess = allow;
}
mIsChrome = true;
} else {
// If this binding isn't running with system principal, then it's running
// from a remote-XUL whitelisted domain. This is already a not-really-
// supported configuration (among other things, we don't use XBL scopes in
// that configuration for compatibility reasons). But we should still at
// least make an effort to prevent binding code from running if content
// script is disabled or if the source domain is blacklisted (since the
// source domain for remote XBL must always be the same as the source domain
// of the bound content).
//
// If we just ask the binding document if script is enabled, it will
// discover that it has no inner window, and return false. So instead, we
// short-circuit the normal compartment-managed script-disabling machinery,
// and query the policy for the URI directly.
bool allow;
nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
nsresult rv = ssm->PolicyAllowsScript(uri, &allow);
mScriptAccess = NS_SUCCEEDED(rv) && allow;
}
}

Просмотреть файл

@ -27,7 +27,7 @@ public:
already_AddRefed<nsIDocument> GetDocument()
{ nsCOMPtr<nsIDocument> copy = mDocument; return copy.forget(); }
bool GetScriptAccess() { return mScriptAccess; }
bool GetScriptAccess() const { return mScriptAccess; }
nsIURI* DocumentURI() { return mDocument->GetDocumentURI(); }

Просмотреть файл

@ -214,7 +214,7 @@ nsXBLPrototypeBinding::SetBindingElement(nsIContent* aElement)
}
bool
nsXBLPrototypeBinding::GetAllowScripts()
nsXBLPrototypeBinding::GetAllowScripts() const
{
return mXBLDocInfoWeak->GetScriptAccess();
}

Просмотреть файл

@ -48,7 +48,7 @@ public:
// binding URIs.
bool CompareBindingURI(nsIURI* aURI) const;
bool GetAllowScripts();
bool GetAllowScripts() const;
nsresult BindingAttached(nsIContent* aBoundElement);
nsresult BindingDetached(nsIContent* aBoundElement);

Просмотреть файл

@ -1,4 +1,6 @@
[DEFAULT]
support-files =
file_bug944407.xml
[test_bug378518.xul]
[test_bug398135.xul]
@ -6,3 +8,4 @@
[test_bug721452.xul]
[test_bug723676.xul]
[test_bug772966.xul]
[test_bug944407.xul]

Просмотреть файл

@ -0,0 +1,8 @@
<!DOCTYPE html>
<html>
<body>
<div id="deny" style="-moz-binding: url(file_bug944407.xml#testAllowScript)"></div>
<div id="allow" style="-moz-binding: url(chrome://mochitests/content/chrome/content/xbl/test/file_bug944407.xml#testAllowScript)"</div>
<script>/* Flush layout with a script tab - see bug 944407 comment 37. */</script>
</body>
</html>

Просмотреть файл

@ -0,0 +1,78 @@
<?xml version="1.0"?>
<bindings id="testBindings" xmlns="http://www.mozilla.org/xbl"
xmlns:html="http://www.w3.org/1999/xhtml">
<binding id="testAllowScript">
<implementation>
<property name="someProp" onget="return 2;" readonly="true"></property>
<method name="someMethod"><body> return 3; </body></method>
<method name="startTest">
<body>
<![CDATA[
// Make sure we only get constructed when we're loaded from a domain
// with script enabled.
is(this.id, 'allow', "XBL should only be bound when the origin of the binding allows scripts");
var t = this;
doFinish = function() {
// Take a moment to make sure that other constructors don't run when they shouldn't.
if (t.id == 'allow')
setTimeout(SpecialPowers.wrap(window.parent).finish, 100);
}
onTestEvent = function(target) {
ok(true, 'called event handler');
// First, dispatch an event to the anonymous content. The event
// handlers on the AC should run, but they won't until bug 948000
// is fixed. So the check here is a todo().
var e = new MouseEvent('click');
document.getAnonymousNodes(target)[1].dispatchEvent(e);
// Now, dispatch a key event to test key handlers and move the test along.
var k = document.createEvent('KeyboardEvent');
k.initEvent('keyup', true, true);
target.dispatchEvent(k);
}
// Check the implementation.
is(this.someProp, 2, "Properties work");
is(this.someMethod(), 3, "Methods work");
// Kick over to the event handlers. This tests XBL event handlers,
// XBL key handlers, and event handlers on anonymous content.
this.dispatchEvent(new CustomEvent('testEvent'));
]]>
</body>
</method>
<constructor>
<![CDATA[
win = XPCNativeWrapper.unwrap(window);
SpecialPowers = win.SpecialPowers;
ok = win.ok = SpecialPowers.wrap(window.parent).ok;
todo = win.todo = SpecialPowers.wrap(window.parent).todo;
is = win.is = SpecialPowers.wrap(window.parent).is;
info = win.info = SpecialPowers.wrap(window.parent).info;
info("Invoked constructor for " + this.id);
var t = this;
window.addEventListener('load', function loadListener() {
window.removeEventListener('load', loadListener);
// Wait two refresh-driver ticks to make sure that the constructor runs
// for both |allow| and |deny| if it's ever going to.
//
// See bug 944407 comment 37.
info("Invoked load listener for " + t.id);
window.requestAnimationFrame(function() { window.requestAnimationFrame(t.startTest.bind(t)); });
});
]]>
</constructor>
</implementation>
<handlers>
<handler event="testEvent" action="onTestEvent(this)" allowuntrusted="true"/>
<handler event="keyup" action="ok(true, 'called key handler'); doFinish();" allowuntrusted="true"/>
</handlers>
<content>Anonymous Content<html:div onclick="todo(true, 'called event handler on ac, this needs bug 948000');"></html:div><html:b style="display:none"><children/></html:b></content>
</binding>
</bindings>

Просмотреть файл

@ -12,6 +12,8 @@ support-files =
file_bug591198_xbl.xml
file_bug821850.xhtml
file_bug844783.xhtml
file_bug944407.html
file_bug944407.xml
[test_bug310107.html]
[test_bug366770.html]

Просмотреть файл

@ -0,0 +1,44 @@
<?xml version="1.0"?>
<?xml-stylesheet type="text/css" href="chrome://global/skin"?>
<?xml-stylesheet type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"?>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=944407
-->
<window title="Mozilla Bug 944407"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
<!-- test results are displayed in the html:body -->
<body xmlns="http://www.w3.org/1999/xhtml">
<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=944407"
target="_blank">Mozilla Bug 944407</a>
</body>
<!-- test code goes here -->
<script type="application/javascript">
<![CDATA[
/** Test for XBL bindings with script disabled. **/
SimpleTest.waitForExplicitFinish();
const Cu = Components.utils;
Cu.import('resource://gre/modules/Services.jsm');
function go() {
// Disable javascript, and load the frame.
function loadFrame() {
ok(!Services.prefs.getBoolPref('javascript.enabled'), "Javascript should be disabled");
$('ifr').setAttribute('src', 'http://mochi.test:8888/tests/content/xbl/test/file_bug944407.html');
}
SpecialPowers.pushPrefEnv({ set: [['javascript.enabled', false]] }, loadFrame);
}
function finish() {
SimpleTest.finish();
}
addLoadEvent(go);
]]>
</script>
<iframe id='ifr' />
</window>

Просмотреть файл

@ -1703,14 +1703,16 @@ Navigator::HasMobileMessageSupport(JSContext* /* unused */, JSObject* aGlobal)
/* static */
bool
Navigator::HasTelephonySupport(JSContext* /* unused */, JSObject* aGlobal)
Navigator::HasTelephonySupport(JSContext* cx, JSObject* aGlobal)
{
JS::Rooted<JSObject*> global(cx, aGlobal);
// First of all, the general pref has to be turned on.
bool enabled = false;
Preferences::GetBool("dom.telephony.enabled", &enabled);
NS_ENSURE_TRUE(enabled, false);
nsCOMPtr<nsPIDOMWindow> win = GetWindowFromGlobal(aGlobal);
nsCOMPtr<nsPIDOMWindow> win = GetWindowFromGlobal(global);
return win && CheckPermission(win, "telephony");
}
@ -1854,8 +1856,10 @@ bool Navigator::HasInputMethodSupport(JSContext* /* unused */,
/* static */
bool
Navigator::HasDataStoreSupport(JSContext* /* unused */, JSObject* aGlobal)
Navigator::HasDataStoreSupport(JSContext* cx, JSObject* aGlobal)
{
JS::Rooted<JSObject*> global(cx, aGlobal);
// First of all, the general pref has to be turned on.
bool enabled = false;
Preferences::GetBool("dom.datastore.enabled", &enabled);
@ -1866,7 +1870,7 @@ Navigator::HasDataStoreSupport(JSContext* /* unused */, JSObject* aGlobal)
return true;
}
nsCOMPtr<nsPIDOMWindow> win = GetWindowFromGlobal(aGlobal);
nsCOMPtr<nsPIDOMWindow> win = GetWindowFromGlobal(global);
if (!win) {
return false;
}

Просмотреть файл

@ -250,7 +250,7 @@ public:
}
static bool HasMobileMessageSupport(JSContext* /* unused */,
JSObject* aGlobal);
static bool HasTelephonySupport(JSContext* /* unused */,
static bool HasTelephonySupport(JSContext* cx,
JSObject* aGlobal);
static bool HasCameraSupport(JSContext* /* unused */,
JSObject* aGlobal);
@ -286,7 +286,7 @@ public:
static bool HasInputMethodSupport(JSContext* /* unused */, JSObject* aGlobal);
static bool HasDataStoreSupport(JSContext* /* unused */, JSObject* aGlobal);
static bool HasDataStoreSupport(JSContext* cx, JSObject* aGlobal);
nsPIDOMWindow* GetParentObject() const
{

Просмотреть файл

@ -1,98 +0,0 @@
# 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/.
import os
import cPickle
from Configuration import Configuration
from Codegen import CGBindingRoot, replaceFileIfChanged, CGEventRoot
from mozbuild.makeutil import Makefile
from mozbuild.pythonutil import iter_modules_in_path
from buildconfig import topsrcdir
def generate_binding_files(config, outputprefix, srcprefix, webidlfile,
generatedEventsWebIDLFiles):
"""
|config| Is the configuration object.
|outputprefix| is a prefix to use for the header guards and filename.
"""
depsname = ".deps/" + outputprefix + ".pp"
root = CGBindingRoot(config, outputprefix, webidlfile)
replaceFileIfChanged(outputprefix + ".h", root.declare())
replaceFileIfChanged(outputprefix + ".cpp", root.define())
if webidlfile in generatedEventsWebIDLFiles:
eventName = webidlfile[:-len(".webidl")]
generatedEvent = CGEventRoot(config, eventName)
replaceFileIfChanged(eventName + ".h", generatedEvent.declare())
replaceFileIfChanged(eventName + ".cpp", generatedEvent.define())
mk = Makefile()
# NOTE: it's VERY important that we output dependencies for the FooBinding
# file here, not for the header or generated cpp file. These dependencies
# are used later to properly determine changedDeps and prevent rebuilding
# too much. See the comment explaining $(binding_dependency_trackers) in
# Makefile.in.
rule = mk.create_rule([outputprefix])
rule.add_dependencies(os.path.join(srcprefix, x) for x in sorted(root.deps()))
rule.add_dependencies(iter_modules_in_path(topsrcdir))
with open(depsname, 'w') as f:
mk.dump(f)
def main():
# Parse arguments.
from optparse import OptionParser
usagestring = "usage: %prog [header|cpp] configFile outputPrefix srcPrefix webIDLFile"
o = OptionParser(usage=usagestring)
o.add_option("--verbose-errors", action='store_true', default=False,
help="When an error happens, display the Python traceback.")
(options, args) = o.parse_args()
configFile = os.path.normpath(args[0])
srcPrefix = os.path.normpath(args[1])
# Load the configuration
f = open('ParserResults.pkl', 'rb')
config = cPickle.load(f)
f.close()
def readFile(f):
file = open(f, 'rb')
try:
contents = file.read()
finally:
file.close()
return contents
allWebIDLFiles = readFile(args[2]).split()
generatedEventsWebIDLFiles = readFile(args[3]).split()
changedDeps = readFile(args[4]).split()
if all(f.endswith("Binding") or f == "ParserResults.pkl" for f in changedDeps):
toRegenerate = filter(lambda f: f.endswith("Binding"), changedDeps)
if len(toRegenerate) == 0 and len(changedDeps) == 1:
# Work around build system bug 874923: if we get here that means
# that changedDeps contained only one entry and it was
# "ParserResults.pkl". That should never happen: if the
# ParserResults.pkl changes then either one of the globalgen files
# changed (in which case we wouldn't be in this "only
# ParserResults.pkl and *Binding changed" code) or some .webidl
# files changed (and then the corresponding *Binding files should
# show up in changedDeps). Since clearly the build system is
# confused, just regenerate everything to be safe.
toRegenerate = allWebIDLFiles
else:
toRegenerate = map(lambda f: f[:-len("Binding")] + ".webidl",
toRegenerate)
else:
toRegenerate = allWebIDLFiles
for webIDLFile in toRegenerate:
assert webIDLFile.endswith(".webidl")
outputPrefix = webIDLFile[:-len(".webidl")] + "Binding"
generate_binding_files(config, outputPrefix, srcPrefix, webIDLFile,
generatedEventsWebIDLFiles);
if __name__ == '__main__':
main()

Просмотреть файл

@ -29,27 +29,6 @@ INSTANCE_RESERVED_SLOTS = 3
def memberReservedSlot(member):
return "(DOM_INSTANCE_RESERVED_SLOTS + %d)" % member.slotIndex
def replaceFileIfChanged(filename, newContents):
"""
Read a copy of the old file, so that we don't touch it if it hasn't changed.
Returns True if the file was updated, false otherwise.
"""
oldFileContents = ""
try:
oldFile = open(filename, 'rb')
oldFileContents = ''.join(oldFile.readlines())
oldFile.close()
except:
pass
if newContents == oldFileContents:
return False
f = open(filename, 'wb')
f.write(newContents)
f.close()
return True
def toStringBool(arg):
return str(not not arg).lower()

Просмотреть файл

@ -1,46 +0,0 @@
# 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/.
import os
import cPickle
from Configuration import Configuration
from Codegen import CGExampleRoot, replaceFileIfChanged
def generate_interface_example(config, interfaceName):
"""
|config| Is the configuration object.
|interfaceName| is the name of the interface we're generating an example for.
"""
root = CGExampleRoot(config, interfaceName)
exampleHeader = interfaceName + "-example.h"
exampleImpl = interfaceName + "-example.cpp"
replaceFileIfChanged(exampleHeader, root.declare())
replaceFileIfChanged(exampleImpl, root.define())
def main():
# Parse arguments.
from optparse import OptionParser
usagestring = "usage: %prog configFile interfaceName"
o = OptionParser(usage=usagestring)
o.add_option("--verbose-errors", action='store_true', default=False,
help="When an error happens, display the Python traceback.")
(options, args) = o.parse_args()
if len(args) != 2:
o.error(usagestring)
configFile = os.path.normpath(args[0])
interfaceName = args[1]
# Load the configuration
f = open('ParserResults.pkl', 'rb')
config = cPickle.load(f)
f.close()
# Generate the example class.
generate_interface_example(config, interfaceName)
if __name__ == '__main__':
main()

Просмотреть файл

@ -1,81 +0,0 @@
# 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/.
# We do one global pass over all the WebIDL to generate our prototype enum
# and generate information for subsequent phases.
import os
import WebIDL
import cPickle
from Configuration import Configuration
from Codegen import GlobalGenRoots, replaceFileIfChanged
def generate_file(config, name, action):
root = getattr(GlobalGenRoots, name)(config)
if action is 'declare':
filename = name + '.h'
code = root.declare()
else:
assert action is 'define'
filename = name + '.cpp'
code = root.define()
if replaceFileIfChanged(filename, code):
print "Generating %s" % (filename)
else:
print "%s hasn't changed - not touching it" % (filename)
def main():
# Parse arguments.
from optparse import OptionParser
usageString = "usage: %prog [options] webidldir [files]"
o = OptionParser(usage=usageString)
o.add_option("--cachedir", dest='cachedir', default=None,
help="Directory in which to cache lex/parse tables.")
o.add_option("--verbose-errors", action='store_true', default=False,
help="When an error happens, display the Python traceback.")
(options, args) = o.parse_args()
if len(args) < 2:
o.error(usageString)
configFile = args[0]
baseDir = args[1]
fileList = args[2:]
# Parse the WebIDL.
parser = WebIDL.Parser(options.cachedir)
for filename in fileList:
fullPath = os.path.normpath(os.path.join(baseDir, filename))
f = open(fullPath, 'rb')
lines = f.readlines()
f.close()
parser.parse(''.join(lines), fullPath)
parserResults = parser.finish()
# Load the configuration.
config = Configuration(configFile, parserResults)
# Write the configuration out to a pickle.
resultsFile = open('ParserResults.pkl', 'wb')
cPickle.dump(config, resultsFile, -1)
resultsFile.close()
# Generate the atom list.
generate_file(config, 'GeneratedAtomList', 'declare')
# Generate the prototype list.
generate_file(config, 'PrototypeList', 'declare')
# Generate the common code.
generate_file(config, 'RegisterBindings', 'declare')
generate_file(config, 'RegisterBindings', 'define')
generate_file(config, 'UnionTypes', 'declare')
generate_file(config, 'UnionTypes', 'define')
generate_file(config, 'UnionConversions', 'declare')
if __name__ == '__main__':
main()

Просмотреть файл

@ -1,243 +1,85 @@
# 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/.
# 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/.
abs_dist := $(abspath $(DIST))
webidl_base := $(topsrcdir)/dom/webidl
webidl_base = $(topsrcdir)/dom/webidl
# Generated by moz.build
include webidlsrcs.mk
binding_include_path := mozilla/dom
webidl_files += $(generated_events_webidl_files)
all_webidl_files = $(webidl_files) $(generated_webidl_files) $(preprocessed_webidl_files)
# Set exported_binding_headers before adding the test IDL to the mix
exported_binding_headers := $(subst .webidl,Binding.h,$(all_webidl_files))
exported_generated_events_headers := $(subst .webidl,.h,$(generated_events_webidl_files))
# Set linked_binding_cpp_files before adding the test IDL to the mix
linked_binding_cpp_files := $(subst .webidl,Binding.cpp,$(all_webidl_files))
linked_generated_events_cpp_files := $(subst .webidl,.cpp,$(generated_events_webidl_files))
all_webidl_files += $(test_webidl_files) $(preprocessed_test_webidl_files)
generated_header_files := $(subst .webidl,Binding.h,$(all_webidl_files)) $(exported_generated_events_headers)
generated_cpp_files := $(subst .webidl,Binding.cpp,$(all_webidl_files)) $(linked_generated_events_cpp_files)
# We want to be able to only regenerate the .cpp and .h files that really need
# to change when a .webidl file changes. We do this by making the
# binding_dependency_trackers targets have dependencies on the right .webidl
# files via generated .pp files, having a .BindingGen target that depends on the
# binding_dependency_trackers and which has all the generated binding .h/.cpp
# depending on it, and then in the make commands for that target being able to
# check which exact binding_dependency_trackers changed.
binding_dependency_trackers := $(subst .webidl,Binding,$(all_webidl_files))
globalgen_targets := \
GeneratedAtomList.h \
PrototypeList.h \
RegisterBindings.h \
RegisterBindings.cpp \
UnionTypes.h \
UnionTypes.cpp \
UnionConversions.h \
$(NULL)
# Nasty hack: when the test/Makefile.in invokes us to do codegen, it
# uses a target of
# "export TestExampleInterface-example TestExampleProxyInterface-example".
# We don't actually need to load our .o.pp files in that case, so just
# pretend like we have no CPPSRCS if that's the target. It makes the
# test cycle much faster, which is why we're doing it.
#
# XXXbz We could try to cheat even more and only include our CPPSRCS
# when $(MAKECMDGOALS) contains libs, so that we can skip loading all
# those .o.pp when trying to make a single .cpp file too, but that
# would break |make FooBinding.o(bj)|. Ah, well.
ifneq (export TestExampleInterface-example TestExampleProxyInterface-example,$(MAKECMDGOALS))
CPPSRCS = \
$(unified_binding_cpp_files) \
$(linked_generated_events_cpp_files) \
$(filter %.cpp, $(globalgen_targets)) \
$(NULL)
ifdef GNU_CC
OS_CXXFLAGS += -Wno-uninitialized
endif
ABS_DIST := $(abspath $(DIST))
# These come from webidlsrcs.mk.
# TODO Write directly into backend.mk.
CPPSRCS += $(globalgen_sources) $(unified_binding_cpp_files)
EXTRA_EXPORT_MDDEPEND_FILES := $(addsuffix .pp,$(binding_dependency_trackers))
# Generated bindings reference *Binding.h, not mozilla/dom/*Binding.h. And,
# since we generate exported bindings directly to $(DIST)/include, we need
# to add that path to the search list.
#
# Ideally, binding generation uses the prefixed header file names.
# Bug 932092 tracks.
LOCAL_INCLUDES += -I$(DIST)/include/mozilla/dom
EXPORTS_GENERATED_FILES := $(exported_binding_headers) $(exported_generated_events_headers)
EXPORTS_GENERATED_DEST := $(ABS_DIST)/include/$(binding_include_path)
EXPORTS_GENERATED_TARGET := export
INSTALL_TARGETS += EXPORTS_GENERATED
# Install auto-generated GlobalGen files. The rules for the install must
# be in the same target/subtier as GlobalGen.py, otherwise the files will not
# get installed into the appropriate location as they are generated.
globalgen_headers_FILES := \
GeneratedAtomList.h \
PrototypeList.h \
RegisterBindings.h \
UnionConversions.h \
UnionTypes.h \
$(NULL)
globalgen_headers_DEST = $(ABS_DIST)/include/mozilla/dom
globalgen_headers_TARGET := export
INSTALL_TARGETS += globalgen_headers
PYTHON_UNIT_TESTS += $(srcdir)/mozwebidlcodegen/test/test_mozwebidlcodegen.py
include $(topsrcdir)/config/rules.mk
ifdef GNU_CC
CXXFLAGS += -Wno-uninitialized
endif
# If you change bindinggen_dependencies here, change it in
# dom/bindings/test/Makefile.in too.
bindinggen_dependencies := \
BindingGen.py \
Bindings.conf \
Configuration.py \
Codegen.py \
ParserResults.pkl \
parser/WebIDL.py \
# TODO This list should be emitted to a .pp file via
# GenerateCSS2PropertiesWebIDL.py.
css2properties_dependencies = \
$(topsrcdir)/layout/style/nsCSSPropList.h \
$(topsrcdir)/layout/style/nsCSSPropAliasList.h \
$(webidl_base)/CSS2Properties.webidl.in \
$(webidl_base)/CSS2PropertiesProps.h \
$(srcdir)/GenerateCSS2PropertiesWebIDL.py \
$(GLOBAL_DEPS) \
$(NULL)
CSS2Properties.webidl: $(topsrcdir)/layout/style/nsCSSPropList.h \
$(topsrcdir)/layout/style/nsCSSPropAliasList.h \
$(webidl_base)/CSS2Properties.webidl.in \
$(webidl_base)/CSS2PropertiesProps.h \
$(srcdir)/GenerateCSS2PropertiesWebIDL.py \
$(GLOBAL_DEPS)
$(CPP) $(DEFINES) $(ACDEFINES) -I$(topsrcdir)/layout/style $(webidl_base)/CSS2PropertiesProps.h | \
PYTHONDONTWRITEBYTECODE=1 $(PYTHON) \
$(srcdir)/GenerateCSS2PropertiesWebIDL.py $(webidl_base)/CSS2Properties.webidl.in > CSS2Properties.webidl
CSS2Properties.webidl: $(css2properties_dependencies)
$(CPP) $(DEFINES) $(ACDEFINES) -I$(topsrcdir)/layout/style \
$(webidl_base)/CSS2PropertiesProps.h | \
PYTHONDONTWRITEBYTECODE=1 $(PYTHON) \
$(srcdir)/GenerateCSS2PropertiesWebIDL.py \
$(webidl_base)/CSS2Properties.webidl.in > $@
$(webidl_files): %: $(webidl_base)/%
$(INSTALL) $(IFLAGS1) $(webidl_base)/$* .
$(test_webidl_files): %: $(srcdir)/test/%
$(INSTALL) $(IFLAGS1) $(srcdir)/test/$* .
# We can't easily use PP_TARGETS here because it insists on outputting targets
# that look like "$(CURDIR)/foo" whereas we want our target to just be "foo".
# Make sure to include $(GLOBAL_DEPS) so we pick up changes to what symbols are
# defined. Also make sure to remove $@ before writing to it, because otherwise
# if a file goes from non-preprocessed to preprocessed we can end up writing to
# a symlink, which will clobber files in the srcdir, which is bad.
$(preprocessed_webidl_files): %: $(webidl_base)/% $(GLOBAL_DEPS)
$(RM) $@
$(call py_action,preprocessor, \
$(DEFINES) $(ACDEFINES) $(XULPPFLAGS) $(webidl_base)/$* -o $@)
# See the comment about PP_TARGETS for $(preprocessed_webidl_files)
$(preprocessed_test_webidl_files): %: $(srcdir)/test/% $(GLOBAL_DEPS)
$(RM) $@
$(call py_action,preprocessor, \
$(DEFINES) $(ACDEFINES) $(XULPPFLAGS) $(srcdir)/test/$* -o $@)
# Make is dumb and can get confused between "foo" and "$(CURDIR)/foo". Make
# sure that the latter depends on the former, since the latter gets used in .pp
# files.
all_webidl_files_absolute = $(addprefix $(CURDIR)/,$(all_webidl_files))
$(all_webidl_files_absolute): $(CURDIR)/%: %
$(generated_header_files): .BindingGen
$(generated_cpp_files): .BindingGen
# $(binding_dependency_trackers) pick up additional dependencies via .pp files
# The rule: just brings the tracker up to date, if it's out of date, so that
# we'll know that we have to redo binding generation and flag this prerequisite
# there as being newer than the bindinggen target.
$(binding_dependency_trackers):
@$(TOUCH) $@
$(globalgen_targets): ParserResults.pkl
%-example: .BindingGen
PYTHONDONTWRITEBYTECODE=1 $(PYTHON) $(topsrcdir)/config/pythonpath.py \
$(PLY_INCLUDE) -I$(srcdir)/parser \
$(srcdir)/ExampleGen.py \
$(srcdir)/Bindings.conf $*
CACHE_DIR = _cache
globalgen_dependencies := \
GlobalGen.py \
Bindings.conf \
Configuration.py \
Codegen.py \
parser/WebIDL.py \
webidlsrcs.mk \
$(all_webidl_files) \
$(CACHE_DIR)/.done \
# Most of the logic for dependencies lives inside Python so it can be
# used by multiple build backends. We simply have rules to generate
# and include the .pp file.
#
# The generated .pp file contains all the important dependencies such as
# changes to .webidl or .py files should result in code generation being
# performed.
codegen_dependencies := \
$(nonstatic_webidl_files) \
$(GLOBAL_DEPS) \
$(NULL)
$(CACHE_DIR)/.done:
$(MKDIR) -p $(CACHE_DIR)
$(call include_deps,codegen.pp)
codegen.pp: $(codegen_dependencies)
$(call py_action,webidl,$(srcdir))
@$(TOUCH) $@
# Running GlobalGen.py updates ParserResults.pkl as a side-effect
ParserResults.pkl: $(globalgen_dependencies)
$(info Generating global WebIDL files)
PYTHONDONTWRITEBYTECODE=1 $(PYTHON) $(topsrcdir)/config/pythonpath.py \
$(PLY_INCLUDE) -I$(srcdir)/parser \
$(srcdir)/GlobalGen.py $(srcdir)/Bindings.conf . \
--cachedir=$(CACHE_DIR) \
$(all_webidl_files)
$(globalgen_headers_FILES): ParserResults.pkl
# Make sure .deps actually exists, since we'll try to write to it from
# BindingGen.py but we're typically running in the export phase, which is
# before anyone has bothered creating .deps.
# Then, pass our long lists through files to try to avoid blowing out the
# command line.
# Next, BindingGen.py will examine the changed dependency list to figure out
# what it really needs to regenerate.
# Finally, touch the .BindingGen file so that we don't have to keep redoing
# all that until something else actually changes.
.BindingGen: $(bindinggen_dependencies) $(binding_dependency_trackers)
$(info Generating WebIDL bindings)
$(MKDIR) -p .deps
echo $(all_webidl_files) > .all-webidl-file-list
echo $(generated_events_webidl_files) > .generated-events-webidl-files
echo $? > .changed-dependency-list
PYTHONDONTWRITEBYTECODE=1 $(PYTHON) $(topsrcdir)/config/pythonpath.py \
$(PLY_INCLUDE) -I$(srcdir)/parser \
$(srcdir)/BindingGen.py \
$(srcdir)/Bindings.conf \
$(CURDIR) \
.all-webidl-file-list \
.generated-events-webidl-files \
.changed-dependency-list
@$(TOUCH) $@
.PHONY: compiletests
compiletests:
$(call SUBMAKE,libs,test)
GARBAGE += \
webidlyacc.py \
codegen.pp \
codegen.json \
parser.out \
$(wildcard *-example.h) \
$(wildcard *-example.cpp) \
.BindingGen \
.all-webidl-file-list \
.generated-events-webidl-files \
.changed-dependency-list \
$(binding_dependency_trackers) \
WebIDLGrammar.pkl \
$(wildcard *.h) \
$(wildcard *Binding.cpp) \
$(wildcard *Event.cpp) \
$(wildcard *-event.cpp) \
$(wildcard *.webidl) \
$(NULL)
# Make sure all binding header files are created during the export stage, so we
# don't have issues with .cpp files being compiled before we've generated the
# headers they depend on. This is really only needed for the test files, since
# the non-test headers are all exported above anyway. Note that this means that
# we do all of our codegen during export.
export:: $(generated_header_files)
distclean::
-$(RM) \
$(generated_header_files) \
$(generated_cpp_files) \
$(all_webidl_files) \
$(globalgen_targets) \
ParserResults.pkl \
$(NULL)
DIST_GARBAGE += \
file-lists.json \
$(NULL)

122
dom/bindings/docs/index.rst Normal file
Просмотреть файл

@ -0,0 +1,122 @@
.. _webidl:
======
WebIDL
======
WebIDL describes interfaces web browsers are supposed to implement.
The interaction between WebIDL and the build system is somewhat complex.
This document will attempt to explain how it all works.
Overview
========
``.webidl`` files throughout the tree define interfaces the browser
implements. Since Gecko/Firefox is implemented in C++, there is a
mechanism to convert these interfaces and associated metadata to
C++ code. That's where the build system comes into play.
All the code for interacting with ``.webidl`` files lives under
``dom/bindings``. There is code in the build system to deal with
WebIDLs explicitly.
WebIDL source file flavors
==========================
Not all ``.webidl`` files are created equal! There are several flavors,
each represented by a separate symbol from :ref:`mozbuild_symbols`.
WEBIDL_FILES
Refers to regular/static ``.webidl`` files. Most WebIDL interfaces
are defined this way.
GENERATED_EVENTS_WEBIDL_FILES
In addition to generating a binding, these ``.webidl`` files also
generate a source file implementing the event object in C++
PREPROCESSED_WEBIDL_FILES
The ``.webidl`` files are generated by preprocessing an input file.
They otherwise behave like *WEBIDL_FILES*.
TEST_WEBIDL_FILES
Like *WEBIDL_FILES* but the interfaces are for testing only and
aren't shipped with the browser.
PREPROCESSED_TEST_WEBIDL_FILES
Like *TEST_WEBIDL_FILES* except the ``.webidl`` is obtained via
preprocessing, much like *PREPROCESSED_WEBIDL_FILES*.
GENERATED_WEBIDL_FILES
The ``.webidl`` for these is obtained through an *external*
mechanism. Typically there are custom build rules for producing these
files.
Producing C++ code
==================
The most complicated part about WebIDLs is the process by which
``.webidl`` files are converted into C++.
This process is handled by code in the :py:mod:`mozwebidlcodegen`
package. :py:class:`mozwebidlcodegen.WebIDLCodegenManager` is
specifically where you want to look for how code generation is
performed. This includes complex dependency management.
Requirements
============
This section aims to document the build and developer workflow requirements
for WebIDL.
Parser unit tests
There are parser tests provided by ``dom/bindings/parser/runtests.py``
that should run as part of ``make check``. There must be a mechanism
to run the tests in *human* mode so they output friendly error
messages.
The current mechanism for this is ``mach webidl-parser-test``.
Mochitests
There are various mochitests under ``dom/bindings/test``. They should
be runnable through the standard mechanisms.
Working with test interfaces
``TestExampleGenBinding.cpp`` calls into methods from the
``TestExampleInterface`` and ``TestExampleProxyInterface`` interfaces.
These interfaces need to be generated as part of the build. These
interfaces should not be exported or packaged.
There is a ``compiletests`` make target in ``dom/bindings`` that
isn't part of the build that facilitates turnkey code generation
and test file compilation.
Minimal rebuilds
Reprocessing every output for every change is expensive. So we don't
inconvenience people changing ``.webidl`` files, the build system
should only perform a minimal rebuild when sources change.
This logic is mostly all handled in
:py:class:`mozwebidlcodegen.WebIDLCodegenManager`. The unit tests for
that Python code should adequately test typical rebuild scenarios.
Bug 940469 tracks making the existing implementation better.
Explicit method for performing codegen
There needs to be an explicit method for invoking code generation.
It needs to cover regular and test files.
This is implemented via ``make export`` in ``dom/bindings``.
No-op binding generation should be fast
So developers touching ``.webidl`` files are not inconvenienced,
no-op binding generation should be fast. Watch out for the build system
processing large dependency files it doesn't need in order to perform
code generation.
Ability to generate example files
*Any* interface can have example ``.h``/``.cpp`` files generated.
There must be a mechanism to facilitate this.
This is currently facilitated through ``mach webidl-example``. e.g.
``mach webidl-example HTMLStyleElement``.

Просмотреть файл

@ -18,6 +18,17 @@ from mozbuild.base import MachCommandBase
@CommandProvider
class WebIDLProvider(MachCommandBase):
@Command('webidl-example', category='misc',
description='Generate example files for a WebIDL interface.')
@CommandArgument('interface', nargs='+',
help='Interface(s) whose examples to generate.')
def webidl_example(self, interface):
from mozwebidlcodegen import BuildSystemWebIDL
manager = self._spawn(BuildSystemWebIDL).manager
for i in interface:
manager.generate_example_files(i)
@Command('webidl-parser-test', category='testing',
description='Run WebIDL tests.')
@CommandArgument('--verbose', '-v', action='store_true',

Просмотреть файл

@ -4,6 +4,8 @@
# 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/.
TEST_DIRS += ['test']
EXPORTS.mozilla += [
'ErrorResult.h',
]
@ -85,3 +87,6 @@ if CONFIG['MOZ_AUDIO_CHANNEL_MANAGER']:
]
FINAL_LIBRARY = 'xul'
SPHINX_TREES['webidl'] = 'docs'
SPHINX_PYTHON_PACKAGE_DIRS += ['mozwebidlcodegen']

Просмотреть файл

@ -0,0 +1,565 @@
# 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/.
# This module contains code for managing WebIDL files and bindings for
# the build system.
from __future__ import unicode_literals
import errno
import hashlib
import json
import logging
import os
from copy import deepcopy
from mach.mixin.logging import LoggingMixin
from mozbuild.base import MozbuildObject
from mozbuild.makeutil import Makefile
from mozbuild.pythonutil import iter_modules_in_path
from mozbuild.util import FileAvoidWrite
import mozpack.path as mozpath
import WebIDL
from Codegen import (
CGBindingRoot,
CGEventRoot,
CGExampleRoot,
GlobalGenRoots,
)
from Configuration import Configuration
class BuildResult(object):
"""Represents the result of processing WebIDL files.
This holds a summary of output file generation during code generation.
"""
def __init__(self):
# The .webidl files that had their outputs regenerated.
self.inputs = set()
# The output files that were created.
self.created = set()
# The output files that changed.
self.updated = set()
# The output files that didn't change.
self.unchanged = set()
class WebIDLCodegenManagerState(dict):
"""Holds state for the WebIDL code generation manager.
State is currently just an extended dict. The internal implementation of
state should be considered a black box to everyone except
WebIDLCodegenManager. But we'll still document it.
Fields:
version
The integer version of the format. This is to detect incompatible
changes between state. It should be bumped whenever the format
changes or semantics change.
webidls
A dictionary holding information about every known WebIDL input.
Keys are the basenames of input WebIDL files. Values are dicts of
metadata. Keys in those dicts are:
* filename - The full path to the input filename.
* inputs - A set of full paths to other webidl files this webidl
depends on.
* outputs - Set of full output paths that are created/derived from
this file.
* sha1 - The hexidecimal SHA-1 of the input filename from the last
processing time.
global_inputs
A dictionary defining files that influence all processing. Keys
are full filenames. Values are hexidecimal SHA-1 from the last
processing time.
"""
VERSION = 1
def __init__(self, fh=None):
self['version'] = self.VERSION
self['webidls'] = {}
self['global_depends'] = {}
if not fh:
return
state = json.load(fh)
if state['version'] != self.VERSION:
raise Exception('Unknown state version: %s' % state['version'])
self['version'] = state['version']
self['global_depends'] = state['global_depends']
for k, v in state['webidls'].items():
self['webidls'][k] = v
# Sets are converted to lists for serialization because JSON
# doesn't support sets.
self['webidls'][k]['inputs'] = set(v['inputs'])
self['webidls'][k]['outputs'] = set(v['outputs'])
def dump(self, fh):
"""Dump serialized state to a file handle."""
normalized = deepcopy(self)
for k, v in self['webidls'].items():
# Convert sets to lists because JSON doesn't support sets.
normalized['webidls'][k]['outputs'] = sorted(v['outputs'])
normalized['webidls'][k]['inputs'] = sorted(v['inputs'])
json.dump(normalized, fh, sort_keys=True)
class WebIDLCodegenManager(LoggingMixin):
"""Manages all code generation around WebIDL.
To facilitate testing, this object is meant to be generic and reusable.
Paths, etc should be parameters and not hardcoded.
"""
# Global parser derived declaration files.
GLOBAL_DECLARE_FILES = {
'GeneratedAtomList.h',
'PrototypeList.h',
'RegisterBindings.h',
'UnionConversions.h',
'UnionTypes.h',
}
# Global parser derived definition files.
GLOBAL_DEFINE_FILES = {
'RegisterBindings.cpp',
'UnionTypes.cpp',
}
# Example interfaces to build along with the tree. Other example
# interfaces will need to be generated manually.
BUILD_EXAMPLE_INTERFACES = {
'TestExampleInterface',
'TestExampleProxyInterface',
}
def __init__(self, config_path, inputs, exported_header_dir,
codegen_dir, state_path, cache_dir=None, make_deps_path=None,
make_deps_target=None):
"""Create an instance that manages WebIDLs in the build system.
config_path refers to a WebIDL config file (e.g. Bindings.conf).
inputs is a 3-tuple describing the input .webidl files and how to
process them. Members are:
(set(.webidl files), set(basenames of exported files),
set(basenames of generated events files))
exported_header_dir and codegen_dir are directories where generated
files will be written to.
state_path is the path to a file that will receive JSON state from our
actions.
make_deps_path is the path to a make dependency file that we can
optionally write.
make_deps_target is the target that receives the make dependencies. It
must be defined if using make_deps_path.
"""
self.populate_logger()
input_paths, exported_stems, generated_events_stems = inputs
self._config_path = config_path
self._input_paths = set(input_paths)
self._exported_stems = set(exported_stems)
self._generated_events_stems = set(generated_events_stems)
self._exported_header_dir = exported_header_dir
self._codegen_dir = codegen_dir
self._state_path = state_path
self._cache_dir = cache_dir
self._make_deps_path = make_deps_path
self._make_deps_target = make_deps_target
if (make_deps_path and not make_deps_target) or (not make_deps_path and
make_deps_target):
raise Exception('Must define both make_deps_path and make_deps_target '
'if one is defined.')
self._parser_results = None
self._config = None
self._state = WebIDLCodegenManagerState()
if os.path.exists(state_path):
with open(state_path, 'rb') as fh:
try:
self._state = WebIDLCodegenManagerState(fh=fh)
except Exception as e:
self.log(logging.WARN, 'webidl_bad_state', {'msg': str(e)},
'Bad WebIDL state: {msg}')
@property
def config(self):
if not self._config:
self._parse_webidl()
return self._config
def generate_build_files(self):
"""Generate files required for the build.
This function is in charge of generating all the .h/.cpp files derived
from input .webidl files. Please note that there are build actions
required to produce .webidl files and these build actions are
explicitly not captured here: this function assumes all .webidl files
are present and up to date.
This routine is called as part of the build to ensure files that need
to exist are present and up to date. This routine may not be called if
the build dependencies (generated as a result of calling this the first
time) say everything is up to date.
Because reprocessing outputs for every .webidl on every invocation
is expensive, we only regenerate the minimal set of files on every
invocation. The rules for deciding what needs done are roughly as
follows:
1. If any .webidl changes, reparse all .webidl files and regenerate
the global derived files. Only regenerate output files (.h/.cpp)
impacted by the modified .webidl files.
2. If an non-.webidl dependency (Python files, config file) changes,
assume everything is out of date and regenerate the world. This
is because changes in those could globally impact every output
file.
3. If an output file is missing, ensure it is present by performing
necessary regeneration.
"""
# Despite #1 above, we assume the build system is smart enough to not
# invoke us if nothing has changed. Therefore, any invocation means
# something has changed. And, if anything has changed, we need to
# parse the WebIDL.
self._parse_webidl()
result = BuildResult()
# If we parse, we always update globals - they are cheap and it is
# easier that way.
created, updated, unchanged = self._write_global_derived()
result.created |= created
result.updated |= updated
result.unchanged |= unchanged
# If any of the extra dependencies changed, regenerate the world.
global_changed, global_hashes = self._global_dependencies_changed()
if global_changed:
# Make a copy because we may modify.
changed_inputs = set(self._input_paths)
else:
changed_inputs = self._compute_changed_inputs()
self._state['global_depends'] = global_hashes
# Generate bindings from .webidl files.
for filename in sorted(changed_inputs):
basename = mozpath.basename(filename)
result.inputs.add(filename)
written, deps = self._generate_build_files_for_webidl(filename)
result.created |= written[0]
result.updated |= written[1]
result.unchanged |= written[2]
self._state['webidls'][basename] = dict(
filename=filename,
outputs=written[0] | written[1] | written[2],
inputs=set(deps),
sha1=self._input_hashes[filename],
)
# Process some special interfaces required for testing.
for interface in self.BUILD_EXAMPLE_INTERFACES:
written = self.generate_example_files(interface)
result.created |= written[0]
result.updated |= written[1]
result.unchanged |= written[2]
# Generate a make dependency file.
if self._make_deps_path:
mk = Makefile()
codegen_rule = mk.create_rule([self._make_deps_target])
codegen_rule.add_dependencies(global_hashes.keys())
codegen_rule.add_dependencies(self._input_paths)
with FileAvoidWrite(self._make_deps_path) as fh:
mk.dump(fh)
self._save_state()
return result
def generate_example_files(self, interface):
"""Generates example files for a given interface."""
root = CGExampleRoot(self.config, interface)
return self._maybe_write_codegen(root, *self._example_paths(interface))
def _parse_webidl(self):
self.log(logging.INFO, 'webidl_parse',
{'count': len(self._input_paths)},
'Parsing {count} WebIDL files.')
hashes = {}
parser = WebIDL.Parser(self._cache_dir)
for path in sorted(self._input_paths):
with open(path, 'rb') as fh:
data = fh.read()
hashes[path] = hashlib.sha1(data).hexdigest()
parser.parse(data, path)
self._parser_results = parser.finish()
self._config = Configuration(self._config_path, self._parser_results)
self._input_hashes = hashes
def _write_global_derived(self):
things = [('declare', f) for f in self.GLOBAL_DECLARE_FILES]
things.extend(('define', f) for f in self.GLOBAL_DEFINE_FILES)
result = (set(), set(), set())
for what, filename in things:
stem = mozpath.splitext(filename)[0]
root = getattr(GlobalGenRoots, stem)(self._config)
if what == 'declare':
code = root.declare()
output_root = self._exported_header_dir
elif what == 'define':
code = root.define()
output_root = self._codegen_dir
else:
raise Exception('Unknown global gen type: %s' % what)
output_path = mozpath.join(output_root, filename)
self._maybe_write_file(output_path, code, result)
return result
def _compute_changed_inputs(self):
"""Compute the set of input files that need to be regenerated."""
changed_inputs = set()
expected_outputs = self.expected_build_output_files()
# Look for missing output files.
if any(not os.path.exists(f) for f in expected_outputs):
# FUTURE Bug 940469 Only regenerate minimum set.
changed_inputs |= self._input_paths
# That's it for examining output files. We /could/ examine SHA-1's of
# output files from a previous run to detect modifications. But that's
# a lot of extra work and most build systems don't do that anyway.
# Now we move on to the input files.
old_hashes = {v['filename']: v['sha1']
for v in self._state['webidls'].values()}
old_filenames = set(old_hashes.keys())
new_filenames = self._input_paths
# If an old file has disappeared or a new file has arrived, mark
# it.
changed_inputs |= old_filenames ^ new_filenames
# For the files in common between runs, compare content. If the file
# has changed, mark it. We don't need to perform mtime comparisons
# because content is a stronger validator.
for filename in old_filenames & new_filenames:
if old_hashes[filename] != self._input_hashes[filename]:
changed_inputs.add(filename)
# We've now populated the base set of inputs that have changed.
# Inherit dependencies from previous run. The full set of dependencies
# is associated with each record, so we don't need to perform any fancy
# graph traversal.
for v in self._state['webidls'].values():
if any(dep for dep in v['inputs'] if dep in changed_inputs):
changed_inputs.add(v['filename'])
# Ensure all changed inputs actually exist (some changed inputs could
# have been from deleted files).
return set(f for f in changed_inputs if os.path.exists(f))
def _binding_info(self, p):
"""Compute binding metadata for an input path.
Returns a tuple of:
(stem, binding_stem, is_event, output_files)
output_files is itself a tuple. The first two items are the binding
header and C++ paths, respectively. The 2nd pair are the event header
and C++ paths or None if this isn't an event binding.
"""
basename = mozpath.basename(p)
stem = mozpath.splitext(basename)[0]
binding_stem = '%sBinding' % stem
if stem in self._exported_stems:
header_dir = self._exported_header_dir
else:
header_dir = self._codegen_dir
is_event = stem in self._generated_events_stems
files = (
mozpath.join(header_dir, '%s.h' % binding_stem),
mozpath.join(self._codegen_dir, '%s.cpp' % binding_stem),
mozpath.join(header_dir, '%s.h' % stem) if is_event else None,
mozpath.join(self._codegen_dir, '%s.cpp' % stem) if is_event else None,
)
return stem, binding_stem, is_event, header_dir, files
def _example_paths(self, interface):
return (
mozpath.join(self._codegen_dir, '%s-example.h' % interface),
mozpath.join(self._codegen_dir, '%s-example.cpp' % interface))
def expected_build_output_files(self):
"""Obtain the set of files generate_build_files() should write."""
paths = set()
# Account for global generation.
for p in self.GLOBAL_DECLARE_FILES:
paths.add(mozpath.join(self._exported_header_dir, p))
for p in self.GLOBAL_DEFINE_FILES:
paths.add(mozpath.join(self._codegen_dir, p))
for p in self._input_paths:
stem, binding_stem, is_event, header_dir, files = self._binding_info(p)
paths |= {f for f in files if f}
for interface in self.BUILD_EXAMPLE_INTERFACES:
for p in self._example_paths(interface):
paths.add(p)
return paths
def _generate_build_files_for_webidl(self, filename):
self.log(logging.INFO, 'webidl_generate_build_for_input',
{'filename': filename},
'Generating WebIDL files derived from {filename}')
stem, binding_stem, is_event, header_dir, files = self._binding_info(filename)
root = CGBindingRoot(self._config, binding_stem, filename)
result = self._maybe_write_codegen(root, files[0], files[1])
if is_event:
generated_event = CGEventRoot(self._config, stem)
result = self._maybe_write_codegen(generated_event, files[2],
files[3], result)
return result, root.deps()
def _global_dependencies_changed(self):
"""Determine whether the global dependencies have changed."""
current_files = set(iter_modules_in_path(mozpath.dirname(__file__)))
# We need to catch other .py files from /dom/bindings. We assume these
# are in the same directory as the config file.
current_files |= set(iter_modules_in_path(mozpath.dirname(self._config_path)))
current_files.add(self._config_path)
current_hashes = {}
for f in current_files:
# This will fail if the file doesn't exist. If a current global
# dependency doesn't exist, something else is wrong.
with open(f, 'rb') as fh:
current_hashes[f] = hashlib.sha1(fh.read()).hexdigest()
# The set of files has changed.
if current_files ^ set(self._state['global_depends'].keys()):
return True, current_hashes
# Compare hashes.
for f, sha1 in current_hashes.items():
if sha1 != self._state['global_depends'][f]:
return True, current_hashes
return False, current_hashes
def _save_state(self):
with open(self._state_path, 'wb') as fh:
self._state.dump(fh)
def _maybe_write_codegen(self, obj, declare_path, define_path, result=None):
assert declare_path and define_path
if not result:
result = (set(), set(), set())
self._maybe_write_file(declare_path, obj.declare(), result)
self._maybe_write_file(define_path, obj.define(), result)
return result
def _maybe_write_file(self, path, content, result):
fh = FileAvoidWrite(path)
fh.write(content)
existed, updated = fh.close()
if not existed:
result[0].add(path)
elif updated:
result[1].add(path)
else:
result[2].add(path)
def create_build_system_manager(topsrcdir, topobjdir, dist_dir):
"""Create a WebIDLCodegenManager for use by the build system."""
src_dir = os.path.join(topsrcdir, 'dom', 'bindings')
obj_dir = os.path.join(topobjdir, 'dom', 'bindings')
with open(os.path.join(obj_dir, 'file-lists.json'), 'rb') as fh:
files = json.load(fh)
inputs = (files['webidls'], files['exported_stems'],
files['generated_events_stems'])
cache_dir = os.path.join(obj_dir, '_cache')
try:
os.makedirs(cache_dir)
except OSError as e:
if e.errno != errno.EEXIST:
raise
return WebIDLCodegenManager(
os.path.join(src_dir, 'Bindings.conf'),
inputs,
os.path.join(dist_dir, 'include', 'mozilla', 'dom'),
obj_dir,
os.path.join(obj_dir, 'codegen.json'),
cache_dir=cache_dir,
# The make rules include a codegen.pp file containing dependencies.
make_deps_path=os.path.join(obj_dir, 'codegen.pp'),
make_deps_target='codegen.pp',
)
class BuildSystemWebIDL(MozbuildObject):
@property
def manager(self):
if not hasattr(self, '_webidl_manager'):
self._webidl_manager = create_build_system_manager(
self.topsrcdir, self.topobjdir, self.distdir)
return self._webidl_manager

Просмотреть файл

@ -0,0 +1,3 @@
interface Child : Parent {
void ChildBaz();
};

Просмотреть файл

@ -0,0 +1,2 @@
interface DummyInterface {};
interface DummyInterfaceWorkers {};

Просмотреть файл

@ -0,0 +1,3 @@
/* These interfaces are hard-coded and need to be defined. */
interface TestExampleInterface {};
interface TestExampleProxyInterface {};

Просмотреть файл

@ -0,0 +1,3 @@
interface Parent {
void MethodFoo();
};

Просмотреть файл

@ -0,0 +1,13 @@
interface EventTarget {
void addEventListener();
};
interface Event {};
callback EventHandlerNonNull = any (Event event);
typedef EventHandlerNonNull? EventHandler;
[NoInterfaceObject]
interface TestEvent : EventTarget {
attribute EventHandler onfoo;
};

Просмотреть файл

@ -0,0 +1,278 @@
# 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/.
from __future__ import unicode_literals
import imp
import json
import os
import shutil
import sys
import tempfile
import unittest
import mozpack.path as mozpath
from mozwebidlcodegen import (
WebIDLCodegenManager,
WebIDLCodegenManagerState,
)
from mozfile import NamedTemporaryFile
from mozunit import (
MockedOpen,
main,
)
OUR_DIR = mozpath.abspath(mozpath.dirname(__file__))
TOPSRCDIR = mozpath.normpath(mozpath.join(OUR_DIR, '..', '..', '..', '..'))
class TestWebIDLCodegenManager(unittest.TestCase):
TEST_STEMS = {
'Child',
'Parent',
'ExampleBinding',
'TestEvent',
}
@property
def _static_input_paths(self):
s = {mozpath.join(OUR_DIR, p) for p in os.listdir(OUR_DIR)
if p.endswith('.webidl')}
return s
@property
def _config_path(self):
config = mozpath.join(TOPSRCDIR, 'dom', 'bindings', 'Bindings.conf')
self.assertTrue(os.path.exists(config))
return config
def _get_manager_args(self):
tmp = tempfile.mkdtemp()
self.addCleanup(shutil.rmtree, tmp)
cache_dir = mozpath.join(tmp, 'cache')
os.mkdir(cache_dir)
ip = self._static_input_paths
inputs = (
ip,
{mozpath.splitext(mozpath.basename(p))[0] for p in ip},
set()
)
return dict(
config_path=self._config_path,
inputs=inputs,
exported_header_dir=mozpath.join(tmp, 'exports'),
codegen_dir=mozpath.join(tmp, 'codegen'),
state_path=mozpath.join(tmp, 'state.json'),
make_deps_path=mozpath.join(tmp, 'codegen.pp'),
make_deps_target='codegen.pp',
cache_dir=cache_dir,
)
def _get_manager(self):
return WebIDLCodegenManager(**self._get_manager_args())
def test_unknown_state_version(self):
"""Loading a state file with a too new version resets state."""
args = self._get_manager_args()
p = args['state_path']
with open(p, 'wb') as fh:
json.dump({
'version': WebIDLCodegenManagerState.VERSION + 1,
'foobar': '1',
}, fh)
manager = WebIDLCodegenManager(**args)
self.assertEqual(manager._state['version'],
WebIDLCodegenManagerState.VERSION)
self.assertNotIn('foobar', manager._state)
def test_generate_build_files(self):
"""generate_build_files() does the right thing from empty."""
manager = self._get_manager()
result = manager.generate_build_files()
self.assertEqual(len(result.inputs), 5)
output = manager.expected_build_output_files()
self.assertEqual(result.created, output)
self.assertEqual(len(result.updated), 0)
self.assertEqual(len(result.unchanged), 0)
for f in output:
self.assertTrue(os.path.isfile(f))
for f in manager.GLOBAL_DECLARE_FILES:
self.assertIn(mozpath.join(manager._exported_header_dir, f), output)
for f in manager.GLOBAL_DEFINE_FILES:
self.assertIn(mozpath.join(manager._codegen_dir, f), output)
for s in self.TEST_STEMS:
self.assertTrue(os.path.isfile(mozpath.join(
manager._exported_header_dir, '%sBinding.h' % s)))
self.assertTrue(os.path.isfile(mozpath.join(
manager._codegen_dir, '%sBinding.cpp' % s)))
self.assertTrue(os.path.isfile(manager._state_path))
with open(manager._state_path, 'rb') as fh:
state = json.load(fh)
self.assertEqual(state['version'], 1)
self.assertIn('webidls', state)
child = state['webidls']['Child.webidl']
self.assertEqual(len(child['inputs']), 2)
self.assertEqual(len(child['outputs']), 2)
self.assertEqual(child['sha1'], 'c41527cad3bc161fa6e7909e48fa11f9eca0468b')
def test_generate_build_files_load_state(self):
"""State should be equivalent when instantiating a new instance."""
args = self._get_manager_args()
m1 = WebIDLCodegenManager(**args)
self.assertEqual(len(m1._state['webidls']), 0)
m1.generate_build_files()
m2 = WebIDLCodegenManager(**args)
self.assertGreater(len(m2._state['webidls']), 2)
self.assertEqual(m1._state, m2._state)
def test_no_change_no_writes(self):
"""If nothing changes, no files should be updated."""
args = self._get_manager_args()
m1 = WebIDLCodegenManager(**args)
m1.generate_build_files()
m2 = WebIDLCodegenManager(**args)
result = m2.generate_build_files()
self.assertEqual(len(result.inputs), 0)
self.assertEqual(len(result.created), 0)
self.assertEqual(len(result.updated), 0)
def test_output_file_regenerated(self):
"""If an output file disappears, it is regenerated."""
args = self._get_manager_args()
m1 = WebIDLCodegenManager(**args)
m1.generate_build_files()
rm_count = 0
for p in m1._state['webidls']['Child.webidl']['outputs']:
rm_count += 1
os.unlink(p)
for p in m1.GLOBAL_DECLARE_FILES:
rm_count += 1
os.unlink(mozpath.join(m1._exported_header_dir, p))
m2 = WebIDLCodegenManager(**args)
result = m2.generate_build_files()
self.assertEqual(len(result.created), rm_count)
def test_only_rebuild_self(self):
"""If an input file changes, only rebuild that one file."""
args = self._get_manager_args()
m1 = WebIDLCodegenManager(**args)
m1.generate_build_files()
child_path = None
for p in m1._input_paths:
if p.endswith('Child.webidl'):
child_path = p
break
self.assertIsNotNone(child_path)
child_content = open(child_path, 'rb').read()
with MockedOpen({child_path: child_content + '\n/* */'}):
m2 = WebIDLCodegenManager(**args)
result = m2.generate_build_files()
self.assertEqual(result.inputs, set([child_path]))
self.assertEqual(len(result.updated), 0)
self.assertEqual(len(result.created), 0)
def test_rebuild_dependencies(self):
"""Ensure an input file used by others results in others rebuilding."""
args = self._get_manager_args()
m1 = WebIDLCodegenManager(**args)
m1.generate_build_files()
parent_path = None
child_path = None
for p in m1._input_paths:
if p.endswith('Parent.webidl'):
parent_path = p
elif p.endswith('Child.webidl'):
child_path = p
self.assertIsNotNone(parent_path)
parent_content = open(parent_path, 'rb').read()
with MockedOpen({parent_path: parent_content + '\n/* */'}):
m2 = WebIDLCodegenManager(**args)
result = m2.generate_build_files()
self.assertEqual(result.inputs, {child_path, parent_path})
self.assertEqual(len(result.updated), 0)
self.assertEqual(len(result.created), 0)
def test_python_change_regenerate_everything(self):
"""If a Python file changes, we should attempt to rebuild everything."""
# We don't want to mutate files in the source directory because we want
# to be able to build from a read-only filesystem. So, we install a
# dummy module and rewrite the metadata to say it comes from the source
# directory.
#
# Hacking imp to accept a MockedFile doesn't appear possible. So for
# the first iteration we read from a temp file. The second iteration
# doesn't need to import, so we are fine with a mocked file.
fake_path = mozpath.join(OUR_DIR, 'fakemodule.py')
with NamedTemporaryFile('wt') as fh:
fh.write('# Original content')
fh.flush()
mod = imp.load_source('mozwebidlcodegen.fakemodule', fh.name)
mod.__file__ = fake_path
args = self._get_manager_args()
m1 = WebIDLCodegenManager(**args)
with MockedOpen({fake_path: '# Original content'}):
old_exists = os.path.exists
try:
def exists(p):
if p == fake_path:
return True
return old_exists(p)
os.path.exists = exists
result = m1.generate_build_files()
l = len(result.inputs)
with open(fake_path, 'wt') as fh:
fh.write('# Modified content')
m2 = WebIDLCodegenManager(**args)
result = m2.generate_build_files()
self.assertEqual(len(result.inputs), l)
result = m2.generate_build_files()
self.assertEqual(len(result.inputs), 0)
finally:
os.path.exists = old_exists
del sys.modules['mozwebidlcodegen.fakemodule']
if __name__ == '__main__':
main()

Просмотреть файл

@ -2,89 +2,23 @@
# 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/.
# Do NOT export this library. We don't actually want our test code
# being added to libxul or anything.
# pymake can't handle descending into dom/bindings several times simultaneously
ifdef .PYMAKE
.NOTPARALLEL:
endif
# Need this for $(test_webidl_files)
include ../webidlsrcs.mk
# But the webidl actually lives in our parent dir
test_webidl_files := $(addprefix ../,$(test_webidl_files))
# Store the actual locations of our source preprocessed files, so we
# can depend on them sanely.
source_preprocessed_test_webidl_files := $(addprefix $(srcdir)/,$(preprocessed_test_webidl_files))
preprocessed_test_webidl_files := $(addprefix ../,$(preprocessed_test_webidl_files))
CPPSRCS += \
$(subst .webidl,Binding.cpp,$(test_webidl_files)) \
$(subst .webidl,Binding.cpp,$(preprocessed_test_webidl_files)) \
$(NULL)
# If you change bindinggen_dependencies here, change it in
# dom/bindings/Makefile.in too. But note that we include ../Makefile
# here manually, since $(GLOBAL_DEPS) won't cover it.
bindinggen_dependencies := \
../BindingGen.py \
../Bindings.conf \
../Configuration.py \
../Codegen.py \
../ParserResults.pkl \
../parser/WebIDL.py \
../Makefile \
$(GLOBAL_DEPS) \
$(NULL)
# $(test_sources) comes from webidlsrcs.mk.
# TODO Update this variable in backend.mk.
CPPSRCS += $(addprefix ../,$(test_sources))
ifdef GNU_CC
CXXFLAGS += -Wno-uninitialized
OS_CXXFLAGS += -Wno-uninitialized
endif
# Bug 932082 tracks having bindings use namespaced includes.
LOCAL_INCLUDES += -I$(DIST)/include/mozilla/dom -I..
# Include rules.mk before any of our targets so our first target is coming from
# rules.mk and running make with no target in this dir does the right thing.
include $(topsrcdir)/config/rules.mk
$(CPPSRCS): .BindingGen
.BindingGen: $(bindinggen_dependencies) \
$(test_webidl_files) \
$(source_preprocessed_test_webidl_files) \
$(NULL)
# The export phase in dom/bindings is what actually looks at
# dependencies and regenerates things as needed, so just go ahead and
# make that phase here. Also make our example interface files. If the
# target used here ever changes, change the conditional around
# $(CPPSRCS) in dom/bindings/Makefile.in.
$(MAKE) -C .. export TestExampleInterface-example TestExampleProxyInterface-example
@$(TOUCH) $@
check::
PYTHONDONTWRITEBYTECODE=1 $(PYTHON) $(topsrcdir)/config/pythonpath.py \
$(PLY_INCLUDE) $(srcdir)/../parser/runtests.py
# Since we define MOCHITEST_FILES, config/makefiles/mochitest.mk goes ahead and
# sets up a rule with libs:: in itm which makes our .DEFAULT_TARGET be "libs".
# Then ruls.mk does |.DEFAULT_TARGET ?= default| which leaves it as "libs". So
# if we make without an explicit target in this directory, we try to make
# "libs", but with a $(MAKECMDGOALS) of empty string. And then rules.mk
# helpfully does not include our *.o.pp files, since it includes them only if
# filtering some stuff out from $(MAKECMDGOALS) leaves it nonempty. The upshot
# is that if some headers change and we run make in this dir without an explicit
# target things don't get rebuilt.
#
# On the other hand, if we set .DEFAULT_TARGET to "default" explicitly here,
# then rules.mk will reinvoke make with "export" and "libs" but this time hey
# will be passed as explicit targets, show up in $(MAKECMDGOALS), and things
# will work. Do this at the end of our Makefile so the rest of the build system
# does not get a chance to muck with it after we set it.
.DEFAULT_GOAL := default
# Make sure to add .BindingGen to GARBAGE so we'll rebuild our example
# files if someone goes through and deletes GARBAGE all over, which
# will delete example files from our parent dir.
GARBAGE += \
.BindingGen \
$(NULL)

Просмотреть файл

@ -14,9 +14,20 @@ MOCHITEST_MANIFESTS += ['mochitest.ini']
MOCHITEST_CHROME_MANIFESTS += ['chrome.ini']
TEST_WEBIDL_FILES += [
'TestDictionary.webidl',
'TestJSImplInheritanceGen.webidl',
'TestTypedef.webidl',
]
PREPROCESSED_TEST_WEBIDL_FILES += [
'TestCodeGen.webidl',
'TestExampleGen.webidl',
'TestJSImplGen.webidl',
]
LOCAL_INCLUDES += [
'/dom/bindings',
'/js/xpconnect/src',
'/js/xpconnect/wrappers',
]

Просмотреть файл

@ -65,8 +65,8 @@ BrowserElementParentFactory.prototype = {
// alive for as long as its frame element lives.
this._bepMap = new WeakMap();
Services.obs.addObserver(this, 'remote-browser-frame-shown', /* ownsWeak = */ true);
Services.obs.addObserver(this, 'in-process-browser-or-app-frame-shown', /* ownsWeak = */ true);
Services.obs.addObserver(this, 'remote-browser-shown', /* ownsWeak = */ true);
Services.obs.addObserver(this, 'inprocess-browser-shown', /* ownsWeak = */ true);
},
_browserFramesPrefEnabled: function() {
@ -79,11 +79,19 @@ BrowserElementParentFactory.prototype = {
},
_observeInProcessBrowserFrameShown: function(frameLoader) {
// Ignore notifications that aren't from a BrowserOrApp
if (!frameLoader.QueryInterface(Ci.nsIFrameLoader).ownerIsBrowserOrAppFrame) {
return;
}
debug("In-process browser frame shown " + frameLoader);
this._createBrowserElementParent(frameLoader, /* hasRemoteFrame = */ false);
},
_observeRemoteBrowserFrameShown: function(frameLoader) {
// Ignore notifications that aren't from a BrowserOrApp
if (!frameLoader.QueryInterface(Ci.nsIFrameLoader).ownerIsBrowserOrAppFrame) {
return;
}
debug("Remote browser frame shown " + frameLoader);
this._createBrowserElementParent(frameLoader, /* hasRemoteFrame = */ true);
},
@ -103,10 +111,10 @@ BrowserElementParentFactory.prototype = {
this._init();
}
break;
case 'remote-browser-frame-shown':
case 'remote-browser-shown':
this._observeRemoteBrowserFrameShown(subject);
break;
case 'in-process-browser-or-app-frame-shown':
case 'inprocess-browser-shown':
this._observeInProcessBrowserFrameShown(subject);
break;
case 'content-document-global-created':

Просмотреть файл

@ -22,11 +22,6 @@ function testSteps()
objectStore.add(Bob);
yield undefined;
// This direct eval causes locals to be aliased, and thus allocated on
// the scope chain. Comment it out (and the workarounds below) and
// the test passes. Bug 943409.
eval('');
db.transaction("foo", "readwrite").objectStore("foo")
.index("name").openCursor().onsuccess = function(event) {
event.target.transaction.oncomplete = continueToNextStep;

Просмотреть файл

@ -35,11 +35,6 @@ function testSteps()
let objectStore = db.createObjectStore("foo", { keyPath: "ss" });
objectStore.createIndex("name", "name", { unique: true });
// This direct eval causes locals to be aliased, and thus allocated on
// the scope chain. Comment it out (and the workarounds below) and
// the test passes. Bug 943409.
eval('');
for (let i = 0; i < objectStoreData.length - 1; i++) {
objectStore.add(objectStoreData[i]);
}

Просмотреть файл

@ -34,9 +34,6 @@ function testSteps()
event.target.onsuccess = continueToNextStep;
// Bug 943409.
eval('');
for (let objectStoreIndex in objectStoreData) {
const objectStoreInfo = objectStoreData[objectStoreIndex];
let objectStore = db.createObjectStore(objectStoreInfo.name,

Просмотреть файл

@ -18,9 +18,6 @@ function testSteps()
let db = event.target.result;
db.onerror = errorHandler;
// Bug 943409.
eval('');
for each (let autoIncrement in [false, true]) {
let objectStore =
db.createObjectStore(autoIncrement, { keyPath: "id",

Просмотреть файл

@ -44,8 +44,8 @@ this.Keyboard = {
},
init: function keyboardInit() {
Services.obs.addObserver(this, 'in-process-browser-or-app-frame-shown', false);
Services.obs.addObserver(this, 'remote-browser-frame-shown', false);
Services.obs.addObserver(this, 'inprocess-browser-shown', false);
Services.obs.addObserver(this, 'remote-browser-shown', false);
Services.obs.addObserver(this, 'oop-frameloader-crashed', false);
for (let name of this._messageNames)
@ -63,6 +63,10 @@ this.Keyboard = {
ppmm.broadcastAsyncMessage('Keyboard:FocusChange', { 'type': 'blur' });
}
} else {
// Ignore notifications that aren't from a BrowserOrApp
if (!frameLoader.ownerIsBrowserOrAppFrame) {
return;
}
this.initFormsFrameScript(mm);
}
},

Просмотреть файл

@ -602,7 +602,7 @@ ParticularProcessPriorityManager::Init()
nsCOMPtr<nsIObserverService> os = services::GetObserverService();
if (os) {
os->AddObserver(this, "audio-channel-process-changed", /* ownsWeak */ true);
os->AddObserver(this, "remote-browser-frame-shown", /* ownsWeak */ true);
os->AddObserver(this, "remote-browser-shown", /* ownsWeak */ true);
os->AddObserver(this, "ipc:browser-destroyed", /* ownsWeak */ true);
os->AddObserver(this, "frameloader-visible-changed", /* ownsWeak */ true);
}
@ -674,7 +674,7 @@ ParticularProcessPriorityManager::Observe(nsISupports* aSubject,
if (topic.EqualsLiteral("audio-channel-process-changed")) {
OnAudioChannelProcessChanged(aSubject);
} else if (topic.EqualsLiteral("remote-browser-frame-shown")) {
} else if (topic.EqualsLiteral("remote-browser-shown")) {
OnRemoteBrowserFrameShown(aSubject);
} else if (topic.EqualsLiteral("ipc:browser-destroyed")) {
OnTabParentDestroyed(aSubject);
@ -747,6 +747,13 @@ ParticularProcessPriorityManager::OnRemoteBrowserFrameShown(nsISupports* aSubjec
nsCOMPtr<nsIFrameLoader> fl = do_QueryInterface(aSubject);
NS_ENSURE_TRUE_VOID(fl);
// Ignore notifications that aren't from a BrowserOrApp
bool isBrowserOrApp;
fl->GetOwnerIsBrowserOrAppFrame(&isBrowserOrApp);
if (!isBrowserOrApp) {
return;
}
nsCOMPtr<nsITabParent> tp;
fl->GetTabParent(getter_AddRefs(tp));
NS_ENSURE_TRUE_VOID(tp);

Просмотреть файл

@ -107,12 +107,9 @@ if CONFIG['MOZ_NFC']:
if CONFIG['MOZ_B2G']:
PARALLEL_DIRS += ['downloads']
# bindings/test is here, because it needs to build after bindings/, and
# we build subdirectories before ourselves.
TEST_DIRS += [
'tests',
'imptests',
'bindings/test',
]
if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('gtk2', 'cocoa', 'windows', 'android', 'qt', 'os2'):

Просмотреть файл

@ -69,7 +69,6 @@ var ecmaGlobals =
{name: "NaN", xbl: false},
"Number",
"Object",
{name: "ParallelArray", nightly: true},
"Proxy",
"RangeError",
"ReferenceError",

Просмотреть файл

@ -553,18 +553,6 @@ if CONFIG['MOZ_B2G_FM']:
'FMRadio.webidl',
]
if CONFIG['ENABLE_TESTS']:
TEST_WEBIDL_FILES += [
'TestDictionary.webidl',
'TestJSImplInheritanceGen.webidl',
'TestTypedef.webidl',
]
PREPROCESSED_TEST_WEBIDL_FILES += [
'TestCodeGen.webidl',
'TestExampleGen.webidl',
'TestJSImplGen.webidl',
]
GENERATED_EVENTS_WEBIDL_FILES = [
'BlobEvent.webidl',
'CallGroupErrorEvent.webidl',

Просмотреть файл

@ -1208,7 +1208,7 @@ public:
JS::Rooted<JSObject*> target(aCx, JS::CurrentGlobalOrNull(aCx));
NS_ASSERTION(target, "This should never be null!");
bool preventDefaultCalled;
nsEventStatus status = nsEventStatus_eIgnore;
nsIScriptGlobalObject* sgo;
if (aWorkerPrivate) {
@ -1222,15 +1222,12 @@ public:
event.fileName = aFilename.get();
event.typeString = NS_LITERAL_STRING("error");
nsEventStatus status = nsEventStatus_eIgnore;
nsIDOMEventTarget* target = static_cast<nsIDOMEventTarget*>(globalTarget);
if (NS_FAILED(nsEventDispatcher::Dispatch(target, nullptr, &event,
nullptr, &status))) {
NS_WARNING("Failed to dispatch worker thread error event!");
status = nsEventStatus_eIgnore;
}
preventDefaultCalled = status == nsEventStatus_eConsumeNoDefault;
}
else if ((sgo = nsJSUtils::GetStaticScriptGlobal(target))) {
// Icky, we have to fire an InternalScriptErrorEvent...
@ -1239,16 +1236,14 @@ public:
event.errorMsg = aMessage.get();
event.fileName = aFilename.get();
nsEventStatus status = nsEventStatus_eIgnore;
if (NS_FAILED(sgo->HandleScriptError(&event, &status))) {
NS_WARNING("Failed to dispatch main thread error event!");
status = nsEventStatus_eIgnore;
}
preventDefaultCalled = status == nsEventStatus_eConsumeNoDefault;
}
if (preventDefaultCalled) {
// Was preventDefault() called?
if (status == nsEventStatus_eConsumeNoDefault) {
return true;
}
}

Просмотреть файл

@ -121,7 +121,7 @@ void
FlattenedPath::Arc(const Point &aOrigin, float aRadius, float aStartAngle,
float aEndAngle, bool aAntiClockwise)
{
ArcToBezier(this, aOrigin, aRadius, aStartAngle, aEndAngle, aAntiClockwise);
ArcToBezier(this, aOrigin, Size(aRadius, aRadius), aStartAngle, aEndAngle, aAntiClockwise);
}
Float
@ -407,7 +407,8 @@ FlattenBezier(const BezierControlPoints &aControlPoints,
return;
}
if (count == 0) {
// Check that at least one of the inflection points is inside [0..1]
if (count == 0 || ((t1 < 0 || t1 > 1.0) && ((t2 < 0 || t2 > 1.0) || count == 1)) ) {
FlattenBezierCurveSegment(aControlPoints, aSink, aTolerance);
return;
}

Просмотреть файл

@ -113,7 +113,7 @@ void
PathBuilderCairo::Arc(const Point &aOrigin, float aRadius, float aStartAngle,
float aEndAngle, bool aAntiClockwise)
{
ArcToBezier(this, aOrigin, aRadius, aStartAngle, aEndAngle, aAntiClockwise);
ArcToBezier(this, aOrigin, Size(aRadius, aRadius), aStartAngle, aEndAngle, aAntiClockwise);
}
Point

Просмотреть файл

@ -13,11 +13,11 @@ namespace mozilla {
namespace gfx {
template <typename T>
void ArcToBezier(T* aSink, const Point &aOrigin, float aRadius, float aStartAngle,
float aEndAngle, bool aAntiClockwise)
void ArcToBezier(T* aSink, const Point &aOrigin, const Size &aRadius,
float aStartAngle, float aEndAngle, bool aAntiClockwise)
{
Point startPoint(aOrigin.x + cos(aStartAngle) * aRadius,
aOrigin.y + sin(aStartAngle) * aRadius);
Point startPoint(aOrigin.x + cos(aStartAngle) * aRadius.width,
aOrigin.y + sin(aStartAngle) * aRadius.height);
aSink->LineTo(startPoint);
@ -56,23 +56,25 @@ void ArcToBezier(T* aSink, const Point &aOrigin, float aRadius, float aStartAngl
currentEndAngle = currentStartAngle + arcSweepLeft * sweepDirection;
}
Point currentStartPoint(aOrigin.x + cos(currentStartAngle) * aRadius,
aOrigin.y + sin(currentStartAngle) * aRadius);
Point currentEndPoint(aOrigin.x + cos(currentEndAngle) * aRadius,
aOrigin.y + sin(currentEndAngle) * aRadius);
Point currentStartPoint(aOrigin.x + cos(currentStartAngle) * aRadius.width,
aOrigin.y + sin(currentStartAngle) * aRadius.height);
Point currentEndPoint(aOrigin.x + cos(currentEndAngle) * aRadius.width,
aOrigin.y + sin(currentEndAngle) * aRadius.height);
// Calculate kappa constant for partial curve. The sign of angle in the
// tangent will actually ensure this is negative for a counter clockwise
// sweep, so changing signs later isn't needed.
Float kappa = (4.0f / 3.0f) * tan((currentEndAngle - currentStartAngle) / 4.0f) * aRadius;
Float kappaFactor = (4.0f / 3.0f) * tan((currentEndAngle - currentStartAngle) / 4.0f);
Float kappaX = kappaFactor * aRadius.width;
Float kappaY = kappaFactor * aRadius.height;
Point tangentStart(-sin(currentStartAngle), cos(currentStartAngle));
Point cp1 = currentStartPoint;
cp1 += tangentStart * kappa;
cp1 += Point(tangentStart.x * kappaX, tangentStart.y * kappaY);
Point revTangentEnd(sin(currentEndAngle), -cos(currentEndAngle));
Point cp2 = currentEndPoint;
cp2 += revTangentEnd * kappa;
cp2 += Point(revTangentEnd.x * kappaX, revTangentEnd.y * kappaY);
aSink->BezierTo(cp1, cp2, currentEndPoint);

Просмотреть файл

@ -88,7 +88,7 @@ void
PathBuilderSkia::Arc(const Point &aOrigin, float aRadius, float aStartAngle,
float aEndAngle, bool aAntiClockwise)
{
ArcToBezier(this, aOrigin, aRadius, aStartAngle, aEndAngle, aAntiClockwise);
ArcToBezier(this, aOrigin, Size(aRadius, aRadius), aStartAngle, aEndAngle, aAntiClockwise);
}
Point

Просмотреть файл

@ -22,7 +22,7 @@ namespace gl {
already_AddRefed<TextureImage>
CreateTextureImage(GLContext* gl,
const nsIntSize& aSize,
const gfx::IntSize& aSize,
TextureImage::ContentType aContentType,
GLenum aWrapMode,
TextureImage::Flags aFlags,
@ -101,7 +101,7 @@ TextureImage::UpdateFromDataSource(gfx::DataSourceSurface *aSurface,
}
gfx::IntRect TextureImage::GetTileRect() {
return gfx::IntRect(gfx::IntPoint(0,0), ToIntSize(mSize));
return gfx::IntRect(gfx::IntPoint(0,0), mSize);
}
gfx::IntRect TextureImage::GetSrcTileRect() {
@ -133,13 +133,13 @@ BasicTextureImage::BeginUpdate(nsIntRegion& aRegion)
if (CanUploadSubTextures(mGLContext)) {
GetUpdateRegion(aRegion);
} else {
aRegion = nsIntRect(nsIntPoint(0, 0), mSize);
aRegion = nsIntRect(nsIntPoint(0, 0), gfx::ThebesIntSize(mSize));
}
mUpdateRegion = aRegion;
nsIntRect rgnSize = mUpdateRegion.GetBounds();
if (!nsIntRect(nsIntPoint(0, 0), mSize).Contains(rgnSize)) {
if (!nsIntRect(nsIntPoint(0, 0), gfx::ThebesIntSize(mSize)).Contains(rgnSize)) {
NS_ERROR("update outside of image");
return nullptr;
}
@ -167,7 +167,7 @@ BasicTextureImage::GetUpdateRegion(nsIntRegion& aForRegion)
// changed, we need to recreate our backing surface and force the
// client to paint everything
if (mTextureState != Valid)
aForRegion = nsIntRect(nsIntPoint(0, 0), mSize);
aForRegion = nsIntRect(nsIntPoint(0, 0), gfx::ThebesIntSize(mSize));
}
void
@ -248,7 +248,7 @@ BasicTextureImage::DirectUpdate(gfxASurface* aSurf, const nsIntRegion& aRegion,
}
void
BasicTextureImage::Resize(const nsIntSize& aSize)
BasicTextureImage::Resize(const gfx::IntSize& aSize)
{
NS_ASSERTION(!mUpdateSurface, "Resize() while in update?");
@ -268,13 +268,8 @@ BasicTextureImage::Resize(const nsIntSize& aSize)
mSize = aSize;
}
// Moz2D equivalents...
void TextureImage::Resize(const gfx::IntSize& aSize) {
Resize(ThebesIntSize(aSize));
}
gfx::IntSize TextureImage::GetSize() const {
return ToIntSize(mSize);
return mSize;
}
TextureImage::TextureImage(const gfx::IntSize& aSize,
@ -316,16 +311,6 @@ BasicTextureImage::BasicTextureImage(GLuint aTexture,
, mUpdateOffset(0, 0)
{}
already_AddRefed<TextureImage>
CreateBasicTextureImage(GLContext* aGL,
const gfx::IntSize& aSize,
TextureImage::ContentType aContentType,
GLenum aWrapMode,
TextureImage::Flags aFlags)
{
return CreateBasicTextureImage(aGL, ThebesIntSize(aSize), aContentType, aWrapMode, aFlags);
}
static bool
WantsSmallTiles(GLContext* gl)
{
@ -345,7 +330,7 @@ WantsSmallTiles(GLContext* gl)
}
TiledTextureImage::TiledTextureImage(GLContext* aGL,
nsIntSize aSize,
gfx::IntSize aSize,
TextureImage::ContentType aContentType,
TextureImage::Flags aFlags,
TextureImage::ImageFormat aImageFormat)
@ -438,7 +423,7 @@ TiledTextureImage::GetUpdateRegion(nsIntRegion& aForRegion)
// if the texture hasn't been initialized yet, or something important
// changed, we need to recreate our backing surface and force the
// client to paint everything
aForRegion = nsIntRect(nsIntPoint(0, 0), mSize);
aForRegion = nsIntRect(nsIntPoint(0, 0), gfx::ThebesIntSize(mSize));
return;
}
@ -484,7 +469,7 @@ TiledTextureImage::BeginUpdate(nsIntRegion& aRegion)
// if the texture hasn't been initialized yet, or something important
// changed, we need to recreate our backing surface and force the
// client to paint everything
aRegion = nsIntRect(nsIntPoint(0, 0), mSize);
aRegion = nsIntRect(nsIntPoint(0, 0), gfx::ThebesIntSize(mSize));
}
nsIntRect bounds = aRegion.GetBounds();
@ -637,7 +622,7 @@ TiledTextureImage::BindTexture(GLenum aTextureUnit)
* each column, and extra rows are pruned after iteration over the entire image
* finishes.
*/
void TiledTextureImage::Resize(const nsIntSize& aSize)
void TiledTextureImage::Resize(const gfx::IntSize& aSize)
{
if (mSize == aSize && mTextureState != Created) {
return;
@ -734,7 +719,7 @@ uint32_t TiledTextureImage::GetTileCount()
already_AddRefed<TextureImage>
CreateBasicTextureImage(GLContext* aGL,
const nsIntSize& aSize,
const gfx::IntSize& aSize,
TextureImage::ContentType aContentType,
GLenum aWrapMode,
TextureImage::Flags aFlags,

Просмотреть файл

@ -158,14 +158,12 @@ public:
* If this isn't implemented by a subclass, it will just perform
* a dummy BeginUpdate/EndUpdate pair.
*/
virtual void Resize(const nsIntSize& aSize) {
virtual void Resize(const gfx::IntSize& aSize) {
mSize = aSize;
nsIntRegion r(nsIntRect(0, 0, aSize.width, aSize.height));
BeginUpdate(r);
EndUpdate();
}
// Moz2D equivalent...
void Resize(const gfx::IntSize& aSize);
/**
* Mark this texture as having valid contents. Call this after modifying
@ -240,7 +238,7 @@ protected:
virtual gfx::IntRect GetSrcTileRect();
nsIntSize mSize;
gfx::IntSize mSize;
GLenum mWrapMode;
ContentType mContentType;
ImageFormat mImageFormat;
@ -302,7 +300,7 @@ public:
virtual bool InUpdate() const { return !!mUpdateSurface; }
virtual void Resize(const nsIntSize& aSize);
virtual void Resize(const gfx::IntSize& aSize);
protected:
GLuint mTexture;
@ -325,7 +323,7 @@ class TiledTextureImage
{
public:
TiledTextureImage(GLContext* aGL,
nsIntSize aSize,
gfx::IntSize aSize,
TextureImage::ContentType,
TextureImage::Flags aFlags = TextureImage::NoFlags,
TextureImage::ImageFormat aImageFormat = gfxImageFormatUnknown);
@ -334,7 +332,7 @@ public:
virtual gfxASurface* BeginUpdate(nsIntRegion& aRegion);
virtual void GetUpdateRegion(nsIntRegion& aForRegion);
virtual void EndUpdate();
virtual void Resize(const nsIntSize& aSize);
virtual void Resize(const gfx::IntSize& aSize);
virtual uint32_t GetTileCount();
virtual void BeginTileIteration();
virtual bool NextTile();
@ -356,7 +354,7 @@ protected:
void* mIterationCallbackData;
nsTArray< nsRefPtr<TextureImage> > mImages;
bool mInUpdate;
nsIntSize mSize;
gfx::IntSize mSize;
unsigned int mTileSize;
unsigned int mRows, mColumns;
GLContext* mGL;
@ -375,19 +373,12 @@ protected:
*/
already_AddRefed<TextureImage>
CreateBasicTextureImage(GLContext* aGL,
const nsIntSize& aSize,
const gfx::IntSize& aSize,
TextureImage::ContentType aContentType,
GLenum aWrapMode,
TextureImage::Flags aFlags,
TextureImage::ImageFormat aImageFormat = gfxImageFormatUnknown);
already_AddRefed<TextureImage>
CreateBasicTextureImage(GLContext* aGL,
const gfx::IntSize& aSize,
TextureImage::ContentType aContentType,
GLenum aWrapMode,
TextureImage::Flags aFlags);
/**
* Return a valid, allocated TextureImage of |aSize| with
* |aContentType|. If |aContentType| is COLOR, |aImageFormat| can be used
@ -406,7 +397,7 @@ CreateBasicTextureImage(GLContext* aGL,
*/
already_AddRefed<TextureImage>
CreateTextureImage(GLContext* gl,
const nsIntSize& aSize,
const gfx::IntSize& aSize,
TextureImage::ContentType aContentType,
GLenum aWrapMode,
TextureImage::Flags aFlags = TextureImage::NoFlags,

Просмотреть файл

@ -47,7 +47,7 @@ private:
already_AddRefed<TextureImage>
CreateTextureImageCGL(GLContext *gl,
const nsIntSize& aSize,
const gfx::IntSize& aSize,
TextureImage::ContentType aContentType,
GLenum aWrapMode,
TextureImage::Flags aFlags,

Просмотреть файл

@ -108,7 +108,7 @@ TextureImageCGL::FinishedSurfaceUpload()
already_AddRefed<TextureImage>
CreateTextureImageCGL(GLContext* gl,
const nsIntSize& aSize,
const gfx::IntSize& aSize,
TextureImage::ContentType aContentType,
GLenum aWrapMode,
TextureImage::Flags aFlags,

Просмотреть файл

@ -8,6 +8,7 @@
#include "GLContext.h"
#include "GLUploadHelpers.h"
#include "gfxPlatform.h"
#include "gfx2DGlue.h"
#include "mozilla/gfx/Types.h"
namespace mozilla {
@ -103,7 +104,7 @@ TextureImageEGL::GetUpdateRegion(nsIntRegion& aForRegion)
if (mTextureState != Valid) {
// if the texture hasn't been initialized yet, force the
// client to paint everything
aForRegion = nsIntRect(nsIntPoint(0, 0), mSize);
aForRegion = nsIntRect(nsIntPoint(0, 0), gfx::ThebesIntSize(mSize));
}
// We can only draw a rectangle, not subregions due to
@ -123,7 +124,7 @@ TextureImageEGL::BeginUpdate(nsIntRegion& aRegion)
mUpdateRect = aRegion.GetBounds();
//printf_stderr("BeginUpdate with updateRect [%d %d %d %d]\n", mUpdateRect.x, mUpdateRect.y, mUpdateRect.width, mUpdateRect.height);
if (!nsIntRect(nsIntPoint(0, 0), mSize).Contains(mUpdateRect)) {
if (!nsIntRect(nsIntPoint(0, 0), gfx::ThebesIntSize(mSize)).Contains(mUpdateRect)) {
NS_ERROR("update outside of image");
return nullptr;
}
@ -173,7 +174,7 @@ TextureImageEGL::EndUpdate()
if (mTextureState != Valid) {
NS_ASSERTION(mUpdateRect.x == 0 && mUpdateRect.y == 0 &&
mUpdateRect.Size() == mSize,
mUpdateRect.Size() == gfx::ThebesIntSize(mSize),
"Bad initial update on non-created texture!");
mGLContext->fTexImage2D(LOCAL_GL_TEXTURE_2D,
@ -242,7 +243,7 @@ TextureImageEGL::BindTexture(GLenum aTextureUnit)
}
void
TextureImageEGL::Resize(const nsIntSize& aSize)
TextureImageEGL::Resize(const gfx::IntSize& aSize)
{
NS_ASSERTION(!mUpdateSurface, "Resize() while in update?");
@ -313,7 +314,7 @@ TextureImageEGL::DestroyEGLSurface(void)
already_AddRefed<TextureImage>
CreateTextureImageEGL(GLContext *gl,
const nsIntSize& aSize,
const gfx::IntSize& aSize,
TextureImage::ContentType aContentType,
GLenum aWrapMode,
TextureImage::Flags aFlags,

Просмотреть файл

@ -47,7 +47,7 @@ public:
virtual bool InUpdate() const { return !!mUpdateSurface; }
virtual void Resize(const nsIntSize& aSize);
virtual void Resize(const gfx::IntSize& aSize);
bool BindTexImage();
@ -79,7 +79,7 @@ protected:
already_AddRefed<TextureImage>
CreateTextureImageEGL(GLContext *gl,
const nsIntSize& aSize,
const gfx::IntSize& aSize,
TextureImage::ContentType aContentType,
GLenum aWrapMode,
TextureImage::Flags aFlags,

Просмотреть файл

@ -5,6 +5,7 @@
#include "D3D9SurfaceImage.h"
#include "gfxImageSurface.h"
#include "gfx2DGlue.h"
namespace mozilla {
namespace layers {
@ -73,7 +74,7 @@ D3D9SurfaceImage::SetData(const Data& aData)
mTexture = texture;
mShareHandle = shareHandle;
mSize = gfxIntSize(region.width, region.height);
mSize = gfx::IntSize(region.width, region.height);
mQuery = query;
return S_OK;
@ -109,7 +110,7 @@ D3D9SurfaceImage::GetDesc() const
return mDesc;
}
gfxIntSize
gfx::IntSize
D3D9SurfaceImage::GetSize()
{
return mSize;
@ -122,7 +123,7 @@ D3D9SurfaceImage::GetAsSurface()
HRESULT hr;
nsRefPtr<gfxImageSurface> surface =
new gfxImageSurface(mSize, gfxImageFormatRGB24);
new gfxImageSurface(gfx::ThebesIntSize(mSize), gfxImageFormatRGB24);
if (!surface->CairoSurface() || surface->CairoStatus()) {
NS_WARNING("Failed to created Cairo image surface for D3D9SurfaceImage.");

Просмотреть файл

@ -44,7 +44,7 @@ public:
// complete.
HANDLE GetShareHandle();
gfxIntSize GetSize() MOZ_OVERRIDE;
gfx::IntSize GetSize() MOZ_OVERRIDE;
already_AddRefed<gfxASurface> GetAsSurface() MOZ_OVERRIDE;
@ -54,7 +54,7 @@ private:
// is complete, whereupon the texture is safe to use.
void EnsureSynchronized();
gfxIntSize mSize;
gfx::IntSize mSize;
RefPtr<IDirect3DTexture9> mTexture;
RefPtr<IDirect3DQuery9> mQuery;
HANDLE mShareHandle;

Просмотреть файл

@ -230,7 +230,7 @@ GrallocImage::GetAsSurface()
}
nsRefPtr<gfxImageSurface> imageSurface =
new gfxImageSurface(GetSize(), gfxImageFormatRGB16_565);
new gfxImageSurface(gfx::ThebesIntSize(GetSize()), gfxImageFormatRGB16_565);
uint32_t width = GetSize().width;
uint32_t height = GetSize().height;
@ -295,9 +295,7 @@ GrallocImage::GetTextureClient()
flags |= TEXTURE_RB_SWAPPED;
}
GrallocBufferActor* actor = static_cast<GrallocBufferActor*>(desc.bufferChild());
mTextureClient = new GrallocTextureClientOGL(actor,
gfx::ToIntSize(mSize),
flags);
mTextureClient = new GrallocTextureClientOGL(actor, mSize, flags);
mTextureClient->SetGraphicBufferLocked(mGraphicBuffer);
}
return mTextureClient;

Просмотреть файл

@ -7,6 +7,7 @@
#include "ImageContainer.h"
#include <string.h> // for memcpy, memset
#include "SharedTextureImage.h" // for SharedTextureImage
#include "gfx2DGlue.h"
#include "gfxImageSurface.h" // for gfxImageSurface
#include "gfxPlatform.h" // for gfxPlatform
#include "gfxUtils.h" // for gfxUtils
@ -16,6 +17,7 @@
#include "mozilla/layers/ImageBridgeChild.h" // for ImageBridgeChild
#include "mozilla/layers/ImageClient.h" // for ImageClient
#include "nsISupportsUtils.h" // for NS_IF_ADDREF
#include "YCbCrUtils.h" // for YCbCr conversions
#ifdef MOZ_WIDGET_GONK
#include "GrallocImages.h"
#endif
@ -50,7 +52,7 @@ Atomic<int32_t> Image::sSerialCounter(0);
already_AddRefed<Image>
ImageFactory::CreateImage(const ImageFormat *aFormats,
uint32_t aNumFormats,
const gfxIntSize &,
const gfx::IntSize &,
BufferRecycleBin *aRecycleBin)
{
if (!aNumFormats) {
@ -287,7 +289,7 @@ ImageContainer::LockCurrentImage()
}
already_AddRefed<gfxASurface>
ImageContainer::LockCurrentAsSurface(gfxIntSize *aSize, Image** aCurrentImage)
ImageContainer::LockCurrentAsSurface(gfx::IntSize *aSize, Image** aCurrentImage)
{
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
@ -345,7 +347,7 @@ ImageContainer::UnlockCurrentImage()
}
already_AddRefed<gfxASurface>
ImageContainer::GetCurrentAsSurface(gfxIntSize *aSize)
ImageContainer::GetCurrentAsSurface(gfx::IntSize *aSize)
{
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
@ -364,7 +366,7 @@ ImageContainer::GetCurrentAsSurface(gfxIntSize *aSize)
return mActiveImage->GetAsSurface();
}
gfxIntSize
gfx::IntSize
ImageContainer::GetCurrentSize()
{
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
@ -556,9 +558,9 @@ PlanarYCbCrImage::GetAsSurface()
return result.forget();
}
gfxImageFormat format = GetOffscreenFormat();
gfxIntSize size(mSize);
gfxUtils::GetYCbCrToRGBDestFormatAndSize(mData, format, size);
gfx::SurfaceFormat format = gfx::ImageFormatToSurfaceFormat(GetOffscreenFormat());
gfx::IntSize size(mSize);
gfx::GetYCbCrToRGBDestFormatAndSize(mData, format, size);
if (size.width > PlanarYCbCrImage::MAX_DIMENSION ||
size.height > PlanarYCbCrImage::MAX_DIMENSION) {
NS_ERROR("Illegal image dest width or height");
@ -566,11 +568,9 @@ PlanarYCbCrImage::GetAsSurface()
}
nsRefPtr<gfxImageSurface> imageSurface =
new gfxImageSurface(mSize, format);
new gfxImageSurface(gfx::ThebesIntSize(mSize), gfx::SurfaceFormatToImageFormat(format));
gfxUtils::ConvertYCbCrToRGB(mData, format, mSize,
imageSurface->Data(),
imageSurface->Stride());
gfx::ConvertYCbCrToRGB(mData, format, mSize, imageSurface->Data(), imageSurface->Stride());
mSurface = imageSurface;

Просмотреть файл

@ -15,6 +15,7 @@
#include "mozilla/Mutex.h" // for Mutex
#include "mozilla/ReentrantMonitor.h" // for ReentrantMonitorAutoEnter, etc
#include "mozilla/TimeStamp.h" // for TimeStamp
#include "mozilla/gfx/Point.h" // For IntSize
#include "mozilla/layers/LayersTypes.h" // for LayersBackend, etc
#include "mozilla/mozalloc.h" // for operator delete, etc
#include "nsAutoPtr.h" // for nsRefPtr, nsAutoArrayPtr, etc
@ -147,7 +148,7 @@ public:
void* GetImplData() { return mImplData; }
virtual already_AddRefed<gfxASurface> GetAsSurface() = 0;
virtual gfxIntSize GetSize() = 0;
virtual gfx::IntSize GetSize() = 0;
virtual nsIntRect GetPictureRect()
{
return nsIntRect(0, 0, GetSize().width, GetSize().height);
@ -262,7 +263,7 @@ protected:
virtual already_AddRefed<Image> CreateImage(const ImageFormat* aFormats,
uint32_t aNumFormats,
const gfxIntSize &aScaleHint,
const gfx::IntSize &aScaleHint,
BufferRecycleBin *aRecycleBin);
};
@ -483,7 +484,7 @@ public:
* the lock methods should be used to avoid the copy, however this should be
* avoided if the surface is required for a long period of time.
*/
already_AddRefed<gfxASurface> GetCurrentAsSurface(gfxIntSize* aSizeResult);
already_AddRefed<gfxASurface> GetCurrentAsSurface(gfx::IntSize* aSizeResult);
/**
* This is similar to GetCurrentAsSurface, however this does not make a copy
@ -493,7 +494,7 @@ public:
* type of image. Optionally a pointer can be passed to receive the current
* image.
*/
already_AddRefed<gfxASurface> LockCurrentAsSurface(gfxIntSize* aSizeResult,
already_AddRefed<gfxASurface> LockCurrentAsSurface(gfx::IntSize* aSizeResult,
Image** aCurrentImage = nullptr);
/**
@ -501,7 +502,7 @@ public:
* Can be called on any thread. This method takes mReentrantMonitor when accessing
* thread-shared state.
*/
gfxIntSize GetCurrentSize();
gfx::IntSize GetCurrentSize();
/**
* Sets a size that the image is expected to be rendered at.
@ -673,7 +674,7 @@ public:
~AutoLockImage() { if (mContainer) { mContainer->UnlockCurrentImage(); } }
Image* GetImage() { return mImage; }
const gfxIntSize &GetSize() { return mSize; }
const gfx::IntSize &GetSize() { return mSize; }
void Unlock() {
if (mContainer) {
@ -698,7 +699,7 @@ public:
private:
ImageContainer *mContainer;
nsRefPtr<Image> mImage;
gfxIntSize mSize;
gfx::IntSize mSize;
};
struct PlanarYCbCrData {
@ -819,7 +820,7 @@ public:
virtual bool IsValid() { return !!mBufferSize; }
virtual gfxIntSize GetSize() { return mSize; }
virtual gfx::IntSize GetSize() { return mSize; }
PlanarYCbCrImage(BufferRecycleBin *aRecycleBin);
@ -849,7 +850,7 @@ protected:
nsAutoArrayPtr<uint8_t> mBuffer;
uint32_t mBufferSize;
Data mData;
gfxIntSize mSize;
gfx::IntSize mSize;
gfxImageFormat mOffscreenFormat;
nsCountedRef<nsMainThreadSurfaceRef> mSurface;
nsRefPtr<BufferRecycleBin> mRecycleBin;
@ -885,7 +886,7 @@ public:
return surface.forget();
}
gfxIntSize GetSize() { return mSize; }
gfx::IntSize GetSize() { return mSize; }
CairoImage() : Image(nullptr, CAIRO_SURFACE) {}
@ -899,7 +900,7 @@ public:
already_AddRefed<gfxASurface> GetAsSurface();
gfxIntSize GetSize() { return mSize; }
gfx::IntSize GetSize() { return mSize; }
unsigned char *mData;
int mStride;

Просмотреть файл

@ -9,6 +9,7 @@
#include "gfxRect.h" // for gfxRect
#include "nsDebug.h" // for NS_ASSERTION
#include "nsISupportsImpl.h" // for ImageContainer::Release, etc
#include "gfx2DGlue.h"
namespace mozilla {
namespace layers {
@ -33,7 +34,7 @@ void ImageLayer::ComputeEffectiveTransforms(const gfx3DMatrix& aTransformToSurfa
// Snap image edges to pixel boundaries
gfxRect sourceRect(0, 0, 0, 0);
if (mContainer) {
sourceRect.SizeTo(mContainer->GetCurrentSize());
sourceRect.SizeTo(gfx::ThebesIntSize(mContainer->GetCurrentSize()));
if (mScaleMode != SCALE_NONE &&
sourceRect.width != 0.0 && sourceRect.height != 0.0) {
NS_ASSERTION(mScaleMode == SCALE_STRETCH,

Просмотреть файл

@ -16,6 +16,7 @@
#include "ReadbackLayer.h" // for ReadbackLayer
#include "gfxPlatform.h" // for gfxPlatform
#include "gfxUtils.h" // for gfxUtils, etc
#include "gfx2DGlue.h"
#include "mozilla/DebugOnly.h" // for DebugOnly
#include "mozilla/Telemetry.h" // for Accumulate
#include "mozilla/TelemetryHistogramEnums.h"
@ -509,7 +510,7 @@ Layer::SnapTransform(const gfx3DMatrix& aTransform,
gfx3DMatrix result;
if (mManager->IsSnappingEffectiveTransforms() &&
aTransform.Is2D(&matrix2D) &&
gfxSize(1.0, 1.0) <= aSnapRect.Size() &&
gfx::Size(1.0, 1.0) <= ToSize(aSnapRect.Size()) &&
matrix2D.PreservesAxisAlignedRectangles()) {
gfxPoint transformedTopLeft = matrix2D.Transform(aSnapRect.TopLeft());
transformedTopLeft.Round();

Просмотреть файл

@ -8,6 +8,7 @@
#include "ImageContainer.h"
#include "mozilla/gfx/MacIOSurface.h"
#include "mozilla/gfx/Point.h"
#include "mozilla/layers/TextureClient.h"
#include "gfxImageSurface.h"
@ -21,7 +22,7 @@ public:
void SetSurface(MacIOSurface* aSurface) { mSurface = aSurface; }
MacIOSurface* GetSurface() { return mSurface; }
gfxIntSize GetSize() {
gfx::IntSize GetSize() {
return gfxIntSize(mSurface->GetDevicePixelWidth(), mSurface->GetDevicePixelHeight());
}

Просмотреть файл

@ -11,7 +11,7 @@
#include "ImageTypes.h" // for ImageFormat::SHARED_TEXTURE
#include "gfxPoint.h" // for gfxIntSize
#include "nsCOMPtr.h" // for already_AddRefed
#include "nsSize.h" // for nsIntSize
#include "mozilla/gfx/Point.h" // for IntSize
class gfxASurface;
@ -27,14 +27,14 @@ public:
struct Data {
gl::SharedTextureHandle mHandle;
gl::SharedTextureShareType mShareType;
gfxIntSize mSize;
gfx::IntSize mSize;
bool mInverted;
};
void SetData(const Data& aData) { mData = aData; }
const Data* GetData() { return &mData; }
gfxIntSize GetSize() { return mData.mSize; }
gfx::IntSize GetSize() { return mData.mSize; }
virtual already_AddRefed<gfxASurface> GetAsSurface() {
return nullptr;

Просмотреть файл

@ -13,6 +13,7 @@
#include "mozilla/gfx/2D.h"
#include "mozilla/gfx/Helpers.h"
#include "gfxUtils.h"
#include "YCbCrUtils.h"
#include <algorithm>
#include "ImageContainer.h"
#define PIXMAN_DONT_DEFINE_STDINT
@ -175,24 +176,20 @@ public:
PlanarYCbCrData data;
DeserializerToPlanarYCbCrImageData(deserializer, data);
gfxImageFormat format = gfxImageFormatRGB24;
gfxIntSize size;
gfxUtils::GetYCbCrToRGBDestFormatAndSize(data, format, size);
gfx::SurfaceFormat format = FORMAT_B8G8R8X8;
gfx::IntSize size;
gfx::GetYCbCrToRGBDestFormatAndSize(data, format, size);
if (size.width > PlanarYCbCrImage::MAX_DIMENSION ||
size.height > PlanarYCbCrImage::MAX_DIMENSION) {
NS_ERROR("Illegal image dest width or height");
return false;
}
mSize = ToIntSize(size);
mFormat = (format == gfxImageFormatRGB24)
? FORMAT_B8G8R8X8
: FORMAT_B8G8R8A8;
mSize = size;
mFormat = format;
RefPtr<DataSourceSurface> surface = Factory::CreateDataSourceSurface(mSize, mFormat);
gfxUtils::ConvertYCbCrToRGB(data, format, size,
surface->GetData(),
surface->Stride());
gfx::ConvertYCbCrToRGB(data, format, size, surface->GetData(), surface->Stride());
mSurface = surface;
return true;

Просмотреть файл

@ -12,7 +12,6 @@
#include "gfxASurface.h" // for gfxASurface, etc
#include "gfxContext.h" // for gfxContext
#include "gfxPattern.h" // for gfxPattern, etc
#include "gfxPoint.h" // for gfxIntSize
#include "gfxUtils.h" // for gfxUtils
#ifdef MOZ_X11
#include "gfxXlibSurface.h" // for gfxXlibSurface
@ -25,6 +24,7 @@
#include "nsRect.h" // for nsIntRect
#include "nsRegion.h" // for nsIntRegion
#include "nsTraceRefcnt.h" // for MOZ_COUNT_CTOR, etc
#include "mozilla/gfx/Point.h" // for IntSize
using namespace mozilla::gfx;
@ -69,7 +69,7 @@ protected:
float aOpacity,
Layer* aMaskLayer);
gfxIntSize mSize;
gfx::IntSize mSize;
};
void
@ -94,7 +94,7 @@ BasicImageLayer::GetAndPaintCurrentImage(gfxContext* aContext,
nsRefPtr<gfxASurface> surface;
AutoLockImage autoLock(mContainer, getter_AddRefs(surface));
Image *image = autoLock.GetImage();
gfxIntSize size = mSize = autoLock.GetSize();
gfx::IntSize size = mSize = autoLock.GetSize();
if (!surface || surface->CairoStatus()) {
return nullptr;
@ -166,7 +166,7 @@ BasicImageLayer::GetAsSurface(gfxASurface** aSurface,
return false;
}
gfxIntSize dontCare;
gfx::IntSize dontCare;
nsRefPtr<gfxASurface> surface = mContainer->GetCurrentAsSurface(&dontCare);
*aSurface = surface.forget().get();
return true;

Просмотреть файл

@ -11,7 +11,6 @@
#include "gfxASurface.h" // for gfxASurface, etc
#include "gfxImageSurface.h" // for gfxImageSurface
#include "gfxPlatform.h" // for gfxPlatform, gfxImageFormat
#include "gfxPoint.h" // for gfxIntSize
#include "gfxUtils.h" // for gfxUtils
#include "mozilla/mozalloc.h" // for operator delete[], etc
#include "nsAutoPtr.h" // for nsRefPtr, nsAutoArrayPtr
@ -20,6 +19,9 @@
#include "nsDebug.h" // for NS_ERROR, NS_ASSERTION
#include "nsISupportsImpl.h" // for Image::Release, etc
#include "nsThreadUtils.h" // for NS_IsMainThread
#include "mozilla/gfx/Point.h" // for IntSize
#include "gfx2DGlue.h"
#include "YCbCrUtils.h" // for YCbCr conversions
#ifdef XP_MACOSX
#include "gfxQuartzImageSurface.h"
#endif
@ -30,7 +32,7 @@ namespace layers {
class BasicPlanarYCbCrImage : public PlanarYCbCrImage
{
public:
BasicPlanarYCbCrImage(const gfxIntSize& aScaleHint, gfxImageFormat aOffscreenFormat, BufferRecycleBin *aRecycleBin)
BasicPlanarYCbCrImage(const gfx::IntSize& aScaleHint, gfxImageFormat aOffscreenFormat, BufferRecycleBin *aRecycleBin)
: PlanarYCbCrImage(aRecycleBin)
, mScaleHint(aScaleHint)
, mDelayedConversion(false)
@ -54,7 +56,7 @@ public:
private:
nsAutoArrayPtr<uint8_t> mDecodedBuffer;
gfxIntSize mScaleHint;
gfx::IntSize mScaleHint;
int mStride;
bool mDelayedConversion;
};
@ -66,7 +68,7 @@ public:
virtual already_AddRefed<Image> CreateImage(const ImageFormat* aFormats,
uint32_t aNumFormats,
const gfxIntSize &aScaleHint,
const gfx::IntSize &aScaleHint,
BufferRecycleBin *aRecycleBin)
{
if (!aNumFormats) {
@ -99,25 +101,26 @@ BasicPlanarYCbCrImage::SetData(const Data& aData)
return;
}
gfxImageFormat format = GetOffscreenFormat();
gfx::SurfaceFormat format = gfx::ImageFormatToSurfaceFormat(GetOffscreenFormat());
gfxIntSize size(mScaleHint);
gfxUtils::GetYCbCrToRGBDestFormatAndSize(aData, format, size);
gfx::IntSize size(mScaleHint);
gfx::GetYCbCrToRGBDestFormatAndSize(aData, format, size);
if (size.width > PlanarYCbCrImage::MAX_DIMENSION ||
size.height > PlanarYCbCrImage::MAX_DIMENSION) {
NS_ERROR("Illegal image dest width or height");
return;
}
mStride = gfxASurface::FormatStrideForWidth(format, size.width);
gfxImageFormat iFormat = gfx::SurfaceFormatToImageFormat(format);
mStride = gfxASurface::FormatStrideForWidth(iFormat, size.width);
mDecodedBuffer = AllocateBuffer(size.height * mStride);
if (!mDecodedBuffer) {
// out of memory
return;
}
gfxUtils::ConvertYCbCrToRGB(aData, format, size, mDecodedBuffer, mStride);
SetOffscreenFormat(format);
gfx::ConvertYCbCrToRGB(aData, format, size, mDecodedBuffer, mStride);
SetOffscreenFormat(iFormat);
mSize = size;
}
@ -146,7 +149,7 @@ BasicPlanarYCbCrImage::GetAsSurface()
gfxImageFormat format = GetOffscreenFormat();
nsRefPtr<gfxImageSurface> imgSurface =
new gfxImageSurface(mDecodedBuffer, mSize, mStride, format);
new gfxImageSurface(mDecodedBuffer, gfx::ThebesIntSize(mSize), mStride, format);
if (!imgSurface || imgSurface->CairoStatus() != 0) {
return nullptr;
}

Просмотреть файл

@ -17,6 +17,8 @@
#include "mozilla/layers/CompositableForwarder.h"
#include "mozilla/layers/LayersTypes.h"
#include "mozilla/layers/TextureClient.h" // for TextureClient, etc
#include "mozilla/layers/GrallocTextureClient.h"
#include "mozilla/layers/TextureClientOGL.h"
#include "nsAutoPtr.h" // for nsRefPtr
#include "nsDebug.h" // for printf_stderr, NS_ASSERTION
#include "nsXULAppAPI.h" // for XRE_GetProcessType, etc
@ -27,12 +29,6 @@
using namespace mozilla::gfx;
using namespace mozilla::gl;
namespace mozilla {
namespace gfx {
class SharedSurface;
}
}
namespace mozilla {
namespace layers {
@ -44,7 +40,7 @@ CanvasClient::CreateCanvasClient(CanvasClientType aType,
if (aType == CanvasClientGLContext &&
aForwarder->GetCompositorBackendType() == LAYERS_OPENGL) {
aFlags |= TEXTURE_DEALLOCATE_CLIENT;
return new DeprecatedCanvasClientSurfaceStream(aForwarder, aFlags);
return new CanvasClientSurfaceStream(aForwarder, aFlags);
}
if (gfxPlatform::GetPlatform()->UseDeprecatedTextures()) {
aFlags |= TEXTURE_DEALLOCATE_CLIENT;
@ -106,6 +102,78 @@ CanvasClient2D::CreateBufferTextureClient(gfx::SurfaceFormat aFormat, TextureFla
mTextureInfo.mTextureFlags | aFlags);
}
CanvasClientSurfaceStream::CanvasClientSurfaceStream(CompositableForwarder* aLayerForwarder,
TextureFlags aFlags)
: CanvasClient(aLayerForwarder, aFlags)
{
}
void
CanvasClientSurfaceStream::Update(gfx::IntSize aSize, ClientCanvasLayer* aLayer)
{
GLScreenBuffer* screen = aLayer->mGLContext->Screen();
SurfaceStream* stream = screen->Stream();
bool isCrossProcess = !(XRE_GetProcessType() == GeckoProcessType_Default);
bool bufferCreated = false;
if (isCrossProcess) {
#ifdef MOZ_WIDGET_GONK
SharedSurface* surf = stream->SwapConsumer();
if (!surf) {
printf_stderr("surf is null post-SwapConsumer!\n");
return;
}
if (surf->Type() != SharedSurfaceType::Gralloc) {
printf_stderr("Unexpected non-Gralloc SharedSurface in IPC path!");
MOZ_ASSERT(false);
return;
}
SharedSurface_Gralloc* grallocSurf = SharedSurface_Gralloc::Cast(surf);
if (mBuffers.find(surf) == mBuffers.end()) {
GrallocTextureClientOGL* grallocTC =
new GrallocTextureClientOGL(static_cast<GrallocBufferActor*>(grallocSurf->GetDescriptor().bufferChild()),
grallocSurf->Size(),
mTextureInfo.mTextureFlags);
mBuffers[surf] = grallocTC;
bufferCreated = true;
}
if (bufferCreated && !AddTextureClient(mBuffers[surf])) {
mBuffers.erase(surf);
}
if (mBuffers.find(surf) != mBuffers.end()) {
GetForwarder()->UseTexture(this, mBuffers[surf]);
}
#else
printf_stderr("isCrossProcess, but not MOZ_WIDGET_GONK! Someone needs to write some code!");
MOZ_ASSERT(false);
#endif
} else {
if (!mBuffer) {
StreamTextureClientOGL* textureClient =
new StreamTextureClientOGL(mTextureInfo.mTextureFlags);
textureClient->InitWith(stream);
mBuffer = textureClient;
bufferCreated = true;
}
if (bufferCreated && !AddTextureClient(mBuffer)) {
mBuffer = nullptr;
}
if (mBuffer) {
GetForwarder()->UseTexture(this, mBuffer);
}
}
aLayer->Painted();
}
void
DeprecatedCanvasClient2D::Updated()
{

Просмотреть файл

@ -18,6 +18,12 @@
#include "mozilla/gfx/Point.h" // for IntSize
#include "mozilla/gfx/Types.h" // for SurfaceFormat
namespace mozilla {
namespace gfx {
class SharedSurface;
}
}
namespace mozilla {
namespace layers {
@ -95,6 +101,31 @@ private:
RefPtr<TextureClient> mBuffer;
};
// Used for GL canvases where we don't need to do any readback, i.e., with a
// GL backend.
class CanvasClientSurfaceStream : public CanvasClient
{
public:
CanvasClientSurfaceStream(CompositableForwarder* aLayerForwarder, TextureFlags aFlags);
TextureInfo GetTextureInfo() const
{
return TextureInfo(COMPOSITABLE_IMAGE);
}
virtual void Update(gfx::IntSize aSize, ClientCanvasLayer* aLayer) MOZ_OVERRIDE;
virtual void OnDetach() MOZ_OVERRIDE
{
mBuffers.clear();
mBuffer = nullptr;
}
private:
std::map<gfx::SharedSurface*, RefPtr<TextureClient> > mBuffers;
RefPtr<TextureClient> mBuffer;
};
class DeprecatedCanvasClient2D : public CanvasClient
{
public:

Просмотреть файл

@ -51,11 +51,11 @@ public:
"Can only set properties in construction phase");
CanvasLayer::SetVisibleRegion(aRegion);
}
virtual void Initialize(const Data& aData);
virtual void RenderLayer();
virtual void FillSpecificAttributes(SpecificLayerAttributes& aAttrs)
{
aAttrs = CanvasLayerAttributes(mFilter, mBounds);
@ -63,7 +63,7 @@ public:
virtual Layer* AsLayer() { return this; }
virtual ShadowableLayer* AsShadowableLayer() { return this; }
virtual void Disconnect()
{
mCanvasClient = nullptr;
@ -79,7 +79,7 @@ protected:
{
return static_cast<ClientLayerManager*>(mManager);
}
CanvasClientType GetCanvasClientType()
{
if (mGLContext) {
@ -93,6 +93,7 @@ protected:
friend class DeprecatedCanvasClient2D;
friend class CanvasClient2D;
friend class DeprecatedCanvasClientSurfaceStream;
friend class CanvasClientSurfaceStream;
};
}
}

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше