зеркало из https://github.com/mozilla/gecko-dev.git
merge mozilla-inbound to mozilla-central a=merge
This commit is contained in:
Коммит
e8beb2e4be
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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>
|
|
@ -0,0 +1,6 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<body>
|
||||
<h3>Subframe I am.</h3>
|
||||
</body>
|
||||
</html>
|
|
@ -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>
|
|
@ -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]
|
||||
|
|
|
@ -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>
|
|
@ -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.");
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 {
|
||||
{
|
||||
|
|
|
@ -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]);
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -122,6 +122,7 @@ EXPORTS += [
|
|||
'SharedThreadPool.h',
|
||||
'StreamBuffer.h',
|
||||
'ThreadPoolCOMListener.h',
|
||||
'TimeUnits.h',
|
||||
'TimeVarying.h',
|
||||
'TrackUnionStream.h',
|
||||
'VideoFrameContainer.h',
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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]
|
||||
|
|
Двоичный файл не отображается.
|
@ -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>
|
|
@ -38,7 +38,7 @@ function startTest(test, token)
|
|||
manager.finished(token);
|
||||
});
|
||||
|
||||
LoadTest(test, v, token);
|
||||
PlayFragmented(test, v, token);
|
||||
}
|
||||
|
||||
function beginTest() {
|
||||
|
|
|
@ -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>
|
||||
|
|
@ -52,7 +52,7 @@ function startTest(test, token)
|
|||
manager.finished(token);
|
||||
});
|
||||
|
||||
LoadTest(test, v, token);
|
||||
PlayFragmented(test, v, token);
|
||||
}
|
||||
|
||||
function beginTest() {
|
||||
|
|
|
@ -147,7 +147,7 @@ function startTest(test, token)
|
|||
}
|
||||
);
|
||||
|
||||
LoadTest(test, v, token);
|
||||
PlayFragmented(test, v, token);
|
||||
}
|
||||
|
||||
function beginTest() {
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -168,6 +168,8 @@ public:
|
|||
|
||||
virtual TemporaryRef<gfx::SourceSurface> GetAsSourceSurface() = 0;
|
||||
|
||||
virtual bool IsValid() { return true; }
|
||||
|
||||
virtual GrallocImage* AsGrallocImage()
|
||||
{
|
||||
return nullptr;
|
||||
|
|
|
@ -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;
|
||||
|
||||
/**
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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*
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 {}
|
||||
|
|
|
@ -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(),
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
};
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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());
|
||||
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 */
|
|
@ -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
|
||||
|
|
|
@ -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. :-(
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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");
|
|
@ -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)) {
|
||||
|
|
|
@ -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 ||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
<script src="/tests/SimpleTest/EventUtils.js"></script>
|
||||
<script>
|
||||
function test() {
|
||||
focus();
|
||||
synthesizeMouseAtCenter(document.querySelector("span"), {});
|
||||
}
|
||||
function focused() {
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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>
|
|
@ -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>
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче