merge mozilla-inbound to mozilla-central a=merge

This commit is contained in:
Carsten "Tomcat" Book 2015-03-03 13:54:33 +01:00
commit 7636c71e85
118 changed files with 1819 additions and 1570 deletions

View File

@ -1850,6 +1850,10 @@ NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(nsDocument)
if (elm) {
elm->MarkForCC();
}
if (tmp->mExpandoAndGeneration.expando.isObject()) {
JS::ExposeObjectToActiveJS(
&(tmp->mExpandoAndGeneration.expando.toObject()));
}
return true;
}
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END

View File

@ -1369,6 +1369,10 @@ nsHTMLCopyEncoder::SetSelection(nsISelection* aSelection)
return NS_ERROR_NULL_POINTER;
range->GetCommonAncestorContainer(getter_AddRefs(commonParent));
// Thunderbird's msg compose code abuses the HTML copy encoder and gets
// confused if mIsTextWidget ends up becoming true, so for now we skip
// this logic in Thunderbird.
#ifndef MOZ_THUNDERBIRD
for (nsCOMPtr<nsIContent> selContent(do_QueryInterface(commonParent));
selContent;
selContent = selContent->GetParent())
@ -1395,7 +1399,7 @@ nsHTMLCopyEncoder::SetSelection(nsISelection* aSelection)
}
}
}
// normalize selection if we are not in a widget
if (mIsTextWidget)
{
@ -1403,6 +1407,7 @@ nsHTMLCopyEncoder::SetSelection(nsISelection* aSelection)
mMimeType.AssignLiteral("text/plain");
return NS_OK;
}
#endif
// also consider ourselves in a text widget if we can't find an html document
nsCOMPtr<nsIHTMLDocument> htmlDoc = do_QueryInterface(mDocument);

View File

@ -0,0 +1,13 @@
<!DOCTYPE html>
<html>
<body>
<h2>Frame I am.</h2>
<script>
var subframeOrigin = location.hash.substr(1); // e.g., "http://example.com"
var subframe = document.createElement("iframe");
subframe.src = subframeOrigin +
"/tests/dom/base/test/file_bug1091883_subframe.html";
document.body.appendChild(subframe);
</script>
</body>
</html>

View File

@ -0,0 +1,6 @@
<!DOCTYPE html>
<html>
<body>
<h3>Subframe I am.</h3>
</body>
</html>

View File

@ -0,0 +1,13 @@
<!DOCTYPE html>
<html>
<head>
<h3>Target I am.</h3>
<script>
var testRun = location.hash.substr(1);
parent.parent.postMessage(document.referrer + " " + testRun,
"http://mochi.test:8888");
</script>
</head>
<body>
</body>
</html>

View File

@ -100,6 +100,9 @@ support-files =
file_XHR_system_redirect.html^headers^
file_XHR_timeout.sjs
file_base_xbl.xml
file_bug1091883_frame.html
file_bug1091883_subframe.html
file_bug1091883_target.html
file_bug28293.sjs
file_bug326337.xml
file_bug326337_inner.html
@ -249,6 +252,7 @@ support-files =
[test_audioWindowUtils.html]
[test_audioNotification.html]
skip-if = buildapp == 'mulet'
[test_bug1091883.html]
[test_bug116083.html]
[test_bug793311.html]
[test_bug913761.html]

View File

@ -0,0 +1,89 @@
<!DOCTYPE html>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=1091883
-->
<head>
<meta charset="utf-8">
<meta name="referrer" content="origin-when-crossorigin">
<title>Test for Bug 1091883</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<p><a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1091883">Mozilla Bug 1091883</a></p>
<h2>Results</h2>
<pre id="results">Running...</pre>
<script>
SimpleTest.waitForExplicitFinish();
var origins = [
"http://mochi.test:8888", "http://example.com", "http://example.org"];
var numOrigins = origins.length;
// For each combination of (frame, subframe, target) origins, this test
// includes a "frame" that includes a "subframe"; and then this test
// navigates this "subframe" to the "target". Both the referrer and
// the triggering principal are this test, i.e., "http://mochi.test:8888".
// Since the referrer policy is origin-when-crossorigin, we expect to have
// a full referrer if and only if the target is also "http://mochi.test:8888";
// in all other cases, the referrer needs to be the origin alone.
var numTests = numOrigins * numOrigins * numOrigins;
// Helpers to look up the approriate origins for a given test number.
function getFrameOrigin(i) {
return origins[(i / (numOrigins * numOrigins)) | 0];
}
function getSubframeOrigin(i) {
return origins[((i / numOrigins) | 0) % 3];
}
function getTargetOrigin(i) {
return origins[i % 3];
}
// Create the frames, and tell them which subframes to load.
for (var i = 0; i < numTests; i++) {
var frame = document.createElement("iframe");
frame.src = getFrameOrigin(i) +
"/tests/dom/base/test/file_bug1091883_frame.html#" +
getSubframeOrigin(i);
document.body.appendChild(frame);
}
// Navigate all subframes to the target.
window.onload = function() {
for (var i = 0; i < numTests; i++) {
frames[i].frames[0].location = getTargetOrigin(i) +
"/tests/dom/base/test/file_bug1091883_target.html#" + i;
}
};
// Check referrer messages from the target.
var results = {};
function makeResultsKey(i) {
return i + ": " + getFrameOrigin(i) + " | " + getSubframeOrigin(i) + " -> " +
getTargetOrigin(i);
}
window.addEventListener("message", function(event) {
var out = event.data.split(" ");
var referrer = out[0];
var testRun = +out[1];
results[makeResultsKey(testRun)] = referrer;
if (event.origin == "http://mochi.test:8888") {
is(referrer,
"http://mochi.test:8888/tests/dom/base/test/test_bug1091883.html",
"must be full referrer");
} else {
is(referrer, "http://mochi.test:8888", "must be origin referrer");
}
if (Object.keys(results).length == numTests) {
document.getElementById("results").textContent =
JSON.stringify(results, null, 4);
SimpleTest.finish();
}
});
</script>
</body>
</html>

View File

@ -55,10 +55,10 @@ function runTest() {
scrollDown15PxWithPixelScrolling(scrollbox);
// wait for the next refresh driver run
window.mozRequestAnimationFrame(function() {
win.mozRequestAnimationFrame(function() {
// actually, wait for the next one before checking results, since
// scrolling might not be flushed until after this code has run
window.mozRequestAnimationFrame(function() {
win.mozRequestAnimationFrame(function() {
is(scrollbox.scrollTop, scrollTopBefore + 15,
"Pixel scrolling should have finished after one refresh driver iteration. " +
"We shouldn't be scrolling smoothly, even though the pref is set.");

View File

@ -1171,6 +1171,12 @@ nsresult HTMLMediaElement::LoadResource()
// Set the media element's CORS mode only when loading a resource
mCORSMode = AttrValueToCORSMode(GetParsedAttr(nsGkAtoms::crossorigin));
#ifdef MOZ_EME
if (mMediaKeys && !IsMediaStreamURI(mLoadingSrc)) {
return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
}
#endif
HTMLMediaElement* other = LookupMediaElementURITable(mLoadingSrc);
if (other && other->mDecoder) {
// Clone it.
@ -4381,6 +4387,11 @@ HTMLMediaElement::SetMediaKeys(mozilla::dom::MediaKeys* aMediaKeys,
mMediaKeys->Shutdown();
mMediaKeys = nullptr;
}
if (mDecoder && !mMediaSource) {
ShutdownDecoder();
promise->MaybeReject(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
return promise.forget();
}
mMediaKeys = aMediaKeys;
if (mMediaKeys) {

View File

@ -215,8 +215,8 @@ HTMLVideoElement::GetVideoPlaybackQuality()
if (mDecoder) {
MediaDecoder::FrameStatistics& stats = mDecoder->GetFrameStatistics();
totalFrames = stats.GetParsedFrames();
droppedFrames = totalFrames - stats.GetPresentedFrames();
corruptedFrames = totalFrames - stats.GetDecodedFrames();
droppedFrames = stats.GetDroppedFrames();
corruptedFrames = 0;
}
}

View File

@ -52,6 +52,7 @@ using struct mozilla::layers::TextureFactoryIdentifier from "mozilla/layers/Comp
using mozilla::CSSPoint from "Units.h";
using mozilla::CSSToScreenScale from "Units.h";
using mozilla::CommandInt from "mozilla/EventForwards.h";
using mozilla::Modifiers from "mozilla/EventForwards.h";
using mozilla::layers::GeckoContentController::APZStateChange from "mozilla/layers/GeckoContentController.h";
using mozilla::WritingMode from "WritingModes.h";
@ -512,10 +513,10 @@ child:
// interface in gfx/layers/apz/public/GeckoContentController.h. Refer to documentation
// in that file for these functions.
AcknowledgeScrollUpdate(ViewID aScrollId, uint32_t aScrollGeneration);
HandleDoubleTap(CSSPoint point, ScrollableLayerGuid aGuid);
HandleSingleTap(CSSPoint point, ScrollableLayerGuid aGuid);
HandleLongTap(CSSPoint point, ScrollableLayerGuid aGuid, uint64_t aInputBlockId);
HandleLongTapUp(CSSPoint point, ScrollableLayerGuid aGuid);
HandleDoubleTap(CSSPoint aPoint, Modifiers aModifiers, ScrollableLayerGuid aGuid);
HandleSingleTap(CSSPoint aPoint, Modifiers aModifiers, ScrollableLayerGuid aGuid);
HandleLongTap(CSSPoint point, Modifiers aModifiers, ScrollableLayerGuid aGuid, uint64_t aInputBlockId);
HandleLongTapUp(CSSPoint point, Modifiers aModifiers, ScrollableLayerGuid aGuid);
NotifyAPZStateChange(ViewID aViewId, APZStateChange aChange, int aArg);

View File

@ -2046,7 +2046,7 @@ TabChild::RecvAcknowledgeScrollUpdate(const ViewID& aScrollId,
}
bool
TabChild::RecvHandleDoubleTap(const CSSPoint& aPoint, const ScrollableLayerGuid& aGuid)
TabChild::RecvHandleDoubleTap(const CSSPoint& aPoint, const Modifiers& aModifiers, const ScrollableLayerGuid& aGuid)
{
TABC_LOG("Handling double tap at %s with %p %p\n",
Stringify(aPoint).c_str(), mGlobal.get(), mTabChildGlobal.get());
@ -2055,6 +2055,8 @@ TabChild::RecvHandleDoubleTap(const CSSPoint& aPoint, const ScrollableLayerGuid&
return true;
}
// Note: there is nothing to do with the modifiers here, as we are not
// synthesizing any sort of mouse event.
CSSPoint point = APZCCallbackHelper::ApplyCallbackTransform(aPoint, aGuid,
GetPresShellResolution());
nsString data;
@ -2070,29 +2072,29 @@ TabChild::RecvHandleDoubleTap(const CSSPoint& aPoint, const ScrollableLayerGuid&
}
bool
TabChild::RecvHandleSingleTap(const CSSPoint& aPoint, const ScrollableLayerGuid& aGuid)
TabChild::RecvHandleSingleTap(const CSSPoint& aPoint, const Modifiers& aModifiers, const ScrollableLayerGuid& aGuid)
{
if (mGlobal && mTabChildGlobal) {
mAPZEventState->ProcessSingleTap(aPoint, aGuid, GetPresShellResolution());
mAPZEventState->ProcessSingleTap(aPoint, aModifiers, aGuid, GetPresShellResolution());
}
return true;
}
bool
TabChild::RecvHandleLongTap(const CSSPoint& aPoint, const ScrollableLayerGuid& aGuid, const uint64_t& aInputBlockId)
TabChild::RecvHandleLongTap(const CSSPoint& aPoint, const Modifiers& aModifiers, const ScrollableLayerGuid& aGuid, const uint64_t& aInputBlockId)
{
if (mGlobal && mTabChildGlobal) {
mAPZEventState->ProcessLongTap(GetDOMWindowUtils(), aPoint, aGuid,
mAPZEventState->ProcessLongTap(GetDOMWindowUtils(), aPoint, aModifiers, aGuid,
aInputBlockId, GetPresShellResolution());
}
return true;
}
bool
TabChild::RecvHandleLongTapUp(const CSSPoint& aPoint, const ScrollableLayerGuid& aGuid)
TabChild::RecvHandleLongTapUp(const CSSPoint& aPoint, const Modifiers& aModifiers, const ScrollableLayerGuid& aGuid)
{
if (mGlobal && mTabChildGlobal) {
mAPZEventState->ProcessLongTapUp(aPoint, aGuid, GetPresShellResolution());
mAPZEventState->ProcessLongTapUp(aPoint, aModifiers, aGuid, GetPresShellResolution());
}
return true;
}
@ -2269,9 +2271,9 @@ TabChild::UpdateTapState(const WidgetTouchEvent& aEvent, nsEventStatus aStatus)
case NS_TOUCH_END:
if (!TouchManager::gPreventMouseEvents) {
APZCCallbackHelper::DispatchSynthesizedMouseEvent(NS_MOUSE_MOVE, time, currentPoint, mWidget);
APZCCallbackHelper::DispatchSynthesizedMouseEvent(NS_MOUSE_BUTTON_DOWN, time, currentPoint, mWidget);
APZCCallbackHelper::DispatchSynthesizedMouseEvent(NS_MOUSE_BUTTON_UP, time, currentPoint, mWidget);
APZCCallbackHelper::DispatchSynthesizedMouseEvent(NS_MOUSE_MOVE, time, currentPoint, 0, mWidget);
APZCCallbackHelper::DispatchSynthesizedMouseEvent(NS_MOUSE_BUTTON_DOWN, time, currentPoint, 0, mWidget);
APZCCallbackHelper::DispatchSynthesizedMouseEvent(NS_MOUSE_BUTTON_UP, time, currentPoint, 0, mWidget);
}
// fall through
case NS_TOUCH_CANCEL:

View File

@ -322,13 +322,17 @@ public:
virtual bool RecvAcknowledgeScrollUpdate(const ViewID& aScrollId,
const uint32_t& aScrollGeneration) MOZ_OVERRIDE;
virtual bool RecvHandleDoubleTap(const CSSPoint& aPoint,
const Modifiers& aModifiers,
const mozilla::layers::ScrollableLayerGuid& aGuid) MOZ_OVERRIDE;
virtual bool RecvHandleSingleTap(const CSSPoint& aPoint,
const Modifiers& aModifiers,
const mozilla::layers::ScrollableLayerGuid& aGuid) MOZ_OVERRIDE;
virtual bool RecvHandleLongTap(const CSSPoint& aPoint,
const Modifiers& aModifiers,
const mozilla::layers::ScrollableLayerGuid& aGuid,
const uint64_t& aInputBlockId) MOZ_OVERRIDE;
virtual bool RecvHandleLongTapUp(const CSSPoint& aPoint,
const Modifiers& aModifiers,
const mozilla::layers::ScrollableLayerGuid& aGuid) MOZ_OVERRIDE;
virtual bool RecvNotifyAPZStateChange(const ViewID& aViewId,
const APZStateChange& aChange,

View File

@ -995,40 +995,39 @@ TabParent::AcknowledgeScrollUpdate(const ViewID& aScrollId, const uint32_t& aScr
}
void TabParent::HandleDoubleTap(const CSSPoint& aPoint,
int32_t aModifiers,
Modifiers aModifiers,
const ScrollableLayerGuid &aGuid)
{
if (!mIsDestroyed) {
unused << SendHandleDoubleTap(aPoint, aGuid);
unused << SendHandleDoubleTap(aPoint, aModifiers, aGuid);
}
}
void TabParent::HandleSingleTap(const CSSPoint& aPoint,
int32_t aModifiers,
Modifiers aModifiers,
const ScrollableLayerGuid &aGuid)
{
// TODO Send the modifier data to TabChild for use in mouse events.
if (!mIsDestroyed) {
unused << SendHandleSingleTap(aPoint, aGuid);
unused << SendHandleSingleTap(aPoint, aModifiers, aGuid);
}
}
void TabParent::HandleLongTap(const CSSPoint& aPoint,
int32_t aModifiers,
Modifiers aModifiers,
const ScrollableLayerGuid &aGuid,
uint64_t aInputBlockId)
{
if (!mIsDestroyed) {
unused << SendHandleLongTap(aPoint, aGuid, aInputBlockId);
unused << SendHandleLongTap(aPoint, aModifiers, aGuid, aInputBlockId);
}
}
void TabParent::HandleLongTapUp(const CSSPoint& aPoint,
int32_t aModifiers,
Modifiers aModifiers,
const ScrollableLayerGuid &aGuid)
{
if (!mIsDestroyed) {
unused << SendHandleLongTapUp(aPoint, aGuid);
unused << SendHandleLongTapUp(aPoint, aModifiers, aGuid);
}
}
@ -1239,40 +1238,40 @@ CSSPoint TabParent::AdjustTapToChildWidget(const CSSPoint& aPoint)
return aPoint + (LayoutDevicePoint(mChildProcessOffsetAtTouchStart) * GetLayoutDeviceToCSSScale());
}
bool TabParent::SendHandleSingleTap(const CSSPoint& aPoint, const ScrollableLayerGuid& aGuid)
bool TabParent::SendHandleSingleTap(const CSSPoint& aPoint, const Modifiers& aModifiers, const ScrollableLayerGuid& aGuid)
{
if (mIsDestroyed) {
return false;
}
return PBrowserParent::SendHandleSingleTap(AdjustTapToChildWidget(aPoint), aGuid);
return PBrowserParent::SendHandleSingleTap(AdjustTapToChildWidget(aPoint), aModifiers, aGuid);
}
bool TabParent::SendHandleLongTap(const CSSPoint& aPoint, const ScrollableLayerGuid& aGuid, const uint64_t& aInputBlockId)
bool TabParent::SendHandleLongTap(const CSSPoint& aPoint, const Modifiers& aModifiers, const ScrollableLayerGuid& aGuid, const uint64_t& aInputBlockId)
{
if (mIsDestroyed) {
return false;
}
return PBrowserParent::SendHandleLongTap(AdjustTapToChildWidget(aPoint), aGuid, aInputBlockId);
return PBrowserParent::SendHandleLongTap(AdjustTapToChildWidget(aPoint), aModifiers, aGuid, aInputBlockId);
}
bool TabParent::SendHandleLongTapUp(const CSSPoint& aPoint, const ScrollableLayerGuid& aGuid)
bool TabParent::SendHandleLongTapUp(const CSSPoint& aPoint, const Modifiers& aModifiers, const ScrollableLayerGuid& aGuid)
{
if (mIsDestroyed) {
return false;
}
return PBrowserParent::SendHandleLongTapUp(AdjustTapToChildWidget(aPoint), aGuid);
return PBrowserParent::SendHandleLongTapUp(AdjustTapToChildWidget(aPoint), aModifiers, aGuid);
}
bool TabParent::SendHandleDoubleTap(const CSSPoint& aPoint, const ScrollableLayerGuid& aGuid)
bool TabParent::SendHandleDoubleTap(const CSSPoint& aPoint, const Modifiers& aModifiers, const ScrollableLayerGuid& aGuid)
{
if (mIsDestroyed) {
return false;
}
return PBrowserParent::SendHandleDoubleTap(AdjustTapToChildWidget(aPoint), aGuid);
return PBrowserParent::SendHandleDoubleTap(AdjustTapToChildWidget(aPoint), aModifiers, aGuid);
}
bool TabParent::SendMouseWheelEvent(WidgetWheelEvent& event)
@ -1897,7 +1896,6 @@ TabParent::RecvDispatchAfterKeyboardEvent(const WidgetKeyboardEvent& aEvent)
if (mFrameElement &&
PresShell::BeforeAfterKeyboardEventEnabled() &&
localEvent.message != NS_KEY_PRESS) {
nsCOMPtr<nsINode> node(do_QueryInterface(mFrameElement));
presShell->DispatchAfterKeyboardEvent(mFrameElement, localEvent,
aEvent.mFlags.mDefaultPrevented);
}

View File

@ -251,17 +251,17 @@ public:
void UIResolutionChanged();
void AcknowledgeScrollUpdate(const ViewID& aScrollId, const uint32_t& aScrollGeneration);
void HandleDoubleTap(const CSSPoint& aPoint,
int32_t aModifiers,
Modifiers aModifiers,
const ScrollableLayerGuid& aGuid);
void HandleSingleTap(const CSSPoint& aPoint,
int32_t aModifiers,
Modifiers aModifiers,
const ScrollableLayerGuid& aGuid);
void HandleLongTap(const CSSPoint& aPoint,
int32_t aModifiers,
Modifiers aModifiers,
const ScrollableLayerGuid& aGuid,
uint64_t aInputBlockId);
void HandleLongTapUp(const CSSPoint& aPoint,
int32_t aModifiers,
Modifiers aModifiers,
const ScrollableLayerGuid& aGuid);
void NotifyAPZStateChange(ViewID aViewId,
APZStateChange aChange,
@ -287,10 +287,10 @@ public:
bool SendMouseWheelEvent(mozilla::WidgetWheelEvent& event);
bool SendRealKeyEvent(mozilla::WidgetKeyboardEvent& event);
bool SendRealTouchEvent(WidgetTouchEvent& event);
bool SendHandleSingleTap(const CSSPoint& aPoint, const ScrollableLayerGuid& aGuid);
bool SendHandleLongTap(const CSSPoint& aPoint, const ScrollableLayerGuid& aGuid, const uint64_t& aInputBlockId);
bool SendHandleLongTapUp(const CSSPoint& aPoint, const ScrollableLayerGuid& aGuid);
bool SendHandleDoubleTap(const CSSPoint& aPoint, const ScrollableLayerGuid& aGuid);
bool SendHandleSingleTap(const CSSPoint& aPoint, const Modifiers& aModifiers, const ScrollableLayerGuid& aGuid);
bool SendHandleLongTap(const CSSPoint& aPoint, const Modifiers& aModifiers, const ScrollableLayerGuid& aGuid, const uint64_t& aInputBlockId);
bool SendHandleLongTapUp(const CSSPoint& aPoint, const Modifiers& aModifiers, const ScrollableLayerGuid& aGuid);
bool SendHandleDoubleTap(const CSSPoint& aPoint, const Modifiers& aModifiers, const ScrollableLayerGuid& aGuid);
virtual PDocumentRendererParent*
AllocPDocumentRendererParent(const nsRect& documentRect,

View File

@ -61,9 +61,11 @@ public:
// from the resource.
virtual void NotifyBytesConsumed(int64_t aBytes, int64_t aOffset) = 0;
// Increments the parsed and decoded frame counters by the passed in counts.
// Increments the parsed, decoded and dropped frame counters by the passed in
// counts.
// Can be called on any thread.
virtual void NotifyDecodedFrames(uint32_t aParsed, uint32_t aDecoded) = 0;
virtual void NotifyDecodedFrames(uint32_t aParsed, uint32_t aDecoded,
uint32_t aDropped) = 0;
// Return the duration of the media in microseconds.
virtual int64_t GetMediaDuration() = 0;
@ -137,17 +139,19 @@ public:
// to ensure all parsed and decoded frames are reported on all return paths.
class AutoNotifyDecoded {
public:
AutoNotifyDecoded(AbstractMediaDecoder* aDecoder, uint32_t& aParsed, uint32_t& aDecoded)
: mDecoder(aDecoder), mParsed(aParsed), mDecoded(aDecoded) {}
explicit AutoNotifyDecoded(AbstractMediaDecoder* aDecoder)
: mParsed(0), mDecoded(0), mDropped(0), mDecoder(aDecoder) {}
~AutoNotifyDecoded() {
if (mDecoder) {
mDecoder->NotifyDecodedFrames(mParsed, mDecoded);
mDecoder->NotifyDecodedFrames(mParsed, mDecoded, mDropped);
}
}
uint32_t mParsed;
uint32_t mDecoded;
uint32_t mDropped;
private:
AbstractMediaDecoder* mDecoder;
uint32_t& mParsed;
uint32_t& mDecoded;
};
#ifdef MOZ_EME

View File

@ -937,7 +937,8 @@ public:
mReentrantMonitor("MediaDecoder::FrameStats"),
mParsedFrames(0),
mDecodedFrames(0),
mPresentedFrames(0) {}
mPresentedFrames(0),
mDroppedFrames(0) {}
// Returns number of frames which have been parsed from the media.
// Can be called on any thread.
@ -961,14 +962,22 @@ public:
return mPresentedFrames;
}
// Number of frames that have been skipped because they have missed their
// compoisition deadline.
uint32_t GetDroppedFrames() {
return mDroppedFrames;
}
// Increments the parsed and decoded frame counters by the passed in counts.
// Can be called on any thread.
void NotifyDecodedFrames(uint32_t aParsed, uint32_t aDecoded) {
if (aParsed == 0 && aDecoded == 0)
void NotifyDecodedFrames(uint32_t aParsed, uint32_t aDecoded,
uint32_t aDropped) {
if (aParsed == 0 && aDecoded == 0 && aDropped == 0)
return;
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
mParsedFrames += aParsed;
mDecodedFrames += aDecoded;
mDroppedFrames += aDropped;
}
// Increments the presented frame counters.
@ -994,6 +1003,8 @@ public:
// Number of decoded frames which were actually sent down the rendering
// pipeline to be painted ("presented"). Access protected by mReentrantMonitor.
uint32_t mPresentedFrames;
uint32_t mDroppedFrames;
};
// Return the frame decode/paint related statistics.
@ -1001,9 +1012,10 @@ public:
// Increments the parsed and decoded frame counters by the passed in counts.
// Can be called on any thread.
virtual void NotifyDecodedFrames(uint32_t aParsed, uint32_t aDecoded) MOZ_OVERRIDE
virtual void NotifyDecodedFrames(uint32_t aParsed, uint32_t aDecoded,
uint32_t aDropped) MOZ_OVERRIDE
{
GetFrameStatistics().NotifyDecodedFrames(aParsed, aDecoded);
GetFrameStatistics().NotifyDecodedFrames(aParsed, aDecoded, aDropped);
}
protected:

View File

@ -3155,12 +3155,13 @@ void MediaDecoderStateMachine::AdvanceFrame()
#endif
while (IsRealTime() || clock_time >= frame->mTime) {
mVideoFrameEndTime = frame->GetEndTime();
#ifdef PR_LOGGING
if (currentFrame) {
mDecoder->NotifyDecodedFrames(0, 0, 1);
#ifdef PR_LOGGING
VERBOSE_LOG("discarding video frame mTime=%lld clock_time=%lld (%d so far)",
currentFrame->mTime, clock_time, ++droppedFrames);
}
#endif
}
currentFrame = frame;
nsRefPtr<VideoData> releaseMe = VideoQueue().PopFront();
// Notify the decode thread that the video queue's buffers may have

62
dom/media/TimeUnits.h Normal file
View File

@ -0,0 +1,62 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef TIME_UNITS_H
#define TIME_UNITS_H
#include "VideoUtils.h"
#include "mozilla/FloatingPoint.h"
namespace mozilla {
namespace media {
struct Microseconds {
Microseconds()
: mValue(0)
{}
explicit Microseconds(int64_t aValue)
: mValue(aValue)
{}
double ToSeconds() {
return double(mValue) / USECS_PER_S;
}
static Microseconds FromSeconds(double aValue) {
MOZ_ASSERT(!IsNaN(aValue));
double val = aValue * USECS_PER_S;
if (val >= double(INT64_MAX)) {
return Microseconds(INT64_MAX);
} else if (val <= double(INT64_MIN)) {
return Microseconds(INT64_MIN);
} else {
return Microseconds(int64_t(val));
}
}
bool operator > (const Microseconds& aOther) const {
return mValue > aOther.mValue;
}
bool operator >= (const Microseconds& aOther) const {
return mValue >= aOther.mValue;
}
bool operator < (const Microseconds& aOther) const {
return mValue < aOther.mValue;
}
bool operator <= (const Microseconds& aOther) const {
return mValue <= aOther.mValue;
}
int64_t mValue;
};
}
}
#endif // TIME_UNITS_H

View File

@ -33,6 +33,10 @@ void VideoFrameContainer::SetCurrentFrame(const gfxIntSize& aIntrinsicSize,
Image* aImage,
TimeStamp aTargetTime)
{
if (aImage && !aImage->IsValid()) {
return;
}
MutexAutoLock lock(mMutex);
if (aIntrinsicSize != mIntrinsicSize) {

View File

@ -125,8 +125,7 @@ bool AndroidMediaReader::DecodeVideoFrame(bool &aKeyframeSkip,
{
// Record number of frames decoded and parsed. Automatically update the
// stats counters using the AutoNotifyDecoded stack-based class.
uint32_t parsed = 0, decoded = 0;
AbstractMediaDecoder::AutoNotifyDecoded autoNotify(mDecoder, parsed, decoded);
AbstractMediaDecoder::AutoNotifyDecoded a(mDecoder);
// Throw away the currently buffered frame if we are seeking.
if (mLastVideoFrame && mVideoSeekTimeUs != -1) {
@ -162,7 +161,8 @@ bool AndroidMediaReader::DecodeVideoFrame(bool &aKeyframeSkip,
// when a frame is a keyframe.
#if 0
if (!frame.mKeyFrame) {
++parsed;
++a.mParsed;
++a.mDropped;
continue;
}
#endif
@ -250,9 +250,9 @@ bool AndroidMediaReader::DecodeVideoFrame(bool &aKeyframeSkip,
if (!v) {
return false;
}
parsed++;
decoded++;
NS_ASSERTION(decoded <= parsed, "Expect to decode fewer frames than parsed in AndroidMedia...");
a.mParsed++;
a.mDecoded++;
NS_ASSERTION(a.mDecoded <= a.mParsed, "Expect to decode fewer frames than parsed in AndroidMedia...");
// Since MPAPI doesn't give us the end time of frames, we keep one frame
// buffered in AndroidMediaReader and push it into the queue as soon

View File

@ -598,7 +598,7 @@ MP4Reader::RequestVideoData(bool aSkipToNextKeyframe,
if (!eos && NS_FAILED(mVideo.mDecoder->Flush())) {
NS_WARNING("Failed to skip/flush video when skipping-to-next-keyframe.");
}
mDecoder->NotifyDecodedFrames(parsed, 0);
mDecoder->NotifyDecodedFrames(parsed, 0, parsed);
}
MonitorAutoLock lock(mVideo.mMonitor);
@ -672,8 +672,7 @@ MP4Reader::Update(TrackType aTrack)
// Record number of frames decoded and parsed. Automatically update the
// stats counters using the AutoNotifyDecoded stack-based class.
uint32_t parsed = 0, decoded = 0;
AbstractMediaDecoder::AutoNotifyDecoded autoNotify(mDecoder, parsed, decoded);
AbstractMediaDecoder::AutoNotifyDecoded a(mDecoder);
bool needInput = false;
bool needOutput = false;
@ -688,7 +687,7 @@ MP4Reader::Update(TrackType aTrack)
}
if (aTrack == kVideo) {
uint64_t delta = decoder.mNumSamplesOutput - mLastReportedNumDecodedFrames;
decoded = static_cast<uint32_t>(delta);
a.mDecoded = static_cast<uint32_t>(delta);
mLastReportedNumDecodedFrames = decoder.mNumSamplesOutput;
}
if (decoder.HasPromise()) {
@ -722,7 +721,7 @@ MP4Reader::Update(TrackType aTrack)
if (sample) {
decoder.mDecoder->Input(sample);
if (aTrack == kVideo) {
parsed++;
a.mParsed++;
}
} else {
{

View File

@ -251,7 +251,6 @@ WMFAudioMFTManager::Output(int64_t aStreamOffset,
// reset the frame counters, and capture the timestamp. Future timestamps
// will be offset from this block's timestamp.
UINT32 discontinuity = false;
int32_t numFramesToStrip = 0;
sample->GetUINT32(MFSampleExtension_Discontinuity, &discontinuity);
if (mMustRecaptureAudioPosition || discontinuity) {
// Update the output type, in case this segment has a different
@ -267,21 +266,11 @@ WMFAudioMFTManager::Output(int64_t aStreamOffset,
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
hr = HNsToFrames(timestampHns, mAudioRate, &mAudioFrameOffset);
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
if (mAudioFrameOffset < 0) {
// First sample has a negative timestamp. Strip off the samples until
// we reach positive territory.
numFramesToStrip = -mAudioFrameOffset;
mAudioFrameOffset = 0;
}
mMustRecaptureAudioPosition = false;
}
MOZ_ASSERT(numFramesToStrip >= 0);
// We can assume PCM 16 output.
int32_t numSamples = currentLength / 2;
int32_t numFrames = numSamples / mAudioChannels;
int32_t offset = std::min<int32_t>(numFramesToStrip, numFrames);
numFrames -= offset;
numSamples -= offset * mAudioChannels;
MOZ_ASSERT(numFrames >= 0);
MOZ_ASSERT(numSamples >= 0);
if (numFrames == 0) {
@ -292,10 +281,7 @@ WMFAudioMFTManager::Output(int64_t aStreamOffset,
nsAutoArrayPtr<AudioDataValue> audioData(new AudioDataValue[numSamples]);
int16_t* pcm = ((int16_t*)data) + (offset * mAudioChannels);
MOZ_ASSERT(pcm >= (int16_t*)data);
MOZ_ASSERT(pcm <= (int16_t*)(data + currentLength));
MOZ_ASSERT(pcm+numSamples <= (int16_t*)(data + currentLength));
int16_t* pcm = (int16_t*)data;
for (int32_t i = 0; i < numSamples; ++i) {
audioData[i] = AudioSampleToFloat(pcm[i]);
}

View File

@ -757,7 +757,7 @@ bool GStreamerReader::DecodeVideoFrame(bool &aKeyFrameSkip,
}
}
mDecoder->NotifyDecodedFrames(0, 1);
mDecoder->NotifyDecodedFrames(0, 1, 0);
#if GST_VERSION_MAJOR >= 1
GstSample *sample = gst_app_sink_pull_sample(mVideoAppSink);
@ -771,6 +771,7 @@ bool GStreamerReader::DecodeVideoFrame(bool &aKeyFrameSkip,
bool isKeyframe = !GST_BUFFER_FLAG_IS_SET(buffer, GST_BUFFER_FLAG_DELTA_UNIT);
if ((aKeyFrameSkip && !isKeyframe)) {
mDecoder->NotifyDecodedFrames(0, 0, 1);
gst_buffer_unref(buffer);
return true;
}
@ -1150,7 +1151,7 @@ void GStreamerReader::NewVideoBuffer()
* and notify the decode thread potentially blocked in DecodeVideoFrame
*/
mDecoder->NotifyDecodedFrames(1, 0);
mDecoder->NotifyDecodedFrames(1, 0, 0);
mVideoSinkBufferCount++;
mon.NotifyAll();
}

View File

@ -134,6 +134,7 @@ MediaSourceReader::RequestAudioData()
SwitchSourceResult ret = SwitchAudioSource(&mLastAudioTime);
switch (ret) {
case SOURCE_NEW:
GetAudioReader()->ResetDecode();
mAudioSeekRequest.Begin(GetAudioReader()->Seek(GetReaderAudioTime(mLastAudioTime), 0)
->RefableThen(GetTaskQueue(), __func__, this,
&MediaSourceReader::CompleteAudioSeekAndDoRequest,
@ -247,6 +248,7 @@ MediaSourceReader::OnAudioNotDecoded(NotDecodedReason aReason)
// See if we can find a different source that can pick up where we left off.
if (SwitchAudioSource(&mLastAudioTime) == SOURCE_NEW) {
GetAudioReader()->ResetDecode();
mAudioSeekRequest.Begin(GetAudioReader()->Seek(GetReaderAudioTime(mLastAudioTime), 0)
->RefableThen(GetTaskQueue(), __func__, this,
&MediaSourceReader::CompleteAudioSeekAndDoRequest,
@ -284,6 +286,7 @@ MediaSourceReader::RequestVideoData(bool aSkipToNextKeyframe, int64_t aTimeThres
SwitchSourceResult ret = SwitchVideoSource(&mLastVideoTime);
switch (ret) {
case SOURCE_NEW:
GetVideoReader()->ResetDecode();
mVideoSeekRequest.Begin(GetVideoReader()->Seek(GetReaderVideoTime(mLastVideoTime), 0)
->RefableThen(GetTaskQueue(), __func__, this,
&MediaSourceReader::CompleteVideoSeekAndDoRequest,
@ -374,6 +377,7 @@ MediaSourceReader::OnVideoNotDecoded(NotDecodedReason aReason)
// See if we can find a different reader that can pick up where we left off.
if (SwitchVideoSource(&mLastVideoTime) == SOURCE_NEW) {
GetVideoReader()->ResetDecode();
mVideoSeekRequest.Begin(GetVideoReader()->Seek(GetReaderVideoTime(mLastVideoTime), 0)
->RefableThen(GetTaskQueue(), __func__, this,
&MediaSourceReader::CompleteVideoSeekAndDoRequest,
@ -719,7 +723,7 @@ MediaSourceReader::NotifyTimeRangesChanged()
{
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
if (mWaitingForSeekData) {
//post a task to the state machine thread to call seek.
//post a task to the decode queue to try to complete the pending seek.
RefPtr<nsIRunnable> task(NS_NewRunnableMethod(
this, &MediaSourceReader::AttemptSeek));
GetTaskQueue()->Dispatch(task.forget());
@ -826,6 +830,7 @@ MediaSourceReader::DoAudioSeek()
mWaitingForSeekData = true;
return;
}
GetAudioReader()->ResetDecode();
mAudioSeekRequest.Begin(GetAudioReader()->Seek(GetReaderAudioTime(mPendingSeekTime), 0)
->RefableThen(GetTaskQueue(), __func__, this,
&MediaSourceReader::OnAudioSeekCompleted,
@ -869,11 +874,6 @@ MediaSourceReader::AttemptSeek()
mWaitingForSeekData = false;
}
ResetDecode();
for (uint32_t i = 0; i < mTrackBuffers.Length(); ++i) {
mTrackBuffers[i]->ResetDecode();
}
// Decoding discontinuity upon seek, reset last times to seek target.
mLastAudioTime = mPendingSeekTime;
mLastVideoTime = mPendingSeekTime;
@ -896,6 +896,7 @@ MediaSourceReader::DoVideoSeek()
mWaitingForSeekData = true;
return;
}
GetVideoReader()->ResetDecode();
mVideoSeekRequest.Begin(GetVideoReader()->Seek(GetReaderVideoTime(mPendingSeekTime), 0)
->RefableThen(GetTaskQueue(), __func__, this,
&MediaSourceReader::OnVideoSeekCompleted,

View File

@ -21,6 +21,7 @@
#include "nsThreadUtils.h"
#include "prlog.h"
#include <time.h>
#include "TimeUnits.h"
struct JSContext;
class JSObject;
@ -286,9 +287,8 @@ SourceBuffer::DoRangeRemoval(double aStart, double aEnd)
{
MSE_DEBUG("DoRangeRemoval(%f, %f)", aStart, aEnd);
if (mTrackBuffer && !IsInfinite(aStart)) {
int64_t start = aStart * USECS_PER_S;
int64_t end = IsInfinite(aEnd) ? INT64_MAX : (int64_t)(aEnd * USECS_PER_S);
mTrackBuffer->RangeRemoval(start, end);
mTrackBuffer->RangeRemoval(media::Microseconds::FromSeconds(aStart),
media::Microseconds::FromSeconds(aEnd));
}
}

View File

@ -13,8 +13,12 @@
#ifdef PR_LOGGING
extern PRLogModuleInfo* GetMediaSourceLog();
/* Polyfill __func__ on MSVC to pass to the log. */
#ifdef _MSC_VER
#define __func__ __FUNCTION__
#endif
#define MSE_DEBUG(arg, ...) PR_LOG(GetMediaSourceLog(), PR_LOG_DEBUG, (TOSTRING(name) "SourceBufferDecoder(%p:%s)::%s: " arg, this, mResource->GetContentType().get(), __func__, ##__VA_ARGS__))
#define MSE_DEBUG(arg, ...) PR_LOG(GetMediaSourceLog(), PR_LOG_DEBUG, ("SourceBufferDecoder(%p:%s)::%s: " arg, this, mResource->GetContentType().get(), __func__, ##__VA_ARGS__))
#else
#define MSE_DEBUG(...)
#endif
@ -180,9 +184,10 @@ SourceBufferDecoder::GetResource() const
}
void
SourceBufferDecoder::NotifyDecodedFrames(uint32_t aParsed, uint32_t aDecoded)
SourceBufferDecoder::NotifyDecodedFrames(uint32_t aParsed, uint32_t aDecoded,
uint32_t aDropped)
{
return mParentDecoder->NotifyDecodedFrames(aParsed, aDecoded);
return mParentDecoder->NotifyDecodedFrames(aParsed, aDecoded, aDropped);
}
void

View File

@ -52,7 +52,7 @@ public:
virtual void FirstFrameLoaded(nsAutoPtr<MediaInfo> aInfo, bool aRestoredFromDormant) MOZ_FINAL MOZ_OVERRIDE;
virtual void NotifyBytesConsumed(int64_t aBytes, int64_t aOffset) MOZ_FINAL MOZ_OVERRIDE;
virtual void NotifyDataArrived(const char* aBuffer, uint32_t aLength, int64_t aOffset) MOZ_FINAL MOZ_OVERRIDE;
virtual void NotifyDecodedFrames(uint32_t aParsed, uint32_t aDecoded) MOZ_FINAL MOZ_OVERRIDE;
virtual void NotifyDecodedFrames(uint32_t aParsed, uint32_t aDecoded, uint32_t aDropped) MOZ_FINAL MOZ_OVERRIDE;
virtual void NotifyWaitingForResourcesStatusChanged() MOZ_FINAL MOZ_OVERRIDE;
virtual void OnReadMetadataCompleted() MOZ_FINAL MOZ_OVERRIDE;
virtual void QueueMetadata(int64_t aTime, nsAutoPtr<MediaInfo> aInfo, nsAutoPtr<MetadataTags> aTags) MOZ_FINAL MOZ_OVERRIDE;

View File

@ -839,14 +839,6 @@ TrackBuffer::BreakCycles()
MOZ_ASSERT(!mParentDecoder);
}
void
TrackBuffer::ResetDecode()
{
for (uint32_t i = 0; i < mDecoders.Length(); ++i) {
mDecoders[i]->GetReader()->ResetDecode();
}
}
void
TrackBuffer::ResetParserState()
{
@ -979,16 +971,17 @@ TrackBuffer::RemoveDecoder(SourceBufferDecoder* aDecoder)
}
bool
TrackBuffer::RangeRemoval(int64_t aStart, int64_t aEnd)
TrackBuffer::RangeRemoval(media::Microseconds aStart,
media::Microseconds aEnd)
{
MOZ_ASSERT(NS_IsMainThread());
ReentrantMonitorAutoEnter mon(mParentDecoder->GetReentrantMonitor());
nsRefPtr<dom::TimeRanges> buffered = new dom::TimeRanges();
int64_t bufferedEnd = Buffered(buffered) * USECS_PER_S;
int64_t bufferedStart = buffered->GetStartTime() * USECS_PER_S;
media::Microseconds bufferedEnd = media::Microseconds::FromSeconds(Buffered(buffered));
media::Microseconds bufferedStart = media::Microseconds::FromSeconds(buffered->GetStartTime());
if (bufferedStart < 0 || aStart > bufferedEnd || aEnd < bufferedStart) {
if (bufferedStart < media::Microseconds(0) || aStart > bufferedEnd || aEnd < bufferedStart) {
// Nothing to remove.
return false;
}
@ -1008,14 +1001,14 @@ TrackBuffer::RangeRemoval(int64_t aStart, int64_t aEnd)
for (size_t i = 0; i < decoders.Length(); ++i) {
nsRefPtr<dom::TimeRanges> buffered = new dom::TimeRanges();
decoders[i]->GetBuffered(buffered);
if (int64_t(buffered->GetEndTime() * USECS_PER_S) < aEnd) {
if (media::Microseconds::FromSeconds(buffered->GetEndTime()) < aEnd) {
// Can be fully removed.
MSE_DEBUG("remove all bufferedEnd=%f time=%f, size=%lld",
buffered->GetEndTime(), time,
decoders[i]->GetResource()->GetSize());
decoders[i]->GetResource()->EvictAll();
} else {
int64_t offset = decoders[i]->ConvertToByteOffset(aEnd);
int64_t offset = decoders[i]->ConvertToByteOffset(aEnd.ToSeconds());
MSE_DEBUG("removing some bufferedEnd=%f offset=%lld size=%lld",
buffered->GetEndTime(), offset,
decoders[i]->GetResource()->GetSize());
@ -1027,11 +1020,11 @@ TrackBuffer::RangeRemoval(int64_t aStart, int64_t aEnd)
} else {
// Only trimming existing buffers.
for (size_t i = 0; i < decoders.Length(); ++i) {
if (aStart <= int64_t(buffered->GetStartTime() * USECS_PER_S)) {
if (aStart <= media::Microseconds::FromSeconds(buffered->GetStartTime())) {
// It will be entirely emptied, can clear all data.
decoders[i]->GetResource()->EvictAll();
} else {
decoders[i]->Trim(aStart);
decoders[i]->Trim(aStart.mValue);
}
}
}

View File

@ -16,6 +16,7 @@
#include "nsCOMPtr.h"
#include "nsString.h"
#include "nscore.h"
#include "TimeUnits.h"
namespace mozilla {
@ -81,9 +82,6 @@ public:
void BreakCycles();
// Call ResetDecode() on each decoder in mDecoders.
void ResetDecode();
// Run MSE Reset Parser State Algorithm.
// 3.5.2 Reset Parser State
// http://w3c.github.io/media-source/#sourcebuffer-reset-parser-state
@ -99,7 +97,8 @@ public:
// Implementation is only partial, we can only trim a buffer.
// Returns true if data was evicted.
// Times are in microseconds.
bool RangeRemoval(int64_t aStart, int64_t aEnd);
bool RangeRemoval(mozilla::media::Microseconds aStart,
mozilla::media::Microseconds aEnd);
// Abort any pending appendBuffer by rejecting any pending promises.
void AbortAppendData();

View File

@ -122,6 +122,7 @@ EXPORTS += [
'SharedThreadPool.h',
'StreamBuffer.h',
'ThreadPoolCOMListener.h',
'TimeUnits.h',
'TimeVarying.h',
'TrackUnionStream.h',
'VideoFrameContainer.h',

View File

@ -899,8 +899,7 @@ bool OggReader::DecodeVideoFrame(bool &aKeyframeSkip,
// Record number of frames decoded and parsed. Automatically update the
// stats counters using the AutoNotifyDecoded stack-based class.
uint32_t parsed = 0, decoded = 0;
AbstractMediaDecoder::AutoNotifyDecoded autoNotify(mDecoder, parsed, decoded);
AbstractMediaDecoder::AutoNotifyDecoded a(mDecoder);
// Read the next data packet. Skip any non-data packets we encounter.
ogg_packet* packet = 0;
@ -915,7 +914,7 @@ bool OggReader::DecodeVideoFrame(bool &aKeyframeSkip,
}
nsAutoRef<ogg_packet> autoRelease(packet);
parsed++;
a.mParsed++;
NS_ASSERTION(packet && packet->granulepos != -1,
"Must know first packet's granulepos");
bool eos = packet->e_o_s;
@ -925,7 +924,7 @@ bool OggReader::DecodeVideoFrame(bool &aKeyframeSkip,
{
aKeyframeSkip = false;
nsresult res = DecodeTheora(packet, aTimeThreshold);
decoded++;
a.mDecoded++;
if (NS_FAILED(res)) {
return false;
}

View File

@ -35,10 +35,10 @@ extern PRLogModuleInfo* gMediaDecoderLog;
#define DECODER_LOG(type, msg)
#endif
class OmxReaderProcessCachedDataTask : public Task
class MediaOmxReader::ProcessCachedDataTask : public Task
{
public:
OmxReaderProcessCachedDataTask(MediaOmxReader* aOmxReader, int64_t aOffset)
ProcessCachedDataTask(MediaOmxReader* aOmxReader, int64_t aOffset)
: mOmxReader(aOmxReader),
mOffset(aOffset)
{ }
@ -70,10 +70,10 @@ private:
// the IO task dispatches a runnable to the main thread for parsing the
// data. This goes on until all of the MP3 file has been parsed.
class OmxReaderNotifyDataArrivedRunnable : public nsRunnable
class MediaOmxReader::NotifyDataArrivedRunnable : public nsRunnable
{
public:
OmxReaderNotifyDataArrivedRunnable(MediaOmxReader* aOmxReader,
NotifyDataArrivedRunnable(MediaOmxReader* aOmxReader,
const char* aBuffer, uint64_t aLength,
int64_t aOffset, uint64_t aFullLength)
: mOmxReader(aOmxReader),
@ -117,7 +117,7 @@ private:
// might block for too long. Instead we post an IO task
// to the IO thread if there is more data available.
XRE_GetIOMessageLoop()->PostTask(FROM_HERE,
new OmxReaderProcessCachedDataTask(mOmxReader.get(), mOffset));
new ProcessCachedDataTask(mOmxReader.get(), mOffset));
}
}
@ -128,16 +128,9 @@ private:
uint64_t mFullLength;
};
void MediaOmxReader::CancelProcessCachedData()
{
MOZ_ASSERT(NS_IsMainThread());
MutexAutoLock lock(mMutex);
mIsShutdown = true;
}
MediaOmxReader::MediaOmxReader(AbstractMediaDecoder *aDecoder)
: MediaOmxCommonReader(aDecoder)
, mMutex("MediaOmxReader.Data")
, mShutdownMutex("MediaOmxReader.Shutdown")
, mHasVideo(false)
, mHasAudio(false)
, mVideoSeekTimeUs(-1)
@ -167,6 +160,16 @@ nsresult MediaOmxReader::Init(MediaDecoderReader* aCloneDonor)
return NS_OK;
}
already_AddRefed<AbstractMediaDecoder>
MediaOmxReader::SafeGetDecoder() {
nsRefPtr<AbstractMediaDecoder> decoder;
MutexAutoLock lock(mShutdownMutex);
if (!mIsShutdown) {
decoder = mDecoder;
}
return decoder.forget();
}
void MediaOmxReader::ReleaseDecoder()
{
if (mOmxDecoder.get()) {
@ -178,9 +181,10 @@ void MediaOmxReader::ReleaseDecoder()
nsRefPtr<ShutdownPromise>
MediaOmxReader::Shutdown()
{
nsCOMPtr<nsIRunnable> cancelEvent =
NS_NewRunnableMethod(this, &MediaOmxReader::CancelProcessCachedData);
NS_DispatchToMainThread(cancelEvent);
{
MutexAutoLock lock(mShutdownMutex);
mIsShutdown = true;
}
nsRefPtr<ShutdownPromise> p = MediaDecoderReader::Shutdown();
@ -366,8 +370,7 @@ bool MediaOmxReader::DecodeVideoFrame(bool &aKeyframeSkip,
// Record number of frames decoded and parsed. Automatically update the
// stats counters using the AutoNotifyDecoded stack-based class.
uint32_t parsed = 0, decoded = 0;
AbstractMediaDecoder::AutoNotifyDecoded autoNotify(mDecoder, parsed, decoded);
AbstractMediaDecoder::AutoNotifyDecoded a(mDecoder);
bool doSeek = mVideoSeekTimeUs != -1;
if (doSeek) {
@ -392,7 +395,7 @@ bool MediaOmxReader::DecodeVideoFrame(bool &aKeyframeSkip,
continue;
}
parsed++;
a.mParsed++;
if (frame.mShouldSkip && mSkipCount < MAX_DROPPED_FRAMES) {
mSkipCount++;
continue;
@ -469,8 +472,8 @@ bool MediaOmxReader::DecodeVideoFrame(bool &aKeyframeSkip,
return false;
}
decoded++;
NS_ASSERTION(decoded <= parsed, "Expect to decode fewer frames than parsed in OMX decoder...");
a.mDecoded++;
NS_ASSERTION(a.mDecoded <= a.mParsed, "Expect to decode fewer frames than parsed in OMX decoder...");
mVideoQueue.Push(v);
@ -483,7 +486,8 @@ bool MediaOmxReader::DecodeVideoFrame(bool &aKeyframeSkip,
void MediaOmxReader::NotifyDataArrived(const char* aBuffer, uint32_t aLength, int64_t aOffset)
{
MOZ_ASSERT(NS_IsMainThread());
if (IsShutdown()) {
nsRefPtr<AbstractMediaDecoder> decoder = SafeGetDecoder();
if (!decoder) { // reader has shut down
return;
}
if (HasVideo()) {
@ -496,10 +500,10 @@ void MediaOmxReader::NotifyDataArrived(const char* aBuffer, uint32_t aLength, in
mMP3FrameParser.Parse(aBuffer, aLength, aOffset);
int64_t duration = mMP3FrameParser.GetDuration();
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
ReentrantMonitorAutoEnter mon(decoder->GetReentrantMonitor());
if (duration != mLastParserDuration && mUseParserDuration) {
mLastParserDuration = duration;
mDecoder->UpdateEstimatedMediaDuration(mLastParserDuration);
decoder->UpdateEstimatedMediaDuration(mLastParserDuration);
}
}
@ -585,7 +589,8 @@ void MediaOmxReader::EnsureActive() {
int64_t MediaOmxReader::ProcessCachedData(int64_t aOffset, bool aWaitForCompletion)
{
// Could run on decoder thread or IO thread.
if (IsShutdown()) {
nsRefPtr<AbstractMediaDecoder> decoder = SafeGetDecoder();
if (!decoder) { // reader has shut down
return -1;
}
// We read data in chunks of 32 KiB. We can reduce this
@ -596,8 +601,8 @@ int64_t MediaOmxReader::ProcessCachedData(int64_t aOffset, bool aWaitForCompleti
NS_ASSERTION(!NS_IsMainThread(), "Should not be on main thread.");
MOZ_ASSERT(mDecoder->GetResource());
int64_t resourceLength = mDecoder->GetResource()->GetCachedDataEnd(0);
MOZ_ASSERT(decoder->GetResource());
int64_t resourceLength = decoder->GetResource()->GetCachedDataEnd(0);
NS_ENSURE_TRUE(resourceLength >= 0, -1);
if (aOffset >= resourceLength) {
@ -608,16 +613,13 @@ int64_t MediaOmxReader::ProcessCachedData(int64_t aOffset, bool aWaitForCompleti
nsAutoArrayPtr<char> buffer(new char[bufferLength]);
nsresult rv = mDecoder->GetResource()->ReadFromCache(buffer.get(),
nsresult rv = decoder->GetResource()->ReadFromCache(buffer.get(),
aOffset, bufferLength);
NS_ENSURE_SUCCESS(rv, -1);
nsRefPtr<OmxReaderNotifyDataArrivedRunnable> runnable(
new OmxReaderNotifyDataArrivedRunnable(this,
buffer.forget(),
bufferLength,
aOffset,
resourceLength));
nsRefPtr<NotifyDataArrivedRunnable> runnable(
new NotifyDataArrivedRunnable(this, buffer.forget(), bufferLength,
aOffset, resourceLength));
if (aWaitForCompletion) {
rv = NS_DispatchToMainThread(runnable.get(), NS_DISPATCH_SYNC);
} else {

View File

@ -30,8 +30,9 @@ class AbstractMediaDecoder;
class MediaOmxReader : public MediaOmxCommonReader
{
// This flag protect the mIsShutdown variable, that may access by decoder / main / IO thread.
Mutex mMutex;
// This mutex is held when accessing the mIsShutdown variable, which is
// modified on the decode task queue and read on main and IO threads.
Mutex mShutdownMutex;
nsCString mType;
bool mHasVideo;
bool mHasAudio;
@ -42,6 +43,8 @@ class MediaOmxReader : public MediaOmxCommonReader
int64_t mLastParserDuration;
int32_t mSkipCount;
bool mUseParserDuration;
// If mIsShutdown is false, and mShutdownMutex is held, then
// AbstractMediaDecoder::mDecoder will be non-null.
bool mIsShutdown;
protected:
android::sp<android::OmxDecoder> mOmxDecoder;
@ -107,18 +110,24 @@ public:
virtual nsRefPtr<ShutdownPromise> Shutdown() MOZ_OVERRIDE;
android::sp<android::MediaSource> GetAudioOffloadTrack();
// This method is intended only for private use but public only for
// MediaPromise::InvokeCallbackMethod().
void ReleaseDecoder();
private:
class ProcessCachedDataTask;
class NotifyDataArrivedRunnable;
bool IsShutdown() {
MutexAutoLock lock(mMutex);
MutexAutoLock lock(mShutdownMutex);
return mIsShutdown;
}
void ReleaseDecoder();
int64_t ProcessCachedData(int64_t aOffset, bool aWaitForCompletion);
void CancelProcessCachedData();
android::sp<android::MediaSource> GetAudioOffloadTrack();
already_AddRefed<AbstractMediaDecoder> SafeGetDecoder();
};
} // namespace mozilla

View File

@ -215,8 +215,6 @@ public:
// Called on ALooper thread.
void onMessageReceived(const sp<AMessage> &msg);
int64_t ProcessCachedData(int64_t aOffset, bool aWaitForCompletion);
sp<MediaSource> GetAudioOffloadTrack() { return mAudioOffloadTrack; }
void RecycleCallbackImp(TextureClient* aClient);

View File

@ -157,8 +157,7 @@ bool RawReader::DecodeVideoFrame(bool &aKeyframeSkip,
// Record number of frames decoded and parsed. Automatically update the
// stats counters using the AutoNotifyDecoded stack-based class.
uint32_t parsed = 0, decoded = 0;
AbstractMediaDecoder::AutoNotifyDecoded autoNotify(mDecoder, parsed, decoded);
AbstractMediaDecoder::AutoNotifyDecoded a(mDecoder);
if (!mFrameSize)
return false; // Metadata read failed. We should refuse to play.
@ -185,7 +184,7 @@ bool RawReader::DecodeVideoFrame(bool &aKeyframeSkip,
return false;
}
parsed++;
a.mParsed++;
if (currentFrameTime >= aTimeThreshold)
break;
@ -229,7 +228,7 @@ bool RawReader::DecodeVideoFrame(bool &aKeyframeSkip,
mVideoQueue.Push(v);
mCurrentFrame++;
decoded++;
a.mDecoded++;
currentFrameTime += USECS_PER_S / mFrameRate;
return true;

View File

@ -129,6 +129,11 @@ function MaybeCrossOriginURI(test, uri)
function PlayFragmented(test, elem, token)
{
if (!test.fragments) {
ok(false, token + " test does not have a fragments list");
return Promise.reject();
}
return new Promise(function(resolve, reject) {
var ms = new MediaSource();
elem.src = URL.createObjectURL(ms);
@ -181,22 +186,6 @@ function PlayFragmented(test, elem, token)
});
}
// Returns a promise that is resovled when the media element is ready to have
// its play() function called; when it's loaded MSE fragments, or once the load
// has started for non-MSE video.
function LoadTest(test, elem, token)
{
if (test.fragments) {
return PlayFragmented(test, elem, token);
}
// This file isn't fragmented; set the media source normally.
return new Promise(function(resolve, reject) {
elem.src = MaybeCrossOriginURI(test, test.name);
resolve();
});
}
function SetupEME(test, token, params)
{
var v = document.createElement("video");

View File

@ -672,6 +672,14 @@ var gEMETests = [
},
];
var gEMENonFragmentedTests = [
{
name:"short-cenc.mp4",
type:"video/mp4; codecs=\"avc1.64000d,mp4a.40.2\"",
duration:0.47,
},
];
function checkMetadata(msg, e, test) {
if (test.width) {
is(e.videoWidth, test.width, msg + " video width");

View File

@ -231,6 +231,7 @@ support-files =
seek_support.js
seekLies.sjs
seek_with_sound.ogg^headers^
short-cenc.mp4
sine.webm
sine.webm^headers^
short-video.ogv
@ -367,6 +368,8 @@ skip-if = buildapp == 'b2g' && toolkit != 'gonk' # bug 1082984
skip-if = buildapp == 'b2g' || toolkit == 'android' || e10s # bug 1043403, bug 1057908
[test_eme_canvas_blocked.html]
skip-if = buildapp == 'b2g' || toolkit == 'android' || e10s # bug 1043403, bug 1057908
[test_eme_non_fragmented.html]
skip-if = buildapp == 'b2g' || toolkit == 'android' || e10s # bug 1043403, bug 1057908
[test_eme_obs_notification.html]
skip-if = buildapp == 'b2g' || toolkit == 'android' || e10s # bug 1043403, bug 1057908
[test_eme_persistent_sessions.html]

Binary file not shown.

View File

@ -0,0 +1,37 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
This XML file describes the encryption applied to short-cenc.mp4. To generate
short-cenc, run the following command:
MP4Box -crypt short-cenc.xml -out short-cenc.mp4 short.mp4
-->
<GPACDRM type="CENC AES-CTR">
<DRMInfo type="pssh" version="1">
<!--
SystemID specified in
https://dvcs.w3.org/hg/html-media/raw-file/tip/encrypted-media/cenc-format.html
-->
<BS ID128="1077efecc0b24d02ace33c1e52e2fb4b" />
<!-- Number of KeyIDs = 2 -->
<BS bits="32" value="2" />
<!-- KeyID -->
<BS ID128="0x7e571d017e571d017e571d017e571d01" />
<BS ID128="0x7e571d027e571d027e571d027e571d02" />
</DRMInfo>
<CrypTrack trackID="1" isEncrypted="1" IV_size="16" saiSavedBox="senc"
first_IV="0x00000000000000000000000000000000">
<key KID="0x7e571d017e571d017e571d017e571d01"
value="0x7e5711117e5711117e5711117e571111" />
</CrypTrack>
<CrypTrack trackID="2" isEncrypted="1" IV_size="16" saiSavedBox="senc"
first_IV="0x00000000000000000000000000000000">
<key KID="0x7e571d027e571d027e571d027e571d02"
value="0x7e5722227e5722227e5722227e572222" />
</CrypTrack>
</GPACDRM>

View File

@ -38,7 +38,7 @@ function startTest(test, token)
manager.finished(token);
});
LoadTest(test, v, token);
PlayFragmented(test, v, token);
}
function beginTest() {

View File

@ -0,0 +1,109 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Bug 1131392 - Test that EME does not work for non-MSE media</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
<script type="text/javascript" src="manifest.js"></script>
<script type="text/javascript" src="eme.js"></script>
</head>
<body>
<pre id="test">
<script class="testbody" type="text/javascript">
var manager = new MediaTestManager;
function DoSetMediaKeys(v)
{
var options = [{
initDataType: "cenc",
videoType: test.type,
}];
return navigator.requestMediaKeySystemAccess("org.w3.clearkey", options)
.then(function(keySystemAccess) {
return keySystemAccess.createMediaKeys();
})
.catch(function() {
ok(false, token + " was not expecting failure (yet)");
})
.then(function(mediaKeys) {
return v.setMediaKeys(mediaKeys);
});
}
function TestSetMediaKeys(test, token)
{
manager.started(token);
var v = document.createElement("video");
// XXX the encrypted event should never fire here after bug 1134434
v.addEventListener("encrypted", function() {
DoSetMediaKeys(v)
.then(function() {
ok(false, token + " expected setMediaKeys to fail.");
manager.finished(token);
}, function(err) {
is(err.name, "NotSupportedError", token + " should return correct error");
manager.finished(token);
});
});
v.src = test.name;
}
function TestSetSrc(test, token)
{
manager.started(token);
var v = document.createElement("video");
v.addEventListener("error", function(err) {
ok(true, token + " got error setting src on video element, as expected");
manager.finished(token);
});
DoSetMediaKeys(v)
.then(function() {
v.src = test.name;
})
.catch(function() {
ok(false, token + " got error setting media keys");
});
}
function startTest(test, token)
{
TestSetMediaKeys(test, token + "_setMediaKeys");
TestSetSrc(test, token + "_setSrc");
}
function beginTest() {
manager.runTests(gEMENonFragmentedTests, startTest);
}
var prefs = [
[ "media.mediasource.enabled", true ],
[ "media.mediasource.youtubeonly", false ],
[ "media.mediasource.mp4.enabled", true ],
];
if (/Linux/.test(navigator.userAgent) ||
!document.createElement('video').canPlayType("video/mp4")) {
// XXX remove once we have mp4 PlatformDecoderModules on all platforms.
prefs.push([ "media.fragmented-mp4.exposed", true ]);
prefs.push([ "media.fragmented-mp4.use-blank-decoder", true ]);
}
SimpleTest.waitForExplicitFinish();
SpecialPowers.pushPrefEnv({ "set" : prefs }, beginTest);
</script>
</pre>
</body>
</html>

View File

@ -52,7 +52,7 @@ function startTest(test, token)
manager.finished(token);
});
LoadTest(test, v, token);
PlayFragmented(test, v, token);
}
function beginTest() {

View File

@ -147,7 +147,7 @@ function startTest(test, token)
}
);
LoadTest(test, v, token);
PlayFragmented(test, v, token);
}
function beginTest() {

View File

@ -86,9 +86,9 @@ function startTest(test, token)
}
manager.finished(token);
});
});
LoadTest(test, v, token)
PlayFragmented(test, v, token)
.then(function() {
v.play();
}).catch(function() {

View File

@ -32,7 +32,7 @@ function startTest(test, token)
ok(false, TimeStamp(case1token) + " should never reach loadeddata, as setMediaKeys should fail");
});
manager.started(case1token);
LoadTest(test, v1, case1token);
PlayFragmented(test, v1, case1token);
// Case 2. creating a MediaElementSource on a media element with a MediaKeys should fail.
@ -51,7 +51,7 @@ function startTest(test, token)
manager.finished(case2token);
});
manager.started(case2token);
LoadTest(test, v2, case2token);
PlayFragmented(test, v2, case2token);
// Case 3. capturing a media element with mozCaptureStream that has a MediaKeys should fail.
@ -69,7 +69,7 @@ function startTest(test, token)
manager.finished(case3token);
});
manager.started(case3token);
LoadTest(test, v3, case3token);
PlayFragmented(test, v3, case3token);
}
function beginTest() {

View File

@ -83,7 +83,8 @@ BufferDecoder::NotifyBytesConsumed(int64_t aBytes, int64_t aOffset)
}
void
BufferDecoder::NotifyDecodedFrames(uint32_t aParsed, uint32_t aDecoded)
BufferDecoder::NotifyDecodedFrames(uint32_t aParsed, uint32_t aDecoded,
uint32_t aDropped)
{
// ignore
}

View File

@ -42,7 +42,8 @@ public:
virtual void NotifyBytesConsumed(int64_t aBytes, int64_t aOffset) MOZ_FINAL MOZ_OVERRIDE;
virtual void NotifyDecodedFrames(uint32_t aParsed, uint32_t aDecoded) MOZ_FINAL MOZ_OVERRIDE;
virtual void NotifyDecodedFrames(uint32_t aParsed, uint32_t aDecoded,
uint32_t aDropped) MOZ_FINAL MOZ_OVERRIDE;
virtual int64_t GetMediaDuration() MOZ_FINAL MOZ_OVERRIDE;

View File

@ -337,17 +337,17 @@ bool
IntelWebMVideoDecoder::DecodeVideoFrame(bool& aKeyframeSkip,
int64_t aTimeThreshold)
{
uint32_t parsed = 0, decoded = 0;
AbstractMediaDecoder::AutoNotifyDecoded autoNotify(mReader->GetDecoder(), parsed, decoded);
AbstractMediaDecoder::AutoNotifyDecoded a(mReader->GetDecoder());
MOZ_ASSERT(mPlatform && mReader->GetDecoder());
if (aKeyframeSkip) {
bool ok = SkipVideoDemuxToNextKeyFrame(aTimeThreshold, parsed);
bool ok = SkipVideoDemuxToNextKeyFrame(aTimeThreshold, a.mDropped);
if (!ok) {
NS_WARNING("Failed to skip demux up to next keyframe");
return false;
}
a.mParsed = a.mDropped;
aKeyframeSkip = false;
nsresult rv = mMediaDataDecoder->Flush();
NS_ENSURE_SUCCESS(rv, false);
@ -360,7 +360,7 @@ IntelWebMVideoDecoder::DecodeVideoFrame(bool& aKeyframeSkip,
// mNumSamplesOutput field since the last time we were called.
MonitorAutoLock mon(mMonitor);
uint64_t delta = mNumSamplesOutput - mLastReportedNumDecodedFrames;
decoded = static_cast<uint32_t>(delta);
a.mDecoded = static_cast<uint32_t>(delta);
mLastReportedNumDecodedFrames = mNumSamplesOutput;
}
return rv;

View File

@ -79,9 +79,7 @@ SoftwareWebMVideoDecoder::DecodeVideoFrame(bool &aKeyframeSkip,
// Record number of frames decoded and parsed. Automatically update the
// stats counters using the AutoNotifyDecoded stack-based class.
uint32_t parsed = 0, decoded = 0;
AbstractMediaDecoder::AutoNotifyDecoded autoNotify(mReader->GetDecoder(),
parsed, decoded);
AbstractMediaDecoder::AutoNotifyDecoded a(mReader->GetDecoder());
nsAutoRef<NesteggPacketHolder> holder(mReader->NextPacket(WebMReader::VIDEO));
if (!holder) {
@ -144,7 +142,8 @@ SoftwareWebMVideoDecoder::DecodeVideoFrame(bool &aKeyframeSkip,
}
if (aKeyframeSkip && (!si.is_kf || tstamp_usecs < aTimeThreshold)) {
// Skipping to next keyframe...
parsed++; // Assume 1 frame per chunk.
a.mParsed++; // Assume 1 frame per chunk.
a.mDropped++;
continue;
}
@ -160,7 +159,8 @@ SoftwareWebMVideoDecoder::DecodeVideoFrame(bool &aKeyframeSkip,
// the time threshold required then it is not added
// to the video queue and won't be displayed.
if (tstamp_usecs < aTimeThreshold) {
parsed++; // Assume 1 frame per chunk.
a.mParsed++; // Assume 1 frame per chunk.
a.mDropped++;
continue;
}
@ -218,9 +218,9 @@ SoftwareWebMVideoDecoder::DecodeVideoFrame(bool &aKeyframeSkip,
if (!v) {
return false;
}
parsed++;
decoded++;
NS_ASSERTION(decoded <= parsed,
a.mParsed++;
a.mDecoded++;
NS_ASSERTION(a.mDecoded <= a.mParsed,
"Expect only 1 frame per chunk per packet in WebM...");
mReader->VideoQueue().Push(v);
}

View File

@ -808,8 +808,7 @@ WMFReader::DecodeVideoFrame(bool &aKeyframeSkip,
// Record number of frames decoded and parsed. Automatically update the
// stats counters using the AutoNotifyDecoded stack-based class.
uint32_t parsed = 0, decoded = 0;
AbstractMediaDecoder::AutoNotifyDecoded autoNotify(mDecoder, parsed, decoded);
AbstractMediaDecoder::AutoNotifyDecoded a(mDecoder);
HRESULT hr;
@ -876,8 +875,8 @@ WMFReader::DecodeVideoFrame(bool &aKeyframeSkip,
}
NS_ENSURE_TRUE(SUCCEEDED(hr) && v, false);
parsed++;
decoded++;
a.mParsed++;
a.mDecoded++;
mVideoQueue.Push(v);
#ifdef LOG_SAMPLE_DECODE

View File

@ -159,7 +159,9 @@ PluginModuleChild::PluginModuleChild(bool aIsChrome)
}
mUserAgent.SetIsVoid(true);
#ifdef XP_MACOSX
mac_plugin_interposing::child::SetUpCocoaInterposing();
if (aIsChrome) {
mac_plugin_interposing::child::SetUpCocoaInterposing();
}
#endif
}

View File

@ -13,10 +13,16 @@
namespace mozilla {
namespace layers {
// Maximum number of ms we're willing to wait for
// the YUV -> RGB conversion to take before marking
// the texture as invalid.
static const uint32_t kMaxWaitSyncMs = 5;
D3D9SurfaceImage::D3D9SurfaceImage()
: Image(nullptr, ImageFormat::D3D9_RGB32_TEXTURE)
, mSize(0, 0)
, mIsValid(true)
{}
D3D9SurfaceImage::~D3D9SurfaceImage()
@ -136,9 +142,6 @@ D3D9SurfaceImage::SetData(const Data& aData)
hr = device->StretchRect(surface, &src, textureSurface, nullptr, D3DTEXF_NONE);
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
// Flush the draw command now, so that by the time we come to draw this
// image, we're less likely to need to wait for the draw operation to
// complete.
RefPtr<IDirect3DQuery9> query;
hr = device->CreateQuery(D3DQUERYTYPE_EVENT, byRef(query));
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
@ -148,34 +151,28 @@ D3D9SurfaceImage::SetData(const Data& aData)
mTexture = texture;
mShareHandle = shareHandle;
mSize = gfx::IntSize(region.width, region.height);
mQuery = query;
int iterations = 0;
while (true) {
HRESULT hr = query->GetData(nullptr, 0, D3DGETDATA_FLUSH);
if (hr == S_FALSE) {
Sleep(1);
iterations++;
continue;
}
if (FAILED(hr) || iterations >= kMaxWaitSyncMs) {
mIsValid = false;
}
break;
}
return S_OK;
}
void
D3D9SurfaceImage::EnsureSynchronized()
bool
D3D9SurfaceImage::IsValid()
{
RefPtr<IDirect3DQuery9> query = mQuery;
if (!query) {
// Not setup, or already synchronized.
return;
}
int iterations = 0;
while (iterations < 10 && S_FALSE == query->GetData(nullptr, 0, D3DGETDATA_FLUSH)) {
Sleep(1);
iterations++;
}
mQuery = nullptr;
}
HANDLE
D3D9SurfaceImage::GetShareHandle()
{
// Ensure the image has completed its synchronization,
// and safe to used by the caller on another device.
EnsureSynchronized();
return mShareHandle;
return mIsValid;
}
const D3DSURFACE_DESC&
@ -193,7 +190,6 @@ D3D9SurfaceImage::GetSize()
TextureClient*
D3D9SurfaceImage::GetTextureClient(CompositableClient* aClient)
{
EnsureSynchronized();
if (!mTextureClient) {
RefPtr<SharedTextureClientD3D9> textureClient =
new SharedTextureClientD3D9(aClient->GetForwarder(),
@ -216,9 +212,6 @@ D3D9SurfaceImage::GetAsSourceSurface()
return nullptr;
}
// Ensure that the texture is ready to be used.
EnsureSynchronized();
// Readback the texture from GPU memory into system memory, so that
// we can copy it into the Cairo image. This is expensive.
RefPtr<IDirect3DSurface9> textureSurface;

View File

@ -41,12 +41,6 @@ public:
// Returns the description of the shared surface.
const D3DSURFACE_DESC& GetDesc() const;
// Returns the HANDLE that can be used to open the image as a shared resource.
// If the operation to copy the original resource to the shared resource
// hasn't finished yet, this function blocks until the synchronization is
// complete.
HANDLE GetShareHandle();
gfx::IntSize GetSize() MOZ_OVERRIDE;
virtual TemporaryRef<gfx::SourceSurface> GetAsSourceSurface() MOZ_OVERRIDE;
@ -54,18 +48,16 @@ public:
virtual TextureClient* GetTextureClient(CompositableClient* aClient) MOZ_OVERRIDE;
virtual uint8_t* GetBuffer() MOZ_OVERRIDE { return nullptr; }
private:
virtual bool IsValid() MOZ_OVERRIDE;
// Blocks the calling thread until the copy operation started in SetData()
// is complete, whereupon the texture is safe to use.
void EnsureSynchronized();
private:
gfx::IntSize mSize;
RefPtr<IDirect3DTexture9> mTexture;
RefPtr<IDirect3DQuery9> mQuery;
RefPtr<TextureClient> mTextureClient;
HANDLE mShareHandle;
D3DSURFACE_DESC mDesc;
bool mIsValid;
};
} // namepace layers

View File

@ -168,6 +168,8 @@ public:
virtual TemporaryRef<gfx::SourceSurface> GetAsSourceSurface() = 0;
virtual bool IsValid() { return true; }
virtual GrallocImage* AsGrallocImage()
{
return nullptr;

View File

@ -10,6 +10,7 @@
#include "FrameMetrics.h" // for FrameMetrics, etc
#include "Units.h" // for CSSPoint, CSSRect, etc
#include "mozilla/Assertions.h" // for MOZ_ASSERT_HELPER2
#include "mozilla/EventForwards.h" // for Modifiers
#include "nsISupportsImpl.h"
class Task;
@ -44,7 +45,7 @@ public:
* to.
*/
virtual void HandleDoubleTap(const CSSPoint& aPoint,
int32_t aModifiers,
Modifiers aModifiers,
const ScrollableLayerGuid& aGuid) = 0;
/**
@ -53,7 +54,7 @@ public:
* button down, then mouse button up at |aPoint|.
*/
virtual void HandleSingleTap(const CSSPoint& aPoint,
int32_t aModifiers,
Modifiers aModifiers,
const ScrollableLayerGuid& aGuid) = 0;
/**
@ -61,7 +62,7 @@ public:
* current scroll offset.
*/
virtual void HandleLongTap(const CSSPoint& aPoint,
int32_t aModifiers,
Modifiers aModifiers,
const ScrollableLayerGuid& aGuid,
uint64_t aInputBlockId) = 0;
@ -74,7 +75,7 @@ public:
* notifies the APZ that the long-tap event was prevent-defaulted).
*/
virtual void HandleLongTapUp(const CSSPoint& aPoint,
int32_t aModifiers,
Modifiers aModifiers,
const ScrollableLayerGuid& aGuid) = 0;
/**

View File

@ -84,57 +84,6 @@
# define APZC_LOG_FM(fm, prefix, ...)
#endif
// Static helper functions
namespace {
int32_t
WidgetModifiersToDOMModifiers(mozilla::Modifiers aModifiers)
{
int32_t result = 0;
if (aModifiers & mozilla::MODIFIER_SHIFT) {
result |= nsIDOMWindowUtils::MODIFIER_SHIFT;
}
if (aModifiers & mozilla::MODIFIER_CONTROL) {
result |= nsIDOMWindowUtils::MODIFIER_CONTROL;
}
if (aModifiers & mozilla::MODIFIER_ALT) {
result |= nsIDOMWindowUtils::MODIFIER_ALT;
}
if (aModifiers & mozilla::MODIFIER_META) {
result |= nsIDOMWindowUtils::MODIFIER_META;
}
if (aModifiers & mozilla::MODIFIER_ALTGRAPH) {
result |= nsIDOMWindowUtils::MODIFIER_ALTGRAPH;
}
if (aModifiers & mozilla::MODIFIER_CAPSLOCK) {
result |= nsIDOMWindowUtils::MODIFIER_CAPSLOCK;
}
if (aModifiers & mozilla::MODIFIER_FN) {
result |= nsIDOMWindowUtils::MODIFIER_FN;
}
if (aModifiers & mozilla::MODIFIER_FNLOCK) {
result |= nsIDOMWindowUtils::MODIFIER_FNLOCK;
}
if (aModifiers & mozilla::MODIFIER_NUMLOCK) {
result |= nsIDOMWindowUtils::MODIFIER_NUMLOCK;
}
if (aModifiers & mozilla::MODIFIER_SCROLLLOCK) {
result |= nsIDOMWindowUtils::MODIFIER_SCROLLLOCK;
}
if (aModifiers & mozilla::MODIFIER_SYMBOL) {
result |= nsIDOMWindowUtils::MODIFIER_SYMBOL;
}
if (aModifiers & mozilla::MODIFIER_SYMBOLLOCK) {
result |= nsIDOMWindowUtils::MODIFIER_SYMBOLLOCK;
}
if (aModifiers & mozilla::MODIFIER_OS) {
result |= nsIDOMWindowUtils::MODIFIER_OS;
}
return result;
}
}
namespace mozilla {
namespace layers {
@ -1653,7 +1602,6 @@ nsEventStatus AsyncPanZoomController::OnLongPress(const TapGestureInput& aEvent)
APZC_LOG("%p got a long-press in state %d\n", this, mState);
nsRefPtr<GeckoContentController> controller = GetGeckoContentController();
if (controller) {
int32_t modifiers = WidgetModifiersToDOMModifiers(aEvent.modifiers);
CSSPoint geckoScreenPoint;
if (ConvertToGecko(aEvent.mLocalPoint, &geckoScreenPoint)) {
if (CurrentTouchBlock()->IsDuringFastMotion()) {
@ -1661,7 +1609,7 @@ nsEventStatus AsyncPanZoomController::OnLongPress(const TapGestureInput& aEvent)
return nsEventStatus_eIgnore;
}
uint64_t blockId = GetInputQueue()->InjectNewTouchBlock(this);
controller->HandleLongTap(geckoScreenPoint, modifiers, GetGuid(), blockId);
controller->HandleLongTap(geckoScreenPoint, aEvent.modifiers, GetGuid(), blockId);
return nsEventStatus_eConsumeNoDefault;
}
}
@ -1672,10 +1620,9 @@ nsEventStatus AsyncPanZoomController::OnLongPressUp(const TapGestureInput& aEven
APZC_LOG("%p got a long-tap-up in state %d\n", this, mState);
nsRefPtr<GeckoContentController> controller = GetGeckoContentController();
if (controller) {
int32_t modifiers = WidgetModifiersToDOMModifiers(aEvent.modifiers);
CSSPoint geckoScreenPoint;
if (ConvertToGecko(aEvent.mLocalPoint, &geckoScreenPoint)) {
controller->HandleLongTapUp(geckoScreenPoint, modifiers, GetGuid());
controller->HandleLongTapUp(geckoScreenPoint, aEvent.modifiers, GetGuid());
return nsEventStatus_eConsumeNoDefault;
}
}
@ -1697,7 +1644,7 @@ nsEventStatus AsyncPanZoomController::GenerateSingleTap(const ParentLayerPoint&
// See bug 965381 for the issue this was causing.
controller->PostDelayedTask(
NewRunnableMethod(controller.get(), &GeckoContentController::HandleSingleTap,
geckoScreenPoint, WidgetModifiersToDOMModifiers(aModifiers),
geckoScreenPoint, aModifiers,
GetGuid()),
0);
return nsEventStatus_eConsumeNoDefault;
@ -1733,10 +1680,9 @@ nsEventStatus AsyncPanZoomController::OnDoubleTap(const TapGestureInput& aEvent)
nsRefPtr<GeckoContentController> controller = GetGeckoContentController();
if (controller) {
if (mZoomConstraints.mAllowDoubleTapZoom && CurrentTouchBlock()->TouchActionAllowsDoubleTapZoom()) {
int32_t modifiers = WidgetModifiersToDOMModifiers(aEvent.modifiers);
CSSPoint geckoScreenPoint;
if (ConvertToGecko(aEvent.mLocalPoint, &geckoScreenPoint)) {
controller->HandleDoubleTap(geckoScreenPoint, modifiers, GetGuid());
controller->HandleDoubleTap(geckoScreenPoint, aEvent.modifiers, GetGuid());
}
}
return nsEventStatus_eConsumeNoDefault;

View File

@ -399,6 +399,7 @@ nsEventStatus
APZCCallbackHelper::DispatchSynthesizedMouseEvent(uint32_t aMsg,
uint64_t aTime,
const LayoutDevicePoint& aRefPoint,
Modifiers aModifiers,
nsIWidget* aWidget)
{
MOZ_ASSERT(aMsg == NS_MOUSE_MOVE || aMsg == NS_MOUSE_BUTTON_DOWN ||
@ -414,6 +415,7 @@ APZCCallbackHelper::DispatchSynthesizedMouseEvent(uint32_t aMsg,
if (aMsg != NS_MOUSE_MOVE) {
event.clickCount = 1;
}
event.modifiers = aModifiers;
event.widget = aWidget;
return DispatchWidgetEvent(event);
@ -440,6 +442,7 @@ APZCCallbackHelper::DispatchMouseEvent(const nsCOMPtr<nsIDOMWindowUtils>& aUtils
void
APZCCallbackHelper::FireSingleTapEvent(const LayoutDevicePoint& aPoint,
Modifiers aModifiers,
nsIWidget* aWidget)
{
if (aWidget->Destroyed()) {
@ -448,9 +451,9 @@ APZCCallbackHelper::FireSingleTapEvent(const LayoutDevicePoint& aPoint,
APZCCH_LOG("Dispatching single-tap component events to %s\n",
Stringify(aPoint).c_str());
int time = 0;
DispatchSynthesizedMouseEvent(NS_MOUSE_MOVE, time, aPoint, aWidget);
DispatchSynthesizedMouseEvent(NS_MOUSE_BUTTON_DOWN, time, aPoint, aWidget);
DispatchSynthesizedMouseEvent(NS_MOUSE_BUTTON_UP, time, aPoint, aWidget);
DispatchSynthesizedMouseEvent(NS_MOUSE_MOVE, time, aPoint, aModifiers, aWidget);
DispatchSynthesizedMouseEvent(NS_MOUSE_BUTTON_DOWN, time, aPoint, aModifiers, aWidget);
DispatchSynthesizedMouseEvent(NS_MOUSE_BUTTON_UP, time, aPoint, aModifiers, aWidget);
}
static nsIScrollableFrame*

View File

@ -123,6 +123,7 @@ public:
static nsEventStatus DispatchSynthesizedMouseEvent(uint32_t aMsg,
uint64_t aTime,
const LayoutDevicePoint& aRefPoint,
Modifiers aModifiers,
nsIWidget* aWidget);
/* Dispatch a mouse event with the given parameters.
@ -139,6 +140,7 @@ public:
/* Fire a single-tap event at the given point. The event is dispatched
* via the given widget. */
static void FireSingleTapEvent(const LayoutDevicePoint& aPoint,
Modifiers aModifiers,
nsIWidget* aWidget);
/* Perform hit-testing on the touch points of |aEvent| to determine

View File

@ -10,6 +10,7 @@
#include "mozilla/Preferences.h"
#include "nsCOMPtr.h"
#include "nsDocShell.h"
#include "nsIDOMWindowUtils.h"
#include "nsITimer.h"
#include "nsIWeakReferenceUtils.h"
#include "nsIWidget.h"
@ -18,6 +19,57 @@
#define APZES_LOG(...)
// #define APZES_LOG(...) printf_stderr("APZCCH: " __VA_ARGS__)
// Static helper functions
namespace {
int32_t
WidgetModifiersToDOMModifiers(mozilla::Modifiers aModifiers)
{
int32_t result = 0;
if (aModifiers & mozilla::MODIFIER_SHIFT) {
result |= nsIDOMWindowUtils::MODIFIER_SHIFT;
}
if (aModifiers & mozilla::MODIFIER_CONTROL) {
result |= nsIDOMWindowUtils::MODIFIER_CONTROL;
}
if (aModifiers & mozilla::MODIFIER_ALT) {
result |= nsIDOMWindowUtils::MODIFIER_ALT;
}
if (aModifiers & mozilla::MODIFIER_META) {
result |= nsIDOMWindowUtils::MODIFIER_META;
}
if (aModifiers & mozilla::MODIFIER_ALTGRAPH) {
result |= nsIDOMWindowUtils::MODIFIER_ALTGRAPH;
}
if (aModifiers & mozilla::MODIFIER_CAPSLOCK) {
result |= nsIDOMWindowUtils::MODIFIER_CAPSLOCK;
}
if (aModifiers & mozilla::MODIFIER_FN) {
result |= nsIDOMWindowUtils::MODIFIER_FN;
}
if (aModifiers & mozilla::MODIFIER_FNLOCK) {
result |= nsIDOMWindowUtils::MODIFIER_FNLOCK;
}
if (aModifiers & mozilla::MODIFIER_NUMLOCK) {
result |= nsIDOMWindowUtils::MODIFIER_NUMLOCK;
}
if (aModifiers & mozilla::MODIFIER_SCROLLLOCK) {
result |= nsIDOMWindowUtils::MODIFIER_SCROLLLOCK;
}
if (aModifiers & mozilla::MODIFIER_SYMBOL) {
result |= nsIDOMWindowUtils::MODIFIER_SYMBOL;
}
if (aModifiers & mozilla::MODIFIER_SYMBOLLOCK) {
result |= nsIDOMWindowUtils::MODIFIER_SYMBOLLOCK;
}
if (aModifiers & mozilla::MODIFIER_OS) {
result |= nsIDOMWindowUtils::MODIFIER_OS;
}
return result;
}
}
namespace mozilla {
namespace layers {
@ -57,9 +109,11 @@ public:
DelayedFireSingleTapEvent(nsWeakPtr aWidget,
LayoutDevicePoint& aPoint,
Modifiers aModifiers,
nsITimer* aTimer)
: mWidget(aWidget)
, mPoint(aPoint)
, mModifiers(aModifiers)
// Hold the reference count until we are called back.
, mTimer(aTimer)
{
@ -68,7 +122,7 @@ public:
NS_IMETHODIMP Notify(nsITimer*) MOZ_OVERRIDE
{
if (nsCOMPtr<nsIWidget> widget = do_QueryReferent(mWidget)) {
APZCCallbackHelper::FireSingleTapEvent(mPoint, widget);
APZCCallbackHelper::FireSingleTapEvent(mPoint, mModifiers, widget);
}
mTimer = nullptr;
return NS_OK;
@ -85,6 +139,7 @@ private:
nsWeakPtr mWidget;
LayoutDevicePoint mPoint;
Modifiers mModifiers;
nsCOMPtr<nsITimer> mTimer;
};
@ -92,6 +147,7 @@ NS_IMPL_ISUPPORTS(DelayedFireSingleTapEvent, nsITimerCallback)
void
APZEventState::ProcessSingleTap(const CSSPoint& aPoint,
Modifiers aModifiers,
const ScrollableLayerGuid& aGuid,
float aPresShellResolution)
{
@ -114,14 +170,14 @@ APZEventState::ProcessSingleTap(const CSSPoint& aPoint,
// If the active element isn't visually affected by the :active style, we
// have no need to wait the extra sActiveDurationMs to make the activation
// visually obvious to the user.
APZCCallbackHelper::FireSingleTapEvent(currentPoint, widget);
APZCCallbackHelper::FireSingleTapEvent(currentPoint, aModifiers, widget);
return;
}
APZES_LOG("Active element uses style, scheduling timer for click event\n");
nsCOMPtr<nsITimer> timer = do_CreateInstance(NS_TIMER_CONTRACTID);
nsRefPtr<DelayedFireSingleTapEvent> callback =
new DelayedFireSingleTapEvent(mWidget, currentPoint, timer);
new DelayedFireSingleTapEvent(mWidget, currentPoint, aModifiers, timer);
nsresult rv = timer->InitWithCallback(callback,
sActiveDurationMs,
nsITimer::TYPE_ONE_SHOT);
@ -135,6 +191,7 @@ APZEventState::ProcessSingleTap(const CSSPoint& aPoint,
void
APZEventState::ProcessLongTap(const nsCOMPtr<nsIDOMWindowUtils>& aUtils,
const CSSPoint& aPoint,
Modifiers aModifiers,
const ScrollableLayerGuid& aGuid,
uint64_t aInputBlockId,
float aPresShellResolution)
@ -148,10 +205,14 @@ APZEventState::ProcessLongTap(const nsCOMPtr<nsIDOMWindowUtils>& aUtils,
SendPendingTouchPreventedResponse(false, aGuid);
// Converting the modifiers to DOM format for the DispatchMouseEvent call
// is the most useless thing ever because nsDOMWindowUtils::SendMouseEvent
// just converts them back to widget format, but that API has many callers,
// including in JS code, so it's not trivial to change.
bool eventHandled =
APZCCallbackHelper::DispatchMouseEvent(aUtils, NS_LITERAL_STRING("contextmenu"),
APZCCallbackHelper::ApplyCallbackTransform(aPoint, aGuid, aPresShellResolution),
2, 1, 0, true,
2, 1, WidgetModifiersToDOMModifiers(aModifiers), true,
nsIDOMMouseEvent::MOZ_SOURCE_TOUCH);
APZES_LOG("Contextmenu event handled: %d\n", eventHandled);
@ -163,7 +224,7 @@ APZEventState::ProcessLongTap(const nsCOMPtr<nsIDOMWindowUtils>& aUtils,
* widget->GetDefaultScale();
int time = 0;
nsEventStatus status =
APZCCallbackHelper::DispatchSynthesizedMouseEvent(NS_MOUSE_MOZLONGTAP, time, currentPoint, widget);
APZCCallbackHelper::DispatchSynthesizedMouseEvent(NS_MOUSE_MOZLONGTAP, time, currentPoint, aModifiers, widget);
eventHandled = (status == nsEventStatus_eConsumeNoDefault);
APZES_LOG("MOZLONGTAP event handled: %d\n", eventHandled);
}
@ -173,12 +234,13 @@ APZEventState::ProcessLongTap(const nsCOMPtr<nsIDOMWindowUtils>& aUtils,
void
APZEventState::ProcessLongTapUp(const CSSPoint& aPoint,
Modifiers aModifiers,
const ScrollableLayerGuid& aGuid,
float aPresShellResolution)
{
APZES_LOG("Handling long tap up at %s\n", Stringify(aPoint).c_str());
ProcessSingleTap(aPoint, aGuid, aPresShellResolution);
ProcessSingleTap(aPoint, aModifiers, aGuid, aPresShellResolution);
}
void

View File

@ -50,14 +50,17 @@ public:
NS_INLINE_DECL_REFCOUNTING(APZEventState);
void ProcessSingleTap(const CSSPoint& aPoint,
Modifiers aModifiers,
const ScrollableLayerGuid& aGuid,
float aPresShellResolution);
void ProcessLongTap(const nsCOMPtr<nsIDOMWindowUtils>& aUtils,
const CSSPoint& aPoint,
Modifiers aModifiers,
const ScrollableLayerGuid& aGuid,
uint64_t aInputBlockId,
float aPresShellResolution);
void ProcessLongTapUp(const CSSPoint& aPoint,
Modifiers aModifiers,
const ScrollableLayerGuid& aGuid,
float aPresShellResolution);
void ProcessTouchEvent(const WidgetTouchEvent& aEvent,

View File

@ -129,7 +129,7 @@ ChromeProcessController::GetDOMWindowUtils() const
void
ChromeProcessController::HandleSingleTap(const CSSPoint& aPoint,
int32_t aModifiers,
Modifiers aModifiers,
const ScrollableLayerGuid& aGuid)
{
if (MessageLoop::current() != mUILoop) {
@ -140,11 +140,11 @@ ChromeProcessController::HandleSingleTap(const CSSPoint& aPoint,
return;
}
mAPZEventState->ProcessSingleTap(aPoint, aGuid, GetPresShellResolution());
mAPZEventState->ProcessSingleTap(aPoint, aModifiers, aGuid, GetPresShellResolution());
}
void
ChromeProcessController::HandleLongTap(const mozilla::CSSPoint& aPoint, int32_t aModifiers,
ChromeProcessController::HandleLongTap(const mozilla::CSSPoint& aPoint, Modifiers aModifiers,
const ScrollableLayerGuid& aGuid,
uint64_t aInputBlockId)
{
@ -156,12 +156,12 @@ ChromeProcessController::HandleLongTap(const mozilla::CSSPoint& aPoint, int32_t
return;
}
mAPZEventState->ProcessLongTap(GetDOMWindowUtils(), aPoint, aGuid,
mAPZEventState->ProcessLongTap(GetDOMWindowUtils(), aPoint, aModifiers, aGuid,
aInputBlockId, GetPresShellResolution());
}
void
ChromeProcessController::HandleLongTapUp(const CSSPoint& aPoint, int32_t aModifiers,
ChromeProcessController::HandleLongTapUp(const CSSPoint& aPoint, Modifiers aModifiers,
const ScrollableLayerGuid& aGuid)
{
if (MessageLoop::current() != mUILoop) {
@ -172,7 +172,7 @@ ChromeProcessController::HandleLongTapUp(const CSSPoint& aPoint, int32_t aModifi
return;
}
mAPZEventState->ProcessLongTapUp(aPoint, aGuid, GetPresShellResolution());
mAPZEventState->ProcessLongTapUp(aPoint, aModifiers, aGuid, GetPresShellResolution());
}
void

View File

@ -40,14 +40,14 @@ public:
virtual void AcknowledgeScrollUpdate(const FrameMetrics::ViewID& aScrollId,
const uint32_t& aScrollGeneration) MOZ_OVERRIDE;
virtual void HandleDoubleTap(const mozilla::CSSPoint& aPoint, int32_t aModifiers,
virtual void HandleDoubleTap(const mozilla::CSSPoint& aPoint, Modifiers aModifiers,
const ScrollableLayerGuid& aGuid) MOZ_OVERRIDE {}
virtual void HandleSingleTap(const mozilla::CSSPoint& aPoint, int32_t aModifiers,
virtual void HandleSingleTap(const mozilla::CSSPoint& aPoint, Modifiers aModifiers,
const ScrollableLayerGuid& aGuid) MOZ_OVERRIDE;
virtual void HandleLongTap(const mozilla::CSSPoint& aPoint, int32_t aModifiers,
virtual void HandleLongTap(const mozilla::CSSPoint& aPoint, Modifiers aModifiers,
const ScrollableLayerGuid& aGuid,
uint64_t aInputBlockId) MOZ_OVERRIDE;
virtual void HandleLongTapUp(const CSSPoint& aPoint, int32_t aModifiers,
virtual void HandleLongTapUp(const CSSPoint& aPoint, Modifiers aModifiers,
const ScrollableLayerGuid& aGuid) MOZ_OVERRIDE;
virtual void SendAsyncScrollDOMEvent(bool aIsRoot, const mozilla::CSSRect &aContentRect,
const mozilla::CSSSize &aScrollableSize) MOZ_OVERRIDE {}

View File

@ -143,7 +143,7 @@ CompositableParentManager::ReceiveCompositableUpdate(const CompositableOperation
MOZ_ASSERT(tex.get());
compositable->RemoveTextureHost(tex);
if (!IsAsync() && GetChildProcessId()) {
if (!IsAsync() && ImageBridgeParent::GetInstance(GetChildProcessId())) {
// send FenceHandle if present via ImageBridge.
ImageBridgeParent::SendFenceHandleToTrackerIfPresent(
GetChildProcessId(),

View File

@ -454,13 +454,11 @@ ImageBridgeParent::SendFenceHandleToTrackerIfPresent(base::ProcessId aChildProce
/*static*/ void
ImageBridgeParent::SendPendingAsyncMessges(base::ProcessId aChildProcessId)
{
#ifdef MOZ_WIDGET_GONK
ImageBridgeParent* imageBridge = ImageBridgeParent::GetInstance(aChildProcessId);
if (!imageBridge) {
return;
}
imageBridge->SendPendingAsyncMessges();
#endif
}
} // layers

View File

@ -935,20 +935,23 @@ LayerTransactionParent::RecvChildAsyncMessages(InfallibleTArray<AsyncChildMessag
MOZ_ASSERT(tex.get());
compositable->RemoveTextureHost(tex);
// send FenceHandle if present via ImageBridge.
ImageBridgeParent::SendFenceHandleToTrackerIfPresent(
GetChildProcessId(),
op.holderId(),
op.transactionId(),
op.textureParent(),
compositable);
// Send message back via PImageBridge.
ImageBridgeParent::ReplyRemoveTexture(
GetChildProcessId(),
OpReplyRemoveTexture(true, // isMain
op.holderId(),
op.transactionId()));
if (ImageBridgeParent::GetInstance(GetChildProcessId())) {
// send FenceHandle if present via ImageBridge.
ImageBridgeParent::SendFenceHandleToTrackerIfPresent(
GetChildProcessId(),
op.holderId(),
op.transactionId(),
op.textureParent(),
compositable);
// Send message back via PImageBridge.
ImageBridgeParent::ReplyRemoveTexture(
GetChildProcessId(),
OpReplyRemoveTexture(true, // isMain
op.holderId(),
op.transactionId()));
} else {
NS_ERROR("ImageBridgeParent should exist");
}
break;
}
default:

View File

@ -470,10 +470,14 @@ ShadowLayerForwarder::RemoveTextureFromCompositableAsync(AsyncTransactionTracker
} else {
// If the function is called outside of transaction,
// OpRemoveTextureAsync message is stored as pending message.
#ifdef MOZ_WIDGET_GONK
mPendingAsyncMessages.push_back(OpRemoveTextureAsync(CompositableClient::GetTrackersHolderId(aCompositable->GetIPDLActor()),
aAsyncTransactionTracker->GetId(),
nullptr, aCompositable->GetIPDLActor(),
nullptr, aTexture->GetIPDLActor()));
#else
NS_RUNTIMEABORT("not reached");
#endif
}
CompositableClient::HoldUntilComplete(aCompositable->GetIPDLActor(),
aAsyncTransactionTracker);

View File

@ -62,10 +62,10 @@ class MockContentController : public GeckoContentController {
public:
MOCK_METHOD1(RequestContentRepaint, void(const FrameMetrics&));
MOCK_METHOD2(AcknowledgeScrollUpdate, void(const FrameMetrics::ViewID&, const uint32_t& aScrollGeneration));
MOCK_METHOD3(HandleDoubleTap, void(const CSSPoint&, int32_t, const ScrollableLayerGuid&));
MOCK_METHOD3(HandleSingleTap, void(const CSSPoint&, int32_t, const ScrollableLayerGuid&));
MOCK_METHOD4(HandleLongTap, void(const CSSPoint&, int32_t, const ScrollableLayerGuid&, uint64_t));
MOCK_METHOD3(HandleLongTapUp, void(const CSSPoint&, int32_t, const ScrollableLayerGuid&));
MOCK_METHOD3(HandleDoubleTap, void(const CSSPoint&, Modifiers, const ScrollableLayerGuid&));
MOCK_METHOD3(HandleSingleTap, void(const CSSPoint&, Modifiers, const ScrollableLayerGuid&));
MOCK_METHOD4(HandleLongTap, void(const CSSPoint&, Modifiers, const ScrollableLayerGuid&, uint64_t));
MOCK_METHOD3(HandleLongTapUp, void(const CSSPoint&, Modifiers, const ScrollableLayerGuid&));
MOCK_METHOD3(SendAsyncScrollDOMEvent, void(bool aIsRoot, const CSSRect &aContentRect, const CSSSize &aScrollableSize));
MOCK_METHOD2(PostDelayedTask, void(Task* aTask, int aDelayMs));
MOCK_METHOD3(NotifyAPZStateChange, void(const ScrollableLayerGuid& aGuid, APZStateChange aChange, int aArg));

View File

@ -123,6 +123,9 @@ class JS_PUBLIC_API(ProfilingFrameIterator)
bool isJit() const;
};
JS_FRIEND_API(bool)
IsProfilingEnabledForRuntime(JSRuntime *runtime);
/**
* After each sample run, this method should be called with the latest sample
* buffer generation, and the lapCount. It will update corresponding fields on

View File

@ -7,11 +7,11 @@
#include "builtin/SymbolObject.h"
#include "vm/StringBuffer.h"
#include "vm/Symbol.h"
#include "jsobjinlines.h"
#include "vm/NativeObject-inl.h"
#include "vm/Symbol-inl.h"
using JS::Symbol;
using namespace js;

View File

@ -1254,8 +1254,11 @@ ReadSPSProfilingStack(JSContext *cx, unsigned argc, jsval *vp)
CallArgs args = CallArgsFromVp(argc, vp);
args.rval().setUndefined();
if (!cx->runtime()->spsProfiler.enabled())
// Return boolean 'false' if profiler is not enabled.
if (!cx->runtime()->spsProfiler.enabled()) {
args.rval().setBoolean(false);
return true;
}
// Array holding physical jit stack frames.
RootedObject stack(cx, NewDenseEmptyArray(cx));

View File

@ -26,7 +26,6 @@
#include "gc/Nursery-inl.h"
#include "vm/String-inl.h"
#include "vm/Symbol-inl.h"
using namespace js;
using namespace js::gc;
@ -68,37 +67,43 @@ JS_PUBLIC_DATA(void * const) JS::NullPtr::constNullValue = nullptr;
*/
static inline void
PushMarkStack(GCMarker *gcmarker, JSObject *thing);
PushMarkStack(GCMarker *gcmarker, JSObject *thing) {
gcmarker->traverse(thing);
}
static inline void
PushMarkStack(GCMarker *gcmarker, JSFunction *thing);
PushMarkStack(GCMarker *gcmarker, JSFunction *thing) {
gcmarker->traverse(static_cast<JSObject *>(thing));
}
static inline void
PushMarkStack(GCMarker *gcmarker, JSScript *thing);
PushMarkStack(GCMarker *gcmarker, ObjectGroup *thing) {
gcmarker->traverse(thing);
}
static void
PushMarkStack(GCMarker *gcmarker, jit::JitCode *thing) {
gcmarker->traverse(thing);
}
static inline void
PushMarkStack(GCMarker *gcmarker, JSScript *thing) {
gcmarker->traverse(thing);
}
static inline void
PushMarkStack(GCMarker *gcmarker, LazyScript *thing) {
gcmarker->traverse(thing);
}
static inline void
PushMarkStack(GCMarker *gcmarker, Shape *thing);
static inline void
PushMarkStack(GCMarker *gcmarker, JSString *str);
PushMarkStack(GCMarker *gcmarker, BaseShape *thing);
static inline void
PushMarkStack(GCMarker *gcmarker, JS::Symbol *sym);
PushMarkStack(GCMarker *gcmarker, JSString *thing);
static inline void
PushMarkStack(GCMarker *gcmarker, ObjectGroup *thing);
PushMarkStack(GCMarker *gcmarker, JS::Symbol *thing);
namespace js {
namespace gc {
static void MarkChildren(JSTracer *trc, JSString *str);
static void MarkChildren(JSTracer *trc, JS::Symbol *sym);
static void MarkChildren(JSTracer *trc, JSScript *script);
static void MarkChildren(JSTracer *trc, LazyScript *lazy);
static void MarkChildren(JSTracer *trc, Shape *shape);
static void MarkChildren(JSTracer *trc, BaseShape *base);
static void MarkChildren(JSTracer *trc, ObjectGroup *group);
static void MarkChildren(JSTracer *trc, jit::JitCode *code);
} /* namespace gc */
} /* namespace js */
@ -199,7 +204,7 @@ CheckMarkedThing(JSTracer *trc, T **thingp)
MOZ_ASSERT_IF(gcMarker->shouldCheckCompartments(),
zone->isCollecting() || rt->isAtomsZone(zone));
MOZ_ASSERT_IF(gcMarker->getMarkColor() == GRAY,
MOZ_ASSERT_IF(gcMarker->markColor() == GRAY,
!zone->isGCMarkingBlack() || rt->isAtomsZone(zone));
MOZ_ASSERT(!(zone->isGCSweeping() || zone->isGCFinished() || zone->isGCCompacting()));
@ -938,7 +943,7 @@ ShouldMarkCrossCompartment(JSTracer *trc, JSObject *src, Cell *cell)
if (!IS_GC_MARKING_TRACER(trc))
return true;
uint32_t color = AsGCMarker(trc)->getMarkColor();
uint32_t color = AsGCMarker(trc)->markColor();
MOZ_ASSERT(color == BLACK || color == GRAY);
if (IsInsideNursery(cell)) {
@ -1009,27 +1014,6 @@ gc::MarkValueUnbarriered(JSTracer *trc, Value *v, const char *name)
/*** Push Mark Stack ***/
#define JS_COMPARTMENT_ASSERT(rt, thing) \
MOZ_ASSERT((thing)->zone()->isGCMarking())
#define JS_COMPARTMENT_ASSERT_STR(rt, thing) \
MOZ_ASSERT((thing)->zone()->isGCMarking() || \
(rt)->isAtomsZone((thing)->zone()));
// Symbols can also be in the atoms zone.
#define JS_COMPARTMENT_ASSERT_SYM(rt, sym) \
JS_COMPARTMENT_ASSERT_STR(rt, sym)
static void
PushMarkStack(GCMarker *gcmarker, JSObject *thing)
{
JS_COMPARTMENT_ASSERT(gcmarker->runtime(), thing);
MOZ_ASSERT(!IsInsideNursery(thing));
if (thing->asTenured().markIfUnmarked(gcmarker->getMarkColor()))
gcmarker->pushObject(thing);
}
/*
* PushMarkStack for BaseShape unpacks its children directly onto the mark
* stack. For a pre-barrier between incremental slices, this may result in
@ -1040,61 +1024,10 @@ PushMarkStack(GCMarker *gcmarker, JSObject *thing)
static void
MaybePushMarkStackBetweenSlices(GCMarker *gcmarker, JSObject *thing)
{
DebugOnly<JSRuntime *> rt = gcmarker->runtime();
JS_COMPARTMENT_ASSERT(rt, thing);
MOZ_ASSERT_IF(rt->isHeapBusy(), !IsInsideNursery(thing));
MOZ_ASSERT_IF(gcmarker->runtime()->isHeapBusy(), !IsInsideNursery(thing));
if (!IsInsideNursery(thing) && thing->asTenured().markIfUnmarked(gcmarker->getMarkColor()))
gcmarker->pushObject(thing);
}
static void
PushMarkStack(GCMarker *gcmarker, JSFunction *thing)
{
JS_COMPARTMENT_ASSERT(gcmarker->runtime(), thing);
MOZ_ASSERT(!IsInsideNursery(thing));
if (thing->asTenured().markIfUnmarked(gcmarker->getMarkColor()))
gcmarker->pushObject(thing);
}
static void
PushMarkStack(GCMarker *gcmarker, ObjectGroup *thing)
{
JS_COMPARTMENT_ASSERT(gcmarker->runtime(), thing);
MOZ_ASSERT(!IsInsideNursery(thing));
if (thing->markIfUnmarked(gcmarker->getMarkColor()))
gcmarker->pushType(thing);
}
static void
PushMarkStack(GCMarker *gcmarker, JSScript *thing)
{
JS_COMPARTMENT_ASSERT(gcmarker->runtime(), thing);
MOZ_ASSERT(!IsInsideNursery(thing));
/*
* We mark scripts directly rather than pushing on the stack as they can
* refer to other scripts only indirectly (like via nested functions) and
* we cannot get to deep recursion.
*/
if (thing->markIfUnmarked(gcmarker->getMarkColor()))
MarkChildren(gcmarker, thing);
}
static void
PushMarkStack(GCMarker *gcmarker, LazyScript *thing)
{
JS_COMPARTMENT_ASSERT(gcmarker->runtime(), thing);
MOZ_ASSERT(!IsInsideNursery(thing));
/*
* We mark lazy scripts directly rather than pushing on the stack as they
* only refer to normal scripts and to strings, and cannot recurse.
*/
if (thing->markIfUnmarked(gcmarker->getMarkColor()))
MarkChildren(gcmarker, thing);
if (!IsInsideNursery(thing))
gcmarker->traverse(thing);
}
static void
@ -1107,20 +1040,10 @@ PushMarkStack(GCMarker *gcmarker, Shape *thing)
MOZ_ASSERT(!IsInsideNursery(thing));
/* We mark shapes directly rather than pushing on the stack. */
if (thing->markIfUnmarked(gcmarker->getMarkColor()))
if (thing->markIfUnmarked(gcmarker->markColor()))
ScanShape(gcmarker, thing);
}
static void
PushMarkStack(GCMarker *gcmarker, jit::JitCode *thing)
{
JS_COMPARTMENT_ASSERT(gcmarker->runtime(), thing);
MOZ_ASSERT(!IsInsideNursery(thing));
if (thing->markIfUnmarked(gcmarker->getMarkColor()))
gcmarker->pushJitCode(thing);
}
static inline void
ScanBaseShape(GCMarker *gcmarker, BaseShape *base);
@ -1131,7 +1054,7 @@ PushMarkStack(GCMarker *gcmarker, BaseShape *thing)
MOZ_ASSERT(!IsInsideNursery(thing));
/* We mark base shapes directly rather than pushing on the stack. */
if (thing->markIfUnmarked(gcmarker->getMarkColor()))
if (thing->markIfUnmarked(gcmarker->markColor()))
ScanBaseShape(gcmarker, thing);
}
@ -1154,7 +1077,7 @@ ScanShape(GCMarker *gcmarker, Shape *shape)
MaybePushMarkStackBetweenSlices(gcmarker, shape->setterObject());
shape = shape->previous();
if (shape && shape->markIfUnmarked(gcmarker->getMarkColor()))
if (shape && shape->markIfUnmarked(gcmarker->markColor()))
goto restart;
}
@ -1168,7 +1091,7 @@ ScanBaseShape(GCMarker *gcmarker, BaseShape *base)
if (JSObject *parent = base->getObjectParent()) {
MaybePushMarkStackBetweenSlices(gcmarker, parent);
} else if (GlobalObject *global = base->compartment()->unsafeUnbarrieredMaybeGlobal()) {
PushMarkStack(gcmarker, global);
gcmarker->traverse(global);
}
if (JSObject *metadata = base->getObjectMetadata())
@ -1182,14 +1105,14 @@ ScanBaseShape(GCMarker *gcmarker, BaseShape *base)
if (base->isOwned()) {
UnownedBaseShape *unowned = base->baseUnowned();
MOZ_ASSERT(base->compartment() == unowned->compartment());
unowned->markIfUnmarked(gcmarker->getMarkColor());
unowned->markIfUnmarked(gcmarker->markColor());
}
}
static inline void
ScanLinearString(GCMarker *gcmarker, JSLinearString *str)
{
JS_COMPARTMENT_ASSERT_STR(gcmarker->runtime(), str);
JS_COMPARTMENT_ASSERT(gcmarker->runtime(), str);
MOZ_ASSERT(str->isMarked());
/*
@ -1202,7 +1125,7 @@ ScanLinearString(GCMarker *gcmarker, JSLinearString *str)
MOZ_ASSERT(str->JSString::isLinear());
if (str->isPermanentAtom())
break;
JS_COMPARTMENT_ASSERT_STR(gcmarker->runtime(), str);
JS_COMPARTMENT_ASSERT(gcmarker->runtime(), str);
if (!str->markIfUnmarked())
break;
}
@ -1225,7 +1148,7 @@ ScanRope(GCMarker *gcmarker, JSRope *rope)
for (;;) {
JS_DIAGNOSTICS_ASSERT(GetGCThingTraceKind(rope) == JSTRACE_STRING);
JS_DIAGNOSTICS_ASSERT(rope->JSString::isRope());
JS_COMPARTMENT_ASSERT_STR(gcmarker->runtime(), rope);
JS_COMPARTMENT_ASSERT(gcmarker->runtime(), rope);
MOZ_ASSERT(rope->isMarked());
JSRope *next = nullptr;
@ -1279,7 +1202,7 @@ PushMarkStack(GCMarker *gcmarker, JSString *str)
if (str->isPermanentAtom())
return;
JS_COMPARTMENT_ASSERT_STR(gcmarker->runtime(), str);
JS_COMPARTMENT_ASSERT(gcmarker->runtime(), str);
/*
* As string can only refer to other strings we fully scan its GC graph
@ -1304,58 +1227,13 @@ PushMarkStack(GCMarker *gcmarker, JS::Symbol *sym)
if (sym->isWellKnownSymbol())
return;
JS_COMPARTMENT_ASSERT_SYM(gcmarker->runtime(), sym);
JS_COMPARTMENT_ASSERT(gcmarker->runtime(), sym);
MOZ_ASSERT(!IsInsideNursery(sym));
if (sym->markIfUnmarked())
ScanSymbol(gcmarker, sym);
}
void
gc::MarkChildren(JSTracer *trc, JSObject *obj)
{
obj->markChildren(trc);
}
static void
gc::MarkChildren(JSTracer *trc, JSString *str)
{
if (str->hasBase())
str->markBase(trc);
else if (str->isRope())
str->asRope().markChildren(trc);
}
static void
gc::MarkChildren(JSTracer *trc, JS::Symbol *sym)
{
sym->markChildren(trc);
}
static void
gc::MarkChildren(JSTracer *trc, JSScript *script)
{
script->markChildren(trc);
}
static void
gc::MarkChildren(JSTracer *trc, LazyScript *lazy)
{
lazy->markChildren(trc);
}
static void
gc::MarkChildren(JSTracer *trc, Shape *shape)
{
shape->markChildren(trc);
}
static void
gc::MarkChildren(JSTracer *trc, BaseShape *base)
{
base->markChildren(trc);
}
/*
* This function is used by the cycle collector to trace through the
* children of a BaseShape (and its baseUnowned(), if any). The cycle
@ -1424,10 +1302,10 @@ ScanObjectGroup(GCMarker *gcmarker, ObjectGroup *group)
}
if (group->proto().isObject())
PushMarkStack(gcmarker, group->proto().toObject());
gcmarker->traverse(group->proto().toObject());
if (group->singleton() && !group->lazy())
PushMarkStack(gcmarker, group->singleton());
gcmarker->traverse(group->singleton());
if (group->newScript())
group->newScript()->trace(gcmarker);
@ -1442,10 +1320,10 @@ ScanObjectGroup(GCMarker *gcmarker, ObjectGroup *group)
PushMarkStack(gcmarker, unboxedGroup);
if (TypeDescr *descr = group->maybeTypeDescr())
PushMarkStack(gcmarker, descr);
gcmarker->traverse(descr);
if (JSFunction *fun = group->maybeInterpretedFunction())
PushMarkStack(gcmarker, fun);
gcmarker->traverse(fun);
}
static void
@ -1488,12 +1366,6 @@ gc::MarkChildren(JSTracer *trc, ObjectGroup *group)
}
}
static void
gc::MarkChildren(JSTracer *trc, jit::JitCode *code)
{
code->trace(trc);
}
template<typename T>
static void
PushArenaTyped(GCMarker *gcmarker, ArenaHeader *aheader)
@ -1666,9 +1538,9 @@ GCMarker::processMarkStackOther(uintptr_t tag, uintptr_t addr)
if (restoreValueArray(obj, (void **)&vp, (void **)&end))
pushValueArray(obj, vp, end);
else
pushObject(obj);
repush(obj);
} else if (tag == JitCodeTag) {
MarkChildren(this, reinterpret_cast<jit::JitCode *>(addr));
reinterpret_cast<jit::JitCode *>(addr)->trace(this);
}
}
@ -1676,7 +1548,7 @@ MOZ_ALWAYS_INLINE void
GCMarker::markAndScanString(JSObject *source, JSString *str)
{
if (!str->isPermanentAtom()) {
JS_COMPARTMENT_ASSERT_STR(runtime(), str);
JS_COMPARTMENT_ASSERT(runtime(), str);
MOZ_ASSERT(runtime()->isAtomsZone(str->zone()) || str->zone() == source->zone());
if (str->markIfUnmarked())
ScanString(this, str);
@ -1687,21 +1559,13 @@ MOZ_ALWAYS_INLINE void
GCMarker::markAndScanSymbol(JSObject *source, JS::Symbol *sym)
{
if (!sym->isWellKnownSymbol()) {
JS_COMPARTMENT_ASSERT_SYM(runtime(), sym);
JS_COMPARTMENT_ASSERT(runtime(), sym);
MOZ_ASSERT(runtime()->isAtomsZone(sym->zone()) || sym->zone() == source->zone());
if (sym->markIfUnmarked())
ScanSymbol(this, sym);
}
}
MOZ_ALWAYS_INLINE bool
GCMarker::markObject(JSObject *source, JSObject *obj)
{
JS_COMPARTMENT_ASSERT(runtime(), obj);
MOZ_ASSERT(obj->compartment() == source->compartment());
return obj->asTenured().markIfUnmarked(getMarkColor());
}
inline void
GCMarker::processMarkStackTop(SliceBudget &budget)
{
@ -1756,7 +1620,9 @@ GCMarker::processMarkStackTop(SliceBudget &budget)
markAndScanString(obj, v.toString());
} else if (v.isObject()) {
JSObject *obj2 = &v.toObject();
if (markObject(obj, obj2)) {
MOZ_ASSERT(obj->compartment() == obj2->compartment());
if (mark(obj2)) {
// Save the rest of this value array for later and start scanning obj2's children.N
pushValueArray(obj, vp, end);
obj = obj2;
goto scan_obj;
@ -1777,8 +1643,9 @@ GCMarker::processMarkStackTop(SliceBudget &budget)
unboxedTraceList++;
while (*unboxedTraceList != -1) {
JSObject *obj2 = *reinterpret_cast<JSObject **>(unboxedMemory + *unboxedTraceList);
if (obj2 && markObject(obj, obj2))
pushObject(obj2);
MOZ_ASSERT_IF(obj2, obj->compartment() == obj2->compartment());
if (obj2 && mark(obj2))
repush(obj2);
unboxedTraceList++;
}
unboxedTraceList++;
@ -1788,8 +1655,9 @@ GCMarker::processMarkStackTop(SliceBudget &budget)
markAndScanString(obj, v.toString());
} else if (v.isObject()) {
JSObject *obj2 = &v.toObject();
if (markObject(obj, obj2))
pushObject(obj2);
MOZ_ASSERT(obj->compartment() == obj2->compartment());
if (mark(obj2))
repush(obj2);
} else if (v.isSymbol()) {
markAndScanSymbol(obj, v.toSymbol());
}
@ -1804,12 +1672,12 @@ GCMarker::processMarkStackTop(SliceBudget &budget)
budget.step();
if (budget.isOverBudget()) {
pushObject(obj);
repush(obj);
return;
}
ObjectGroup *group = obj->groupFromGC();
PushMarkStack(this, group);
traverse(group);
Shape *shape = obj->lastProperty();
PushMarkStack(this, shape);
@ -1855,7 +1723,7 @@ GCMarker::processMarkStackTop(SliceBudget &budget)
if (nobj->denseElementsAreCopyOnWrite()) {
JSObject *owner = nobj->getElementsHeader()->ownerObject();
if (owner != nobj) {
PushMarkStack(this, owner);
traverse(owner);
break;
}
}
@ -1926,40 +1794,47 @@ GCMarker::drainMarkStack(SliceBudget &budget)
return true;
}
template <typename T>
void
GCMarker::markChildren(T *thing)
{
thing->markChildren(this);
}
void
js::TraceChildren(JSTracer *trc, void *thing, JSGCTraceKind kind)
{
switch (kind) {
case JSTRACE_OBJECT:
MarkChildren(trc, static_cast<JSObject *>(thing));
static_cast<JSObject *>(thing)->markChildren(trc);
break;
case JSTRACE_SCRIPT:
MarkChildren(trc, static_cast<JSScript *>(thing));
static_cast<JSScript *>(thing)->markChildren(trc);
break;
case JSTRACE_STRING:
MarkChildren(trc, static_cast<JSString *>(thing));
static_cast<JSString *>(thing)->markChildren(trc);
break;
case JSTRACE_SYMBOL:
MarkChildren(trc, static_cast<JS::Symbol *>(thing));
static_cast<JS::Symbol *>(thing)->markChildren(trc);
break;
case JSTRACE_BASE_SHAPE:
MarkChildren(trc, static_cast<BaseShape *>(thing));
static_cast<BaseShape *>(thing)->markChildren(trc);
break;
case JSTRACE_JITCODE:
MarkChildren(trc, (js::jit::JitCode *)thing);
static_cast<jit::JitCode *>(thing)->trace(trc);
break;
case JSTRACE_LAZY_SCRIPT:
MarkChildren(trc, static_cast<LazyScript *>(thing));
static_cast<LazyScript *>(thing)->markChildren(trc);
break;
case JSTRACE_SHAPE:
MarkChildren(trc, static_cast<Shape *>(thing));
static_cast<Shape *>(thing)->markChildren(trc);
break;
case JSTRACE_OBJECT_GROUP:
@ -1978,6 +1853,23 @@ AssertNonGrayGCThing(JSTracer *trc, void **thingp, JSGCTraceKind kind)
DebugOnly<Cell *> thing(static_cast<Cell *>(*thingp));
MOZ_ASSERT_IF(thing->isTenured(), !thing->asTenured().isMarked(js::gc::GRAY));
}
template <typename T>
bool
gc::ZoneIsGCMarking(T *thing)
{
return thing->zone()->isGCMarking();
}
template <typename T>
bool
js::gc::ZoneIsAtomsZoneForString(JSRuntime *rt, T *thing)
{
JSGCTraceKind kind = GetGCThingTraceKind(thing);
if (kind == JSTRACE_STRING || kind == JSTRACE_SYMBOL)
return rt->isAtomsZone(thing->zone());
return false;
}
#endif
static void

View File

@ -250,13 +250,6 @@ MarkCrossCompartmentSlot(JSTracer *trc, JSObject *src, HeapValue *dst_slot, cons
/*** Special Cases ***/
/*
* MarkChildren<JSObject> is exposed solely for preWriteBarrier on
* JSObject::swap. It should not be considered external interface.
*/
void
MarkChildren(JSTracer *trc, JSObject *obj);
/*
* Trace through the shape and any shapes it contains to mark
* non-shape children. This is exposed to the JS API as

View File

@ -54,7 +54,7 @@ StoreBuffer::WholeCellEdges::mark(JSTracer *trc) const
JSObject *object = static_cast<JSObject *>(edge);
if (object->is<ArgumentsObject>())
ArgumentsObject::trace(trc, object);
MarkChildren(trc, object);
object->markChildren(trc);
return;
}
MOZ_ASSERT(kind == JSTRACE_JITCODE);

View File

@ -9,13 +9,16 @@
#include "mozilla/DebugOnly.h"
#include "gc/Heap.h"
#include "js/GCAPI.h"
#include "js/SliceBudget.h"
#include "js/TracingAPI.h"
namespace js {
class NativeObject;
class BaseShape;
class GCMarker;
class LazyScript;
class NativeObject;
class ObjectGroup;
namespace gc {
struct ArenaHeader;
@ -124,6 +127,23 @@ class MarkStack
size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
};
#ifdef DEBUG
namespace gc {
template <typename T>
extern bool
ZoneIsGCMarking(T *thing);
template <typename T>
extern bool
ZoneIsAtomsZoneForString(JSRuntime *rt, T *thing);
} /* namespace gc */
#endif
#define JS_COMPARTMENT_ASSERT(rt, thing) \
MOZ_ASSERT(gc::ZoneIsGCMarking((thing)) || gc::ZoneIsAtomsZoneForString((rt), (thing)))
class GCMarker : public JSTracer
{
public:
@ -137,21 +157,16 @@ class GCMarker : public JSTracer
void stop();
void reset();
void pushObject(JSObject *obj) {
pushTaggedPtr(ObjectTag, obj);
}
void pushType(ObjectGroup *group) {
pushTaggedPtr(GroupTag, group);
}
void pushJitCode(jit::JitCode *code) {
pushTaggedPtr(JitCodeTag, code);
}
uint32_t getMarkColor() const {
return color;
}
// Mark the given GC thing and traverse its children at some point.
void traverse(JSObject *thing) { markAndPush(ObjectTag, thing); }
void traverse(ObjectGroup *thing) { markAndPush(GroupTag, thing); }
void traverse(jit::JitCode *thing) { markAndPush(JitCodeTag, thing); }
// The following traverse methods traverse immediately, go out-of-line to do so.
void traverse(JSScript *thing) { markAndTraverse(thing); }
void traverse(LazyScript *thing) { markAndTraverse(thing); }
// The other types are marked immediately and inline via a ScanFoo shared
// between PushMarkStack and the processMarkStackTop. Since ScanFoo is
// inline in Marking.cpp, we cannot inline it here, yet.
/*
* Care must be taken changing the mark color from gray to black. The cycle
@ -165,12 +180,12 @@ class GCMarker : public JSTracer
MOZ_ASSERT(color == gc::BLACK);
color = gc::GRAY;
}
void setMarkColorBlack() {
MOZ_ASSERT(isDrained());
MOZ_ASSERT(color == gc::GRAY);
color = gc::BLACK;
}
uint32_t markColor() const { return color; }
inline void delayMarkingArena(gc::ArenaHeader *aheader);
void delayMarkingChildren(const void *thing);
@ -230,7 +245,6 @@ class GCMarker : public JSTracer
ValueArrayTag,
ObjectTag,
GroupTag,
XmlTag,
SavedValueArrayTag,
JitCodeTag,
LastTag = JitCodeTag
@ -240,6 +254,37 @@ class GCMarker : public JSTracer
static_assert(StackTagMask >= uintptr_t(LastTag), "The tag mask must subsume the tags.");
static_assert(StackTagMask <= gc::CellMask, "The tag mask must be embeddable in a Cell*.");
// Push an object onto the stack for later tracing and assert that it has
// already been marked.
void repush(JSObject *obj) {
MOZ_ASSERT(gc::TenuredCell::fromPointer(obj)->isMarked(markColor()));
pushTaggedPtr(ObjectTag, obj);
}
template <typename T>
void markAndPush(StackTag tag, T *thing) {
if (mark(thing))
pushTaggedPtr(tag, thing);
}
template <typename T>
void markAndTraverse(T *thing) {
if (mark(thing))
markChildren(thing);
}
template <typename T>
void markChildren(T *thing);
// Mark the given GC thing, but do not trace its children. Return true
// if the thing became marked.
template <typename T>
bool mark(T *thing) {
JS_COMPARTMENT_ASSERT(runtime(), thing);
MOZ_ASSERT(!IsInsideNursery(gc::TenuredCell::fromPointer(thing)));
return gc::TenuredCell::fromPointer(thing)->markIfUnmarked(markColor());
}
void pushTaggedPtr(StackTag tag, void *ptr) {
checkZone(ptr);
uintptr_t addr = reinterpret_cast<uintptr_t>(ptr);

View File

@ -359,14 +359,14 @@ class ZonesIter
struct CompartmentsInZoneIter
{
explicit CompartmentsInZoneIter(JS::Zone *zone) {
explicit CompartmentsInZoneIter(JS::Zone *zone) : zone(zone) {
it = zone->compartments.begin();
end = zone->compartments.end();
}
bool done() const {
MOZ_ASSERT(it);
return it == end;
return it < zone->compartments.begin() ||
it >= zone->compartments.end();
}
void next() {
MOZ_ASSERT(!done());
@ -382,10 +382,11 @@ struct CompartmentsInZoneIter
JSCompartment *operator->() const { return get(); }
private:
JSCompartment **it, **end;
JS::Zone *zone;
JSCompartment **it;
CompartmentsInZoneIter()
: it(nullptr), end(nullptr)
: zone(nullptr), it(nullptr)
{}
// This is for the benefit of CompartmentsIterT::comp.

View File

@ -1485,9 +1485,10 @@ JS_LeaveCompartment(JSContext *cx, JSCompartment *oldCompartment);
typedef void (*JSIterateCompartmentCallback)(JSRuntime *rt, void *data, JSCompartment *compartment);
/*
* This function calls |compartmentCallback| on every compartment. Beware that
* This function calls |compartmentCallback| on every compartment. Beware that
* there is no guarantee that the compartment will survive after the callback
* returns.
* returns. Also, if the callback can GC, there is no guarantee that every
* compartment will be visited.
*/
extern JS_PUBLIC_API(void)
JS_IterateCompartments(JSRuntime *rt, void *data,

View File

@ -20,6 +20,7 @@
#include "jstypes.h"
#include "gc/Marking.h"
#include "vm/Symbol.h"
#include "vm/Xdr.h"
#include "jscntxtinlines.h"
@ -27,7 +28,6 @@
#include "jsobjinlines.h"
#include "vm/String-inl.h"
#include "vm/Symbol-inl.h"
using namespace js;
using namespace js::gc;

View File

@ -480,6 +480,8 @@ struct WeakMapTracer;
* weak map that was live at the time of the last garbage collection.
*
* m will be nullptr if the weak map is not contained in a JS Object.
*
* The callback should not GC (and will assert in a debug build if it does so.)
*/
typedef void
(* WeakMapTraceCallback)(WeakMapTracer *trc, JSObject *m, JS::GCCellPtr key, JS::GCCellPtr value);

View File

@ -2413,8 +2413,8 @@ JSObject::swap(JSContext *cx, HandleObject a, HandleObject b)
*/
JS::Zone *zone = a->zone();
if (zone->needsIncrementalBarrier()) {
MarkChildren(zone->barrierTracer(), a);
MarkChildren(zone->barrierTracer(), b);
a->markChildren(zone->barrierTracer());
b->markChildren(zone->barrierTracer());
}
NotifyGCPostSwap(a, b, r);

View File

@ -14,6 +14,7 @@
#include "jsobj.h"
#include "jswrapper.h"
#include "js/GCAPI.h"
#include "vm/GlobalObject.h"
#include "vm/WeakMapObject.h"
@ -132,8 +133,11 @@ WeakMapBase::traceAllMappings(WeakMapTracer *tracer)
{
JSRuntime *rt = tracer->runtime;
for (CompartmentsIter c(rt, SkipAtoms); !c.done(); c.next()) {
for (WeakMapBase *m = c->gcWeakMapList; m; m = m->next)
for (WeakMapBase *m = c->gcWeakMapList; m; m = m->next) {
// The WeakMapTracer callback is not allowed to GC.
JS::AutoSuppressGCAnalysis nogc;
m->traceMappings(tracer);
}
}
}

View File

@ -3208,6 +3208,18 @@ StackDump(JSContext *cx, unsigned argc, Value *vp)
}
#endif
static bool
StackPointerInfo(JSContext *cx, unsigned argc, Value *vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
// Copy the truncated stack pointer to the result. This value is not used
// as a pointer but as a way to measure frame-size from JS.
args.rval().setInt32(int32_t(reinterpret_cast<size_t>(&args) & 0xfffffff));
return true;
}
static bool
Elapsed(JSContext *cx, unsigned argc, jsval *vp)
{
@ -4897,6 +4909,11 @@ static const JSFunctionSpecWithHelp shell_functions[] = {
"isLatin1(s)",
" Return true iff the string's characters are stored as Latin1."),
JS_FN_HELP("stackPointerInfo", StackPointerInfo, 0, 0,
"stackPointerInfo()",
" Return an int32 value which corresponds to the offset of the latest stack\n"
" pointer, such that one can take the differences of 2 to estimate a frame-size."),
JS_FS_HELP_END
};

View File

@ -848,3 +848,9 @@ JS::UpdateJSRuntimeProfilerSampleBufferGen(JSRuntime *runtime, uint32_t generati
runtime->setProfilerSampleBufferGen(generation);
runtime->updateProfilerSampleBufferLapCount(lapCount);
}
JS_FRIEND_API(bool)
JS::IsProfilingEnabledForRuntime(JSRuntime *runtime)
{
return runtime->spsProfiler.enabled();
}

View File

@ -87,6 +87,12 @@ SPSProfiler::enable(bool enabled)
*/
ReleaseAllJITCode(rt->defaultFreeOp());
// Ensure that lastProfilingFrame is null before 'enabled' becomes true.
if (rt->jitActivation) {
rt->jitActivation->setLastProfilingFrame(nullptr);
rt->jitActivation->setLastProfilingCallSite(nullptr);
}
enabled_ = enabled;
/* Toggle SPS-related jumps on baseline jitcode.

View File

@ -1718,17 +1718,20 @@ JS::ProfilingFrameIterator::ProfilingFrameIterator(JSRuntime *rt, const Register
uint32_t sampleBufferGen)
: rt_(rt),
sampleBufferGen_(sampleBufferGen),
activation_(rt->profilingActivation()),
activation_(nullptr),
savedPrevJitTop_(nullptr)
{
if (!activation_)
if (!rt->spsProfiler.enabled())
MOZ_CRASH("ProfilingFrameIterator called when spsProfiler not enabled for runtime.");
if (!rt->profilingActivation())
return;
// If profiler sampling is not enabled, skip.
if (!rt_->isProfilerSamplingEnabled()) {
activation_ = nullptr;
if (!rt_->isProfilerSamplingEnabled())
return;
}
activation_ = rt->profilingActivation();
MOZ_ASSERT(activation_->isProfiling());

View File

@ -133,13 +133,6 @@ JSRope::new_(js::ExclusiveContext *cx,
return str;
}
inline void
JSRope::markChildren(JSTracer *trc)
{
js::gc::MarkStringUnbarriered(trc, &d.s.u2.left, "left child");
js::gc::MarkStringUnbarriered(trc, &d.s.u3.right, "right child");
}
MOZ_ALWAYS_INLINE void
JSDependentString::init(js::ExclusiveContext *cx, JSLinearString *base, size_t start,
size_t length)
@ -204,13 +197,6 @@ JSDependentString::new_(js::ExclusiveContext *cx, JSLinearString *baseArg, size_
return str;
}
inline void
JSString::markBase(JSTracer *trc)
{
MOZ_ASSERT(hasBase());
js::gc::MarkStringUnbarriered(trc, &d.s.u3.base, "base");
}
MOZ_ALWAYS_INLINE void
JSFlatString::init(const char16_t *chars, size_t length)
{

View File

@ -459,7 +459,10 @@ class JSString : public js::gc::TenuredCell
inline JSLinearString *base() const;
inline void markBase(JSTracer *trc);
void markBase(JSTracer *trc) {
MOZ_ASSERT(hasBase());
js::gc::MarkStringUnbarriered(trc, &d.s.u3.base, "base");
}
/* Only called by the GC for strings with the FINALIZE_STRING kind. */
@ -497,6 +500,8 @@ class JSString : public js::gc::TenuredCell
bool equals(const char *s);
#endif
inline void markChildren(JSTracer *trc);
static MOZ_ALWAYS_INLINE void readBarrier(JSString *thing) {
if (thing->isPermanentAtom())
return;
@ -554,22 +559,25 @@ class JSRope : public JSString
template <typename CharT>
bool copyChars(js::ExclusiveContext *cx, js::ScopedJSFreePtr<CharT> &out) const;
inline JSString *leftChild() const {
JSString *leftChild() const {
MOZ_ASSERT(isRope());
return d.s.u2.left;
}
inline JSString *rightChild() const {
JSString *rightChild() const {
MOZ_ASSERT(isRope());
return d.s.u3.right;
}
inline void markChildren(JSTracer *trc);
void markChildren(JSTracer *trc) {
js::gc::MarkStringUnbarriered(trc, &d.s.u2.left, "left child");
js::gc::MarkStringUnbarriered(trc, &d.s.u3.right, "right child");
}
inline static size_t offsetOfLeft() {
static size_t offsetOfLeft() {
return offsetof(JSRope, d.s.u2.left);
}
inline static size_t offsetOfRight() {
static size_t offsetOfRight() {
return offsetof(JSRope, d.s.u3.right);
}
};
@ -1227,6 +1235,15 @@ JSString::base() const
return d.s.u3.base;
}
inline void
JSString::markChildren(JSTracer *trc)
{
if (hasBase())
markBase(trc);
else if (isRope())
asRope().markChildren(trc);
}
template<>
MOZ_ALWAYS_INLINE const char16_t *
JSLinearString::nonInlineChars(const JS::AutoCheckCannotGC &nogc) const

View File

@ -1,25 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=8 sts=4 et sw=4 tw=99:
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef vm_Symbol_inl_h
#define vm_Symbol_inl_h
#include "vm/Symbol.h"
#include "gc/Marking.h"
#include "js/RootingAPI.h"
#include "jsgcinlines.h"
inline void
JS::Symbol::markChildren(JSTracer *trc)
{
if (description_)
MarkStringUnbarriered(trc, &description_, "description");
}
#endif /* vm_Symbol_inl_h */

View File

@ -15,6 +15,7 @@
#include "jsapi.h"
#include "gc/Barrier.h"
#include "gc/Marking.h"
#include "js/RootingAPI.h"
#include "js/TypeDecls.h"
@ -33,7 +34,11 @@ class Symbol : public js::gc::TenuredCell
uint64_t unused2_;
Symbol(SymbolCode code, JSAtom *desc)
: code_(code), description_(desc) {}
: code_(code), description_(desc)
{
// Silence warnings about unused2 being... unused.
(void)unused2_;
}
Symbol(const Symbol &) = delete;
void operator=(const Symbol &) = delete;
@ -51,7 +56,10 @@ class Symbol : public js::gc::TenuredCell
bool isWellKnownSymbol() const { return uint32_t(code_) < WellKnownSymbolLimit; }
static inline js::ThingRootKind rootKind() { return js::THING_ROOT_SYMBOL; }
inline void markChildren(JSTracer *trc);
inline void markChildren(JSTracer *trc) {
if (description_)
js::gc::MarkStringUnbarriered(trc, &description_, "description");
}
inline void finalize(js::FreeOp *) {}
#ifdef DEBUG

View File

@ -3325,8 +3325,8 @@ XPCJSRuntime::XPCJSRuntime(nsXPConnect* aXPConnect)
// OSX 64-bit Debug: 7MB stack, 636 stack frames => ~11.3k per stack frame
// OSX64 Opt: 7MB stack, 2440 stack frames => ~3k per stack frame
//
// Linux 32-bit Debug: 2MB stack, 447 stack frames => ~4.6k per stack frame
// Linux 64-bit Debug: 4MB stack, 501 stack frames => ~8.2k per stack frame
// Linux 32-bit Debug: 2MB stack, 426 stack frames => ~4.8k per stack frame
// Linux 64-bit Debug: 4MB stack, 455 stack frames => ~9.0k per stack frame
//
// Windows (Opt+Debug): 900K stack, 235 stack frames => ~3.4k per stack frame
//
@ -3358,9 +3358,9 @@ XPCJSRuntime::XPCJSRuntime(nsXPConnect* aXPConnect)
// were not taken at the time of this writing, so we hazard a guess that
// ASAN builds have roughly thrice the stack overhead as normal builds.
// On normal builds, the largest stack frame size we might encounter is
// 8.2k, so let's use a buffer of 8.2 * 3 * 10 = 246k.
// 9.0k (see above), so let's use a buffer of 9.0 * 3 * 10 = 270k.
const size_t kStackQuota = 2 * kDefaultStackQuota;
const size_t kTrustedScriptBuffer = 246 * 1024;
const size_t kTrustedScriptBuffer = 270 * 1024;
#elif defined(XP_WIN)
// 1MB is the default stack size on Windows, so use 900k.
// Windows PGO stack frames have unfortunately gotten pretty large lately. :-(

View File

@ -67,6 +67,11 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=732665
// enough to make the cross-compartment call. So rather than exhausting the
// stack entirely and then checking for 10 chrome frames, we leave ourselves
// one frame's worth, and check for 11.
//
// If this assertion fails, the current work-around so far is to measure
// again the worst frame size, by using the JS Shell to run
// test_bug732665_meta.js . This script will output numbers to update
// XPCJSRuntime.cpp comment, as well as the kTrustedScriptBuffer constant.
contentSb.nnslChrome = chromeSb.nearNativeStackLimit;
var nestedLimit = Cu.evalInSandbox("nearNativeStackLimit(1, function() { nestedLimit = nnslChrome(0);}); nestedLimit;", contentSb);
ok(nestedLimit >= 11, "Chrome should be invokable from content script with an exhausted stack: " + nestedLimit);

View File

@ -0,0 +1,26 @@
var bottom = stackPointerInfo();
var top = bottom;
function nearNativeStackLimit() {
function inner() {
try {
with ({}) { // keep things predictable -- stay in the interpreter
top = stackPointerInfo();
var stepsFromLimit = eval("inner()"); // Use eval to force a number of native stackframes to be created.
}
return stepsFromLimit + 1;
} catch(e) {
// It would be nice to check here that the exception is actually an
// over-recursion here. But doing so would require toString()ing the
// exception, which we may not have the stack space to do.
return 1;
}
}
return inner();
}
var nbFrames = nearNativeStackLimit();
var frameSize = bottom - top;
print("Max stack size:", frameSize, "bytes",
"\nMaximum number of frames:", nbFrames,
"\nAverage frame size:", Math.ceil(frameSize / nbFrames), "bytes");

View File

@ -1623,6 +1623,7 @@ already_AddRefed<LayerManager> nsDisplayList::PaintRoot(nsDisplayListBuilder* aB
nsIFrame* frame = aBuilder->RootReferenceFrame();
nsPresContext* presContext = frame->PresContext();
nsIPresShell* presShell = presContext->GetPresShell();
nsRootPresContext* rootPresContext = presContext->GetRootPresContext();
NotifySubDocInvalidationFunc computeInvalidFunc =
presContext->MayHavePaintEventListenerInSubDocument() ? nsPresContext::NotifySubDocInvalidation : 0;
@ -1735,6 +1736,15 @@ already_AddRefed<LayerManager> nsDisplayList::PaintRoot(nsDisplayListBuilder* aB
}
}
// If this is the content process, we ship plugin geometry updates over with layer
// updates, so calculate that now before we call EndTransaction.
if (rootPresContext &&
aBuilder->WillComputePluginGeometry() &&
XRE_GetProcessType() == GeckoProcessType_Content) {
rootPresContext->ComputePluginGeometryUpdates(aBuilder->RootReferenceFrame(), aBuilder, this);
rootPresContext->CollectPluginGeometryUpdates(layerManager);
}
MaybeSetupTransactionIdAllocator(layerManager, view);
layerManager->EndTransaction(FrameLayerBuilder::DrawPaintedLayer,
@ -4193,8 +4203,10 @@ nsDisplaySubDocument::ComputeFrameMetrics(Layer* aLayer,
nsIFrame* rootScrollFrame = presContext->PresShell()->GetRootScrollFrame();
bool isRootContentDocument = presContext->IsRootContentDocument();
nsIPresShell* presShell = presContext->PresShell();
ContainerLayerParameters params(presShell->GetXResolution(),
presShell->GetYResolution(), nsIntPoint(), aContainerParameters);
ContainerLayerParameters params(
aContainerParameters.mXScale * presShell->GetXResolution(),
aContainerParameters.mYScale * presShell->GetYResolution(),
nsIntPoint(), aContainerParameters);
if ((mFlags & GENERATE_SCROLLABLE_LAYER) &&
rootScrollFrame->GetContent() &&
nsLayoutUtils::GetCriticalDisplayPort(rootScrollFrame->GetContent(), nullptr)) {

View File

@ -2993,15 +2993,17 @@ nsLayoutUtils::PaintFrame(nsRenderingContext* aRenderingContext, nsIFrame* aFram
if (aFlags & PAINT_IGNORE_SUPPRESSION) {
builder.IgnorePaintSuppression();
}
// Windowed plugins aren't allowed in popups
// If the root has embedded plugins, flag the builder so we know we'll need
// to update plugin geometry after painting.
if ((aFlags & PAINT_WIDGET_LAYERS) &&
!willFlushRetainedLayers &&
!(aFlags & PAINT_DOCUMENT_RELATIVE) &&
rootPresContext->NeedToComputePluginGeometryUpdates()) {
builder.SetWillComputePluginGeometry(true);
}
nsRect canvasArea(nsPoint(0, 0), aFrame->GetSize());
nsRect canvasArea(nsPoint(0, 0), aFrame->GetSize());
bool ignoreViewportScrolling =
aFrame->GetParent() ? false : presShell->IgnoringViewportScrolling();
if (ignoreViewportScrolling && rootScrollFrame) {
@ -3263,28 +3265,25 @@ nsLayoutUtils::PaintFrame(nsRenderingContext* aRenderingContext, nsIFrame* aFram
}
if (builder.WillComputePluginGeometry()) {
rootPresContext->ComputePluginGeometryUpdates(aFrame, &builder, &list);
// We're not going to get a WillPaintWindow event here if we didn't do
// widget invalidation, so just apply the plugin geometry update here instead.
// We could instead have the compositor send back an equivalent to WillPaintWindow,
// but it should be close enough to now not to matter.
if (layerManager && !layerManager->NeedsWidgetInvalidation()) {
#if defined(XP_WIN) || defined(MOZ_WIDGET_GTK)
if (XRE_GetProcessType() == GeckoProcessType_Content) {
// If this is a remotely managed widget (PluginWidgetProxy in content)
// store this information in the compositor, which ships this
// over to chrome for application when we paint.
rootPresContext->CollectPluginGeometryUpdates(layerManager);
} else
#endif
{
// For single process compute and apply plugin geometry updates to plugin
// windows, then request composition. For content processes skip eveything
// except requesting composition. Geometry updates were calculated and
// shipped to the chrome process in nsDisplayList when the layer
// transaction completed.
if (XRE_GetProcessType() == GeckoProcessType_Default) {
rootPresContext->ComputePluginGeometryUpdates(aFrame, &builder, &list);
// We're not going to get a WillPaintWindow event here if we didn't do
// widget invalidation, so just apply the plugin geometry update here
// instead. We could instead have the compositor send back an equivalent
// to WillPaintWindow, but it should be close enough to now not to matter.
if (layerManager && !layerManager->NeedsWidgetInvalidation()) {
rootPresContext->ApplyPluginGeometryUpdates();
}
}
// We told the compositor thread not to composite when it received the transaction because
// we wanted to update plugins first. Schedule the composite now.
// We told the compositor thread not to composite when it received the
// transaction because we wanted to update plugins first. Schedule the
// composite now.
if (layerManager) {
layerManager->Composite();
}
@ -7228,14 +7227,25 @@ nsLayoutUtils::FontSizeInflationInner(const nsIFrame *aFrame,
f = f->GetParent()) {
nsIContent* content = f->GetContent();
nsIAtom* fType = f->GetType();
nsIFrame* parent = f->GetParent();
// Also, if there is more than one frame corresponding to a single
// content node, we want the outermost one.
if (!(f->GetParent() && f->GetParent()->GetContent() == content) &&
if (!(parent && parent->GetContent() == content) &&
// ignore width/height on inlines since they don't apply
fType != nsGkAtoms::inlineFrame &&
// ignore width on radios and checkboxes since we enlarge them and
// they have width/height in ua.css
fType != nsGkAtoms::formControlFrame) {
// ruby annotations should have the same inflation as its
// grandparent, which is the ruby frame contains the annotation.
if (fType == nsGkAtoms::rubyTextFrame) {
MOZ_ASSERT(parent &&
parent->GetType() == nsGkAtoms::rubyTextContainerFrame);
nsIFrame* grandparent = parent->GetParent();
MOZ_ASSERT(grandparent &&
grandparent->GetType() == nsGkAtoms::rubyFrame);
return FontSizeInflationFor(grandparent);
}
nsStyleCoord stylePosWidth = f->StylePosition()->mWidth;
nsStyleCoord stylePosHeight = f->StylePosition()->mHeight;
if (stylePosWidth.GetUnit() != eStyleUnit_Auto ||

View File

@ -2920,7 +2920,9 @@ nsRootPresContext::ComputePluginGeometryUpdates(nsIFrame* aFrame,
// This is not happening during a paint event.
ApplyPluginGeometryUpdates();
#else
InitApplyPluginGeometryTimer();
if (XRE_GetProcessType() == GeckoProcessType_Default) {
InitApplyPluginGeometryTimer();
}
#endif
}

View File

@ -3,6 +3,7 @@
<script src="/tests/SimpleTest/EventUtils.js"></script>
<script>
function test() {
focus();
synthesizeMouseAtCenter(document.querySelector("span"), {});
}
function focused() {

View File

@ -13,6 +13,7 @@
# include "LayerManagerD3D9.h"
#endif //MOZ_ENABLE_D3D9_LAYER
#include "mozilla/BrowserElementParent.h"
#include "mozilla/EventForwards.h" // for Modifiers
#include "mozilla/dom/ContentChild.h"
#include "mozilla/dom/TabParent.h"
#include "mozilla/layers/APZCTreeManager.h"
@ -119,7 +120,7 @@ public:
}
virtual void HandleDoubleTap(const CSSPoint& aPoint,
int32_t aModifiers,
Modifiers aModifiers,
const ScrollableLayerGuid& aGuid) MOZ_OVERRIDE
{
if (MessageLoop::current() != mUILoop) {
@ -138,7 +139,7 @@ public:
}
virtual void HandleSingleTap(const CSSPoint& aPoint,
int32_t aModifiers,
Modifiers aModifiers,
const ScrollableLayerGuid& aGuid) MOZ_OVERRIDE
{
if (MessageLoop::current() != mUILoop) {
@ -158,7 +159,7 @@ public:
}
virtual void HandleLongTap(const CSSPoint& aPoint,
int32_t aModifiers,
Modifiers aModifiers,
const ScrollableLayerGuid& aGuid,
uint64_t aInputBlockId) MOZ_OVERRIDE
{
@ -178,7 +179,7 @@ public:
}
virtual void HandleLongTapUp(const CSSPoint& aPoint,
int32_t aModifiers,
Modifiers aModifiers,
const ScrollableLayerGuid& aGuid) MOZ_OVERRIDE
{
if (MessageLoop::current() != mUILoop) {

View File

@ -0,0 +1,6 @@
<!DOCTYPE HTML>
<style>
div { font-family: monospace; font-size: 34px; width: 450px; }
rt { font-size: 50%; }
</style>
<div><ruby><rb>base<rt>rubytext</ruby></div>

View File

@ -0,0 +1,10 @@
<!DOCTYPE HTML>
<style>
div { font-family: monospace; font-size: 12px; width: 450px; }
rt { font-size: 50%; }
</style>
<!--
In a 450px container, the minimum font size at 15em per line is 30px.
This means we map 0px-45px into 30px-45px, so 12px gets mapped to 34px.
-->
<div><ruby><rb>base<rt>rubytext</ruby></div>

Some files were not shown because too many files have changed in this diff Show More