mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-09 19:35:51 +00:00
Merge mozilla-central and inbound
This commit is contained in:
commit
0916bd9c19
@ -835,8 +835,6 @@ GK_ATOM(ontext, "ontext")
|
||||
GK_ATOM(ontouchstart, "ontouchstart")
|
||||
GK_ATOM(ontouchend, "ontouchend")
|
||||
GK_ATOM(ontouchmove, "ontouchmove")
|
||||
GK_ATOM(ontouchenter, "ontouchenter")
|
||||
GK_ATOM(ontouchleave, "ontouchleave")
|
||||
GK_ATOM(ontouchcancel, "ontouchcancel")
|
||||
GK_ATOM(ontransitionend, "ontransitionend")
|
||||
GK_ATOM(onunderflow, "onunderflow")
|
||||
|
@ -6599,6 +6599,8 @@ HTMLInputElement::UpdateValueMissingValidityStateForRadio(bool aIgnoreSelf)
|
||||
bool notify = !mParserCreating;
|
||||
nsCOMPtr<nsIDOMHTMLInputElement> selection = GetSelectedRadioButton();
|
||||
|
||||
aIgnoreSelf = aIgnoreSelf || !IsMutable();
|
||||
|
||||
// If there is no selection, that might mean the radio is not in a group.
|
||||
// In that case, we can look for the checked state of the radio.
|
||||
bool selected = selection || (!aIgnoreSelf && mChecked);
|
||||
@ -6624,7 +6626,7 @@ HTMLInputElement::UpdateValueMissingValidityStateForRadio(bool aIgnoreSelf)
|
||||
: container->GetRequiredRadioCount(name);
|
||||
}
|
||||
|
||||
valueMissing = IsMutable() && required && !selected;
|
||||
valueMissing = required && !selected;
|
||||
|
||||
if (container->GetValueMissingState(name) != valueMissing) {
|
||||
container->SetValueMissingState(name, valueMissing);
|
||||
|
@ -414,6 +414,7 @@ skip-if = (toolkit == 'gonk' && debug) || e10s #debug-only failure
|
||||
[test_bug885024.html]
|
||||
[test_bug893537.html]
|
||||
[test_bug969346.html]
|
||||
[test_bug982039.html]
|
||||
[test_bug1003539.html]
|
||||
[test_change_crossorigin.html]
|
||||
[test_checked.html]
|
||||
|
46
content/html/content/test/test_bug982039.html
Normal file
46
content/html/content/test/test_bug982039.html
Normal file
@ -0,0 +1,46 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=982039
|
||||
-->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for Bug 982039</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
<script type="application/javascript">
|
||||
|
||||
/** Test for Bug 982039 **/
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
function test() {
|
||||
var f = document.getElementById("testform");
|
||||
f.elements[0].disabled = true;
|
||||
is(f.checkValidity(), false,
|
||||
"Setting a radiobutton to disabled shouldn't make form valid.");
|
||||
|
||||
f.elements[1].checked = true;
|
||||
ok(f.checkValidity(), "Form should be now valid.");
|
||||
|
||||
f.elements[0].required = false;
|
||||
f.elements[1].required = false;
|
||||
f.elements[2].required = false;
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
</script>
|
||||
</head>
|
||||
<body onload="test()">
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=982039">Mozilla Bug 982039</a>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
|
||||
</div>
|
||||
<pre id="test">
|
||||
</pre>
|
||||
<form action="#" id="testform">
|
||||
<input type="radio" name="radio" value="1" required>
|
||||
<input type="radio" name="radio" value="2" required>
|
||||
<input type="radio" name="radio" value="3" required>
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
@ -96,26 +96,15 @@ SVGEllipseElement::GetLengthInfo()
|
||||
void
|
||||
SVGEllipseElement::ConstructPath(gfxContext *aCtx)
|
||||
{
|
||||
if (!aCtx->IsCairo()) {
|
||||
RefPtr<DrawTarget> dt = aCtx->GetDrawTarget();
|
||||
FillRule fillRule =
|
||||
aCtx->CurrentFillRule() == gfxContext::FILL_RULE_WINDING ?
|
||||
FillRule::FILL_WINDING : FillRule::FILL_EVEN_ODD;
|
||||
RefPtr<PathBuilder> builder = dt->CreatePathBuilder(fillRule);
|
||||
RefPtr<Path> path = BuildPath(builder);
|
||||
if (path) {
|
||||
nsRefPtr<gfxPath> gfxpath = new gfxPath(path);
|
||||
aCtx->SetPath(gfxpath);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
float x, y, rx, ry;
|
||||
|
||||
GetAnimatedLengthValues(&x, &y, &rx, &ry, nullptr);
|
||||
|
||||
if (rx > 0.0f && ry > 0.0f) {
|
||||
aCtx->Ellipse(gfxPoint(x, y), gfxSize(2.0*rx, 2.0*ry));
|
||||
RefPtr<DrawTarget> dt = aCtx->GetDrawTarget();
|
||||
FillRule fillRule =
|
||||
aCtx->CurrentFillRule() == gfxContext::FILL_RULE_WINDING ?
|
||||
FillRule::FILL_WINDING : FillRule::FILL_EVEN_ODD;
|
||||
RefPtr<PathBuilder> builder = dt->CreatePathBuilder(fillRule);
|
||||
RefPtr<Path> path = BuildPath(builder);
|
||||
if (path) {
|
||||
nsRefPtr<gfxPath> gfxpath = new gfxPath(path);
|
||||
aCtx->SetPath(gfxpath);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -809,7 +809,7 @@ Navigator::Vibrate(const nsTArray<uint32_t>& aPattern)
|
||||
|
||||
// The spec says we check sVibratorEnabled after we've done the sanity
|
||||
// checking on the pattern.
|
||||
if (pattern.IsEmpty() || !sVibratorEnabled) {
|
||||
if (!sVibratorEnabled) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -688,6 +688,23 @@ GetButtonsFlagForButton(int32_t aButton)
|
||||
}
|
||||
}
|
||||
|
||||
nsView*
|
||||
nsDOMWindowUtils::GetViewToDispatchEvent(nsPresContext* presContext, nsIPresShell** presShell)
|
||||
{
|
||||
if (presContext && presShell) {
|
||||
*presShell = presContext->PresShell();
|
||||
if (*presShell) {
|
||||
NS_ADDREF(*presShell);
|
||||
if (nsViewManager* viewManager = (*presShell)->GetViewManager()) {
|
||||
if (nsView* view = viewManager->GetRootView()) {
|
||||
return view;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDOMWindowUtils::SendMouseEventCommon(const nsAString& aType,
|
||||
float aX,
|
||||
@ -756,44 +773,42 @@ nsDOMWindowUtils::SendMouseEventCommon(const nsAString& aType,
|
||||
|
||||
nsEventStatus status;
|
||||
if (aToWindow) {
|
||||
nsCOMPtr<nsIPresShell> presShell = presContext->PresShell();
|
||||
if (!presShell)
|
||||
nsCOMPtr<nsIPresShell> presShell;
|
||||
nsView* view = GetViewToDispatchEvent(presContext, getter_AddRefs(presShell));
|
||||
if (!presShell || !view) {
|
||||
return NS_ERROR_FAILURE;
|
||||
nsViewManager* viewManager = presShell->GetViewManager();
|
||||
if (!viewManager)
|
||||
return NS_ERROR_FAILURE;
|
||||
nsView* view = viewManager->GetRootView();
|
||||
if (!view)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
}
|
||||
status = nsEventStatus_eIgnore;
|
||||
return presShell->HandleEvent(view->GetFrame(), &event, false, &status);
|
||||
}
|
||||
nsresult rv = widget->DispatchEvent(&event, status);
|
||||
*aPreventDefault = (status == nsEventStatus_eConsumeNoDefault);
|
||||
if (aPreventDefault) {
|
||||
*aPreventDefault = (status == nsEventStatus_eConsumeNoDefault);
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDOMWindowUtils::SendPointerEvent(const nsAString& aType,
|
||||
float aX,
|
||||
float aY,
|
||||
int32_t aButton,
|
||||
int32_t aClickCount,
|
||||
int32_t aModifiers,
|
||||
bool aIgnoreRootScrollFrame,
|
||||
float aPressure,
|
||||
unsigned short aInputSourceArg,
|
||||
int32_t aPointerId,
|
||||
int32_t aWidth,
|
||||
int32_t aHeight,
|
||||
int32_t tiltX,
|
||||
int32_t tiltY,
|
||||
bool aIsPrimary,
|
||||
bool aIsSynthesized,
|
||||
uint8_t aOptionalArgCount,
|
||||
bool* aPreventDefault)
|
||||
nsDOMWindowUtils::SendPointerEventCommon(const nsAString& aType,
|
||||
float aX,
|
||||
float aY,
|
||||
int32_t aButton,
|
||||
int32_t aClickCount,
|
||||
int32_t aModifiers,
|
||||
bool aIgnoreRootScrollFrame,
|
||||
float aPressure,
|
||||
unsigned short aInputSourceArg,
|
||||
int32_t aPointerId,
|
||||
int32_t aWidth,
|
||||
int32_t aHeight,
|
||||
int32_t aTiltX,
|
||||
int32_t aTiltY,
|
||||
bool aIsPrimary,
|
||||
bool aIsSynthesized,
|
||||
uint8_t aOptionalArgCount,
|
||||
bool aToWindow,
|
||||
bool* aPreventDefault)
|
||||
{
|
||||
MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
|
||||
|
||||
@ -833,8 +848,8 @@ nsDOMWindowUtils::SendPointerEvent(const nsAString& aType,
|
||||
event.pointerId = aPointerId;
|
||||
event.width = aWidth;
|
||||
event.height = aHeight;
|
||||
event.tiltX = tiltX;
|
||||
event.tiltY = tiltY;
|
||||
event.tiltX = aTiltX;
|
||||
event.tiltY = aTiltY;
|
||||
event.isPrimary = aIsPrimary;
|
||||
event.clickCount = aClickCount;
|
||||
event.time = PR_IntervalNow();
|
||||
@ -849,12 +864,84 @@ nsDOMWindowUtils::SendPointerEvent(const nsAString& aType,
|
||||
event.ignoreRootScrollFrame = aIgnoreRootScrollFrame;
|
||||
|
||||
nsEventStatus status;
|
||||
if (aToWindow) {
|
||||
nsCOMPtr<nsIPresShell> presShell;
|
||||
nsView* view = GetViewToDispatchEvent(presContext, getter_AddRefs(presShell));
|
||||
if (!presShell || !view) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
status = nsEventStatus_eIgnore;
|
||||
return presShell->HandleEvent(view->GetFrame(), &event, false, &status);
|
||||
}
|
||||
nsresult rv = widget->DispatchEvent(&event, status);
|
||||
*aPreventDefault = (status == nsEventStatus_eConsumeNoDefault);
|
||||
if (aPreventDefault) {
|
||||
*aPreventDefault = (status == nsEventStatus_eConsumeNoDefault);
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDOMWindowUtils::SendPointerEvent(const nsAString& aType,
|
||||
float aX,
|
||||
float aY,
|
||||
int32_t aButton,
|
||||
int32_t aClickCount,
|
||||
int32_t aModifiers,
|
||||
bool aIgnoreRootScrollFrame,
|
||||
float aPressure,
|
||||
unsigned short aInputSourceArg,
|
||||
int32_t aPointerId,
|
||||
int32_t aWidth,
|
||||
int32_t aHeight,
|
||||
int32_t aTiltX,
|
||||
int32_t aTiltY,
|
||||
bool aIsPrimary,
|
||||
bool aIsSynthesized,
|
||||
uint8_t aOptionalArgCount,
|
||||
bool* aPreventDefault)
|
||||
{
|
||||
PROFILER_LABEL("nsDOMWindowUtils", "SendPointerEvent",
|
||||
js::ProfileEntry::Category::EVENTS);
|
||||
|
||||
return SendPointerEventCommon(aType, aX, aY, aButton, aClickCount,
|
||||
aModifiers, aIgnoreRootScrollFrame,
|
||||
aPressure, aInputSourceArg, aPointerId,
|
||||
aWidth, aHeight, aTiltX, aTiltY,
|
||||
aIsPrimary, aIsSynthesized,
|
||||
aOptionalArgCount, false, aPreventDefault);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDOMWindowUtils::SendPointerEventToWindow(const nsAString& aType,
|
||||
float aX,
|
||||
float aY,
|
||||
int32_t aButton,
|
||||
int32_t aClickCount,
|
||||
int32_t aModifiers,
|
||||
bool aIgnoreRootScrollFrame,
|
||||
float aPressure,
|
||||
unsigned short aInputSourceArg,
|
||||
int32_t aPointerId,
|
||||
int32_t aWidth,
|
||||
int32_t aHeight,
|
||||
int32_t aTiltX,
|
||||
int32_t aTiltY,
|
||||
bool aIsPrimary,
|
||||
bool aIsSynthesized,
|
||||
uint8_t aOptionalArgCount)
|
||||
{
|
||||
PROFILER_LABEL("nsDOMWindowUtils", "SendPointerEventToWindow",
|
||||
js::ProfileEntry::Category::EVENTS);
|
||||
|
||||
return SendPointerEventCommon(aType, aX, aY, aButton, aClickCount,
|
||||
aModifiers, aIgnoreRootScrollFrame,
|
||||
aPressure, aInputSourceArg, aPointerId,
|
||||
aWidth, aHeight, aTiltX, aTiltY,
|
||||
aIsPrimary, aIsSynthesized,
|
||||
aOptionalArgCount, true, nullptr);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDOMWindowUtils::SendWheelEvent(float aX,
|
||||
float aY,
|
||||
@ -1042,21 +1129,11 @@ nsDOMWindowUtils::SendTouchEventCommon(const nsAString& aType,
|
||||
|
||||
nsEventStatus status;
|
||||
if (aToWindow) {
|
||||
nsCOMPtr<nsIPresShell> presShell = presContext->PresShell();
|
||||
if (!presShell) {
|
||||
nsCOMPtr<nsIPresShell> presShell;
|
||||
nsView* view = GetViewToDispatchEvent(presContext, getter_AddRefs(presShell));
|
||||
if (!presShell || !view) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsViewManager* viewManager = presShell->GetViewManager();
|
||||
if (!viewManager) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsView* view = viewManager->GetRootView();
|
||||
if (!view) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
status = nsEventStatus_eIgnore;
|
||||
*aPreventDefault = (status == nsEventStatus_eConsumeNoDefault);
|
||||
return presShell->HandleEvent(view->GetFrame(), &event, false, &status);
|
||||
|
@ -17,6 +17,7 @@ class nsIPresShell;
|
||||
class nsIWidget;
|
||||
class nsPresContext;
|
||||
class nsIDocument;
|
||||
class nsView;
|
||||
struct nsPoint;
|
||||
|
||||
namespace mozilla {
|
||||
@ -78,6 +79,8 @@ protected:
|
||||
nsIDocument* GetDocument();
|
||||
mozilla::layers::LayerTransactionChild* GetLayerTransaction();
|
||||
|
||||
nsView* GetViewToDispatchEvent(nsPresContext* presContext, nsIPresShell** presShell);
|
||||
|
||||
NS_IMETHOD SendMouseEventCommon(const nsAString& aType,
|
||||
float aX,
|
||||
float aY,
|
||||
@ -91,6 +94,26 @@ protected:
|
||||
bool *aPreventDefault,
|
||||
bool aIsSynthesized);
|
||||
|
||||
NS_IMETHOD SendPointerEventCommon(const nsAString& aType,
|
||||
float aX,
|
||||
float aY,
|
||||
int32_t aButton,
|
||||
int32_t aClickCount,
|
||||
int32_t aModifiers,
|
||||
bool aIgnoreRootScrollFrame,
|
||||
float aPressure,
|
||||
unsigned short aInputSourceArg,
|
||||
int32_t aPointerId,
|
||||
int32_t aWidth,
|
||||
int32_t aHeight,
|
||||
int32_t aTiltX,
|
||||
int32_t aTiltY,
|
||||
bool aIsPrimary,
|
||||
bool aIsSynthesized,
|
||||
uint8_t aOptionalArgCount,
|
||||
bool aToWindow,
|
||||
bool* aPreventDefault);
|
||||
|
||||
NS_IMETHOD SendTouchEventCommon(const nsAString& aType,
|
||||
uint32_t* aIdentifiers,
|
||||
int32_t* aXs,
|
||||
@ -105,7 +128,6 @@ protected:
|
||||
bool aToWindow,
|
||||
bool* aPreventDefault);
|
||||
|
||||
|
||||
static mozilla::Modifiers GetWidgetModifiers(int32_t aModifiers);
|
||||
};
|
||||
|
||||
|
@ -328,8 +328,6 @@ EventListenerManager::AddEventListenerInternal(
|
||||
} else if (aTypeAtom == nsGkAtoms::ontouchstart ||
|
||||
aTypeAtom == nsGkAtoms::ontouchend ||
|
||||
aTypeAtom == nsGkAtoms::ontouchmove ||
|
||||
aTypeAtom == nsGkAtoms::ontouchenter ||
|
||||
aTypeAtom == nsGkAtoms::ontouchleave ||
|
||||
aTypeAtom == nsGkAtoms::ontouchcancel) {
|
||||
mMayHaveTouchEventListener = true;
|
||||
nsPIDOMWindow* window = GetInnerWindowForTarget();
|
||||
|
@ -559,14 +559,6 @@ TOUCH_EVENT(touchmove,
|
||||
NS_TOUCH_MOVE,
|
||||
EventNameType_All,
|
||||
NS_TOUCH_EVENT )
|
||||
TOUCH_EVENT(touchenter,
|
||||
NS_TOUCH_ENTER,
|
||||
EventNameType_All,
|
||||
NS_TOUCH_EVENT )
|
||||
TOUCH_EVENT(touchleave,
|
||||
NS_TOUCH_LEAVE,
|
||||
EventNameType_All,
|
||||
NS_TOUCH_EVENT)
|
||||
TOUCH_EVENT(touchcancel,
|
||||
NS_TOUCH_CANCEL,
|
||||
EventNameType_All,
|
||||
|
@ -3848,9 +3848,13 @@ EventStateManager::NotifyMouseOver(WidgetMouseEvent* aMouseEvent,
|
||||
{
|
||||
NS_ASSERTION(aContent, "Mouse must be over something");
|
||||
|
||||
// If pointer capture is set, we should suppress pointerover/pointerenter events
|
||||
// for all elements except element which have pointer capture.
|
||||
bool dispatch = !aMouseEvent->retargetedByPointerCapture;
|
||||
|
||||
OverOutElementsWrapper* wrapper = GetWrapperByEventID(aMouseEvent);
|
||||
|
||||
if (wrapper->mLastOverElement == aContent)
|
||||
if (wrapper->mLastOverElement == aContent && dispatch)
|
||||
return;
|
||||
|
||||
// Before firing mouseover, check for recursion
|
||||
@ -3861,12 +3865,9 @@ EventStateManager::NotifyMouseOver(WidgetMouseEvent* aMouseEvent,
|
||||
// document's ESM state to indicate that the mouse is over the
|
||||
// content associated with our subdocument.
|
||||
EnsureDocument(mPresContext);
|
||||
nsIDocument *parentDoc = mDocument->GetParentDocument();
|
||||
if (parentDoc) {
|
||||
nsIContent *docContent = parentDoc->FindContentForSubDocument(mDocument);
|
||||
if (docContent) {
|
||||
nsIPresShell *parentShell = parentDoc->GetShell();
|
||||
if (parentShell) {
|
||||
if (nsIDocument *parentDoc = mDocument->GetParentDocument()) {
|
||||
if (nsIContent *docContent = parentDoc->FindContentForSubDocument(mDocument)) {
|
||||
if (nsIPresShell *parentShell = parentDoc->GetShell()) {
|
||||
EventStateManager* parentESM =
|
||||
parentShell->GetPresContext()->EventStateManager();
|
||||
parentESM->NotifyMouseOver(aMouseEvent, docContent);
|
||||
@ -3875,7 +3876,7 @@ EventStateManager::NotifyMouseOver(WidgetMouseEvent* aMouseEvent,
|
||||
}
|
||||
// Firing the DOM event in the parent document could cause all kinds
|
||||
// of havoc. Reverify and take care.
|
||||
if (wrapper->mLastOverElement == aContent)
|
||||
if (wrapper->mLastOverElement == aContent && dispatch)
|
||||
return;
|
||||
|
||||
// Remember mLastOverElement as the related content for the
|
||||
@ -3883,10 +3884,12 @@ EventStateManager::NotifyMouseOver(WidgetMouseEvent* aMouseEvent,
|
||||
nsCOMPtr<nsIContent> lastOverElement = wrapper->mLastOverElement;
|
||||
|
||||
bool isPointer = aMouseEvent->eventStructType == NS_POINTER_EVENT;
|
||||
EnterLeaveDispatcher enterDispatcher(this, aContent, lastOverElement,
|
||||
aMouseEvent,
|
||||
isPointer ? NS_POINTER_ENTER :
|
||||
NS_MOUSEENTER);
|
||||
|
||||
Maybe<EnterLeaveDispatcher> enterDispatcher;
|
||||
if (dispatch) {
|
||||
enterDispatcher.construct(this, aContent, lastOverElement, aMouseEvent,
|
||||
isPointer ? NS_POINTER_ENTER : NS_MOUSEENTER);
|
||||
}
|
||||
|
||||
NotifyMouseOut(aMouseEvent, aContent);
|
||||
|
||||
@ -3898,13 +3901,17 @@ EventStateManager::NotifyMouseOver(WidgetMouseEvent* aMouseEvent,
|
||||
SetContentState(aContent, NS_EVENT_STATE_HOVER);
|
||||
}
|
||||
|
||||
// Fire mouseover
|
||||
wrapper->mLastOverFrame =
|
||||
DispatchMouseOrPointerEvent(aMouseEvent,
|
||||
isPointer ? NS_POINTER_OVER :
|
||||
NS_MOUSE_ENTER_SYNTH,
|
||||
aContent, lastOverElement);
|
||||
wrapper->mLastOverElement = aContent;
|
||||
if (dispatch) {
|
||||
// Fire mouseover
|
||||
wrapper->mLastOverFrame =
|
||||
DispatchMouseOrPointerEvent(aMouseEvent,
|
||||
isPointer ? NS_POINTER_OVER : NS_MOUSE_ENTER_SYNTH,
|
||||
aContent, lastOverElement);
|
||||
wrapper->mLastOverElement = aContent;
|
||||
} else {
|
||||
wrapper->mLastOverFrame = nullptr;
|
||||
wrapper->mLastOverElement = nullptr;
|
||||
}
|
||||
|
||||
// Turn recursion protection back off
|
||||
wrapper->mFirstOverEventElement = nullptr;
|
||||
|
@ -74,8 +74,6 @@ var events =
|
||||
["touchstart",
|
||||
"touchend",
|
||||
"touchmove",
|
||||
"touchenter",
|
||||
"touchleave",
|
||||
"touchcancel"];
|
||||
|
||||
function runEventTest(type) {
|
||||
|
@ -51,7 +51,7 @@ interface nsITranslationNodeList;
|
||||
interface nsIJSRAIIHelper;
|
||||
interface nsIContentPermissionRequest;
|
||||
|
||||
[scriptable, uuid(0ef9e8bb-b934-4f6b-ae05-e98774d8d3d3)]
|
||||
[scriptable, uuid(11911980-607c-4efd-aacc-de3b9005c058)]
|
||||
interface nsIDOMWindowUtils : nsISupports {
|
||||
|
||||
/**
|
||||
@ -371,8 +371,8 @@ interface nsIDOMWindowUtils : nsISupports {
|
||||
[optional] in long aPointerId,
|
||||
[optional] in long aWidth,
|
||||
[optional] in long aHeight,
|
||||
[optional] in long tiltX,
|
||||
[optional] in long tiltY,
|
||||
[optional] in long aTiltX,
|
||||
[optional] in long aTiltY,
|
||||
[optional] in boolean aIsPrimary,
|
||||
[optional] in boolean aIsSynthesized);
|
||||
|
||||
@ -429,6 +429,27 @@ interface nsIDOMWindowUtils : nsISupports {
|
||||
[optional] in unsigned short aInputSourceArg,
|
||||
[optional] in boolean aIsSynthesized);
|
||||
|
||||
/** The same as sendPointerEvent but ensures that the event
|
||||
* is dispatched to this DOM window or one of its children.
|
||||
*/
|
||||
[optional_argc]
|
||||
void sendPointerEventToWindow(in AString aType,
|
||||
in float aX,
|
||||
in float aY,
|
||||
in long aButton,
|
||||
in long aClickCount,
|
||||
in long aModifiers,
|
||||
[optional] in boolean aIgnoreRootScrollFrame,
|
||||
[optional] in float aPressure,
|
||||
[optional] in unsigned short aInputSourceArg,
|
||||
[optional] in long aPointerId,
|
||||
[optional] in long aWidth,
|
||||
[optional] in long aHeight,
|
||||
[optional] in long aTiltX,
|
||||
[optional] in long aTiltY,
|
||||
[optional] in boolean aIsPrimary,
|
||||
[optional] in boolean aIsSynthesized);
|
||||
|
||||
/** The same as sendTouchEvent but ensures that the event is dispatched to
|
||||
* this DOM window or one of its children.
|
||||
*/
|
||||
|
@ -15,7 +15,5 @@ interface nsITouchEventReceiver : nsISupports {
|
||||
[implicit_jscontext] attribute jsval ontouchstart;
|
||||
[implicit_jscontext] attribute jsval ontouchend;
|
||||
[implicit_jscontext] attribute jsval ontouchmove;
|
||||
[implicit_jscontext] attribute jsval ontouchenter;
|
||||
[implicit_jscontext] attribute jsval ontouchleave;
|
||||
[implicit_jscontext] attribute jsval ontouchcancel;
|
||||
};
|
||||
|
@ -110,10 +110,6 @@ interface TouchEventHandlers {
|
||||
attribute EventHandler ontouchend;
|
||||
[Func="nsGenericHTMLElement::TouchEventsEnabled"]
|
||||
attribute EventHandler ontouchmove;
|
||||
[Func="nsGenericHTMLElement::TouchEventsEnabled"]
|
||||
attribute EventHandler ontouchenter;
|
||||
[Func="nsGenericHTMLElement::TouchEventsEnabled"]
|
||||
attribute EventHandler ontouchleave;
|
||||
[Func="nsGenericHTMLElement::TouchEventsEnabled"]
|
||||
attribute EventHandler ontouchcancel;
|
||||
};
|
||||
|
@ -870,6 +870,9 @@ cairo_type1_font_subset_look_for_seac(cairo_type1_font_subset_t *font,
|
||||
* glyph is composed from. All we need to do is to
|
||||
* make sure those glyphs are present in the subset
|
||||
* under their standard names. */
|
||||
if (unlikely (sp < 5))
|
||||
return CAIRO_INT_STATUS_UNSUPPORTED;
|
||||
|
||||
status = use_standard_encoding_glyph (font, stack[3]);
|
||||
if (unlikely (status))
|
||||
return status;
|
||||
|
@ -637,15 +637,14 @@ CairoImage::GetTextureClient(CompositableClient *aClient)
|
||||
|
||||
// gfx::BackendType::NONE means default to content backend
|
||||
textureClient = aClient->CreateTextureClientForDrawing(surface->GetFormat(),
|
||||
TextureFlags::DEFAULT,
|
||||
surface->GetSize(),
|
||||
gfx::BackendType::NONE,
|
||||
surface->GetSize());
|
||||
TextureFlags::DEFAULT);
|
||||
if (!textureClient) {
|
||||
return nullptr;
|
||||
}
|
||||
MOZ_ASSERT(textureClient->CanExposeDrawTarget());
|
||||
if (!textureClient->AllocateForSurface(surface->GetSize()) ||
|
||||
!textureClient->Lock(OpenMode::OPEN_WRITE_ONLY)) {
|
||||
if (!textureClient->Lock(OpenMode::OPEN_WRITE_ONLY)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
@ -1621,29 +1621,6 @@ SetAntialiasingFlags(Layer* aLayer, DrawTarget* aTarget)
|
||||
aTarget->SetPermitSubpixelAA(permitSubpixelAA);
|
||||
}
|
||||
|
||||
void
|
||||
SetAntialiasingFlags(Layer* aLayer, gfxContext* aTarget)
|
||||
{
|
||||
if (!aTarget->IsCairo()) {
|
||||
SetAntialiasingFlags(aLayer, aTarget->GetDrawTarget());
|
||||
return;
|
||||
}
|
||||
|
||||
bool permitSubpixelAA = !(aLayer->GetContentFlags() & Layer::CONTENT_DISABLE_SUBPIXEL_AA);
|
||||
nsRefPtr<gfxASurface> surface = aTarget->CurrentSurface();
|
||||
if (surface->GetContentType() != gfxContentType::COLOR_ALPHA) {
|
||||
// Destination doesn't have alpha channel; no need to set any special flags
|
||||
surface->SetSubpixelAntialiasingEnabled(permitSubpixelAA);
|
||||
return;
|
||||
}
|
||||
|
||||
const nsIntRect& bounds = aLayer->GetVisibleRegion().GetBounds();
|
||||
permitSubpixelAA &= !(aLayer->GetContentFlags() & Layer::CONTENT_COMPONENT_ALPHA) ||
|
||||
surface->GetOpaqueRect().Contains(
|
||||
aTarget->UserToDevice(gfxRect(bounds.x, bounds.y, bounds.width, bounds.height)));
|
||||
surface->SetSubpixelAntialiasingEnabled(permitSubpixelAA);
|
||||
}
|
||||
|
||||
PRLogModuleInfo* LayerManager::sLog;
|
||||
|
||||
} // namespace layers
|
||||
|
@ -2178,7 +2178,6 @@ protected:
|
||||
uint64_t mId;
|
||||
};
|
||||
|
||||
void SetAntialiasingFlags(Layer* aLayer, gfxContext* aTarget);
|
||||
void SetAntialiasingFlags(Layer* aLayer, gfx::DrawTarget* aTarget);
|
||||
|
||||
#ifdef MOZ_DUMP_PAINTING
|
||||
|
@ -74,7 +74,6 @@ nsEventStatus GestureEventListener::HandleInputEvent(const MultiTouchInput& aEve
|
||||
|
||||
switch (aEvent.mType) {
|
||||
case MultiTouchInput::MULTITOUCH_START:
|
||||
case MultiTouchInput::MULTITOUCH_ENTER:
|
||||
mTouches.Clear();
|
||||
for (size_t i = 0; i < aEvent.mTouches.Length(); i++) {
|
||||
mTouches.AppendElement(aEvent.mTouches[i]);
|
||||
@ -90,7 +89,6 @@ nsEventStatus GestureEventListener::HandleInputEvent(const MultiTouchInput& aEve
|
||||
rv = HandleInputTouchMove();
|
||||
break;
|
||||
case MultiTouchInput::MULTITOUCH_END:
|
||||
case MultiTouchInput::MULTITOUCH_LEAVE:
|
||||
for (size_t i = 0; i < aEvent.mTouches.Length(); i++) {
|
||||
for (size_t j = 0; j < mTouches.Length(); j++) {
|
||||
if (aEvent.mTouches[i].mIdentifier == mTouches[j].mIdentifier) {
|
||||
|
@ -96,7 +96,6 @@ BasicLayerManager::PushGroupForLayer(gfxContext* aContext, Layer* aLayer,
|
||||
// region are copied back to the destination. Remember if we've already
|
||||
// clipped precisely to the visible region.
|
||||
*aNeedsClipToVisibleRegion = !didCompleteClip || aRegion.GetNumRects() > 1;
|
||||
MOZ_ASSERT(!aContext->IsCairo());
|
||||
aContext->PushGroup(gfxContentType::COLOR);
|
||||
result = aContext;
|
||||
} else {
|
||||
@ -175,38 +174,23 @@ public:
|
||||
const nsIntRegion& visibleRegion = mLayer->GetEffectiveVisibleRegion();
|
||||
const nsIntRect& bounds = visibleRegion.GetBounds();
|
||||
|
||||
if (mTarget->IsCairo()) {
|
||||
nsRefPtr<gfxASurface> currentSurface = mTarget->CurrentSurface();
|
||||
const gfxRect& targetOpaqueRect = currentSurface->GetOpaqueRect();
|
||||
DrawTarget *dt = mTarget->GetDrawTarget();
|
||||
const IntRect& targetOpaqueRect = dt->GetOpaqueRect();
|
||||
|
||||
// Try to annotate currentSurface with a region of pixels that have been
|
||||
// (or will be) painted opaque, if no such region is currently set.
|
||||
if (targetOpaqueRect.IsEmpty() && visibleRegion.GetNumRects() == 1 &&
|
||||
(mLayer->GetContentFlags() & Layer::CONTENT_OPAQUE) &&
|
||||
!mTransform.HasNonAxisAlignedTransform()) {
|
||||
currentSurface->SetOpaqueRect(
|
||||
mTarget->UserToDevice(gfxRect(bounds.x, bounds.y, bounds.width, bounds.height)));
|
||||
// Try to annotate currentSurface with a region of pixels that have been
|
||||
// (or will be) painted opaque, if no such region is currently set.
|
||||
if (targetOpaqueRect.IsEmpty() && visibleRegion.GetNumRects() == 1 &&
|
||||
(mLayer->GetContentFlags() & Layer::CONTENT_OPAQUE) &&
|
||||
!mTransform.HasNonAxisAlignedTransform()) {
|
||||
|
||||
gfx::Rect opaqueRect = dt->GetTransform().TransformBounds(
|
||||
gfx::Rect(bounds.x, bounds.y, bounds.width, bounds.height));
|
||||
opaqueRect.RoundIn();
|
||||
IntRect intOpaqueRect;
|
||||
if (opaqueRect.ToIntRect(&intOpaqueRect)) {
|
||||
mTarget->GetDrawTarget()->SetOpaqueRect(intOpaqueRect);
|
||||
mPushedOpaqueRect = true;
|
||||
}
|
||||
} else {
|
||||
DrawTarget *dt = mTarget->GetDrawTarget();
|
||||
const IntRect& targetOpaqueRect = dt->GetOpaqueRect();
|
||||
|
||||
// Try to annotate currentSurface with a region of pixels that have been
|
||||
// (or will be) painted opaque, if no such region is currently set.
|
||||
if (targetOpaqueRect.IsEmpty() && visibleRegion.GetNumRects() == 1 &&
|
||||
(mLayer->GetContentFlags() & Layer::CONTENT_OPAQUE) &&
|
||||
!mTransform.HasNonAxisAlignedTransform()) {
|
||||
|
||||
gfx::Rect opaqueRect = dt->GetTransform().TransformBounds(
|
||||
gfx::Rect(bounds.x, bounds.y, bounds.width, bounds.height));
|
||||
opaqueRect.RoundIn();
|
||||
IntRect intOpaqueRect;
|
||||
if (opaqueRect.ToIntRect(&intOpaqueRect)) {
|
||||
mTarget->GetDrawTarget()->SetOpaqueRect(intOpaqueRect);
|
||||
mPushedOpaqueRect = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -214,12 +198,7 @@ public:
|
||||
// previous state it will happen on the exit path of the PaintLayer() so when
|
||||
// painting is complete the opaque rect qill be clear.
|
||||
void ClearOpaqueRect() {
|
||||
if (mTarget->IsCairo()) {
|
||||
nsRefPtr<gfxASurface> currentSurface = mTarget->CurrentSurface();
|
||||
currentSurface->SetOpaqueRect(gfxRect());
|
||||
} else {
|
||||
mTarget->GetDrawTarget()->SetOpaqueRect(IntRect());
|
||||
}
|
||||
mTarget->GetDrawTarget()->SetOpaqueRect(IntRect());
|
||||
}
|
||||
|
||||
gfxContext* mTarget;
|
||||
|
@ -90,7 +90,7 @@ BasicThebesLayer::PaintThebes(gfxContext* aContext,
|
||||
} else {
|
||||
groupContext = aContext;
|
||||
}
|
||||
SetAntialiasingFlags(this, groupContext);
|
||||
SetAntialiasingFlags(this, groupContext->GetDrawTarget());
|
||||
aCallback(this, groupContext, toDraw, DrawRegionClip::CLIP_NONE, nsIntRegion(), aCallbackData);
|
||||
if (needsGroup) {
|
||||
aContext->PopGroupToSource();
|
||||
|
@ -74,8 +74,11 @@ CanvasClient2D::Update(gfx::IntSize aSize, ClientCanvasLayer* aLayer)
|
||||
|
||||
gfx::SurfaceFormat surfaceFormat = gfx::ImageFormatToSurfaceFormat(format);
|
||||
mBuffer = CreateTextureClientForCanvas(surfaceFormat, aSize, flags, aLayer);
|
||||
if (!mBuffer) {
|
||||
NS_WARNING("Failed to allocate the TextureClient");
|
||||
return;
|
||||
}
|
||||
MOZ_ASSERT(mBuffer->CanExposeDrawTarget());
|
||||
mBuffer->AllocateForSurface(aSize);
|
||||
|
||||
bufferCreated = true;
|
||||
}
|
||||
@ -118,16 +121,20 @@ CanvasClient2D::CreateTextureClientForCanvas(gfx::SurfaceFormat aFormat,
|
||||
// We want a cairo backend here as we don't want to be copying into
|
||||
// an accelerated backend and we like LockBits to work. This is currently
|
||||
// the most effective way to make this work.
|
||||
return CreateBufferTextureClient(aFormat, aFlags, BackendType::CAIRO);
|
||||
return TextureClient::CreateForRawBufferAccess(GetForwarder(),
|
||||
aFormat, aSize, BackendType::CAIRO,
|
||||
mTextureInfo.mTextureFlags | aFlags);
|
||||
}
|
||||
|
||||
gfx::BackendType backend = gfxPlatform::GetPlatform()->GetPreferredCanvasBackend();
|
||||
#ifdef XP_WIN
|
||||
return CreateTextureClientForDrawing(aFormat, aFlags, backend, aSize);
|
||||
return CreateTextureClientForDrawing(aFormat, aSize, backend, aFlags);
|
||||
#else
|
||||
// XXX - We should use CreateTextureClientForDrawing, but we first need
|
||||
// to use double buffering.
|
||||
return CreateBufferTextureClient(aFormat, aFlags, backend);
|
||||
return TextureClient::CreateForRawBufferAccess(GetForwarder(),
|
||||
aFormat, aSize, backend,
|
||||
mTextureInfo.mTextureFlags | aFlags);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -101,10 +101,11 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
TemporaryRef<TextureClient> CreateTextureClientForCanvas(gfx::SurfaceFormat aFormat,
|
||||
gfx::IntSize aSize,
|
||||
TextureFlags aFlags,
|
||||
ClientCanvasLayer* aLayer);
|
||||
TemporaryRef<TextureClient>
|
||||
CreateTextureClientForCanvas(gfx::SurfaceFormat aFormat,
|
||||
gfx::IntSize aSize,
|
||||
TextureFlags aFlags,
|
||||
ClientCanvasLayer* aLayer);
|
||||
|
||||
RefPtr<TextureClient> mBuffer;
|
||||
};
|
||||
|
@ -191,15 +191,16 @@ CompositableClient::CreateBufferTextureClient(SurfaceFormat aFormat,
|
||||
}
|
||||
|
||||
TemporaryRef<TextureClient>
|
||||
CompositableClient::CreateTextureClientForDrawing(SurfaceFormat aFormat,
|
||||
TextureFlags aTextureFlags,
|
||||
CompositableClient::CreateTextureClientForDrawing(gfx::SurfaceFormat aFormat,
|
||||
gfx::IntSize aSize,
|
||||
gfx::BackendType aMoz2DBackend,
|
||||
const IntSize& aSizeHint)
|
||||
TextureFlags aTextureFlags,
|
||||
TextureAllocationFlags aAllocFlags)
|
||||
{
|
||||
return TextureClient::CreateTextureClientForDrawing(GetForwarder(), aFormat,
|
||||
aTextureFlags | mTextureFlags,
|
||||
aMoz2DBackend,
|
||||
aSizeHint);
|
||||
return TextureClient::CreateForDrawing(GetForwarder(),
|
||||
aFormat, aSize, aMoz2DBackend,
|
||||
aTextureFlags | mTextureFlags,
|
||||
aAllocFlags);
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -134,9 +134,10 @@ public:
|
||||
|
||||
TemporaryRef<TextureClient>
|
||||
CreateTextureClientForDrawing(gfx::SurfaceFormat aFormat,
|
||||
gfx::IntSize aSize,
|
||||
gfx::BackendType aMoz2DBackend,
|
||||
TextureFlags aTextureFlags,
|
||||
gfx::BackendType aMoz2dBackend,
|
||||
const gfx::IntSize& aSizeHint);
|
||||
TextureAllocationFlags aAllocFlags = ALLOC_DEFAULT);
|
||||
|
||||
virtual void SetDescriptorFromReply(TextureIdentifier aTextureId,
|
||||
const SurfaceDescriptor& aDescriptor)
|
||||
@ -225,6 +226,8 @@ public:
|
||||
|
||||
static uint64_t GetTrackersHolderId(PCompositableChild* aActor);
|
||||
|
||||
TextureFlags GetTextureFlags() const { return mTextureFlags; }
|
||||
|
||||
protected:
|
||||
CompositableChild* mCompositableChild;
|
||||
CompositableForwarder* mForwarder;
|
||||
|
@ -189,35 +189,30 @@ bool
|
||||
ContentClientRemoteBuffer::CreateAndAllocateTextureClient(RefPtr<TextureClient>& aClient,
|
||||
TextureFlags aFlags)
|
||||
{
|
||||
TextureAllocationFlags allocFlags = TextureAllocationFlags::ALLOC_CLEAR_BUFFER;
|
||||
if (aFlags & TextureFlags::ON_WHITE) {
|
||||
allocFlags = TextureAllocationFlags::ALLOC_CLEAR_BUFFER_WHITE;
|
||||
}
|
||||
|
||||
// gfx::BackendType::NONE means fallback to the content backend
|
||||
aClient = CreateTextureClientForDrawing(mSurfaceFormat,
|
||||
mTextureInfo.mTextureFlags | aFlags,
|
||||
aClient = CreateTextureClientForDrawing(mSurfaceFormat, mSize,
|
||||
gfx::BackendType::NONE,
|
||||
mSize);
|
||||
mTextureInfo.mTextureFlags | aFlags,
|
||||
allocFlags);
|
||||
if (!aClient) {
|
||||
// try with ALLOC_FALLBACK
|
||||
aClient = CreateTextureClientForDrawing(mSurfaceFormat, mSize,
|
||||
gfx::BackendType::NONE,
|
||||
mTextureInfo.mTextureFlags
|
||||
| TextureFlags::ALLOC_FALLBACK
|
||||
| aFlags,
|
||||
allocFlags);
|
||||
}
|
||||
|
||||
if (!aClient) {
|
||||
return false;
|
||||
}
|
||||
|
||||
TextureAllocationFlags flags = TextureAllocationFlags::ALLOC_CLEAR_BUFFER;
|
||||
if (aFlags & TextureFlags::ON_WHITE) {
|
||||
flags = TextureAllocationFlags::ALLOC_CLEAR_BUFFER_WHITE;
|
||||
}
|
||||
|
||||
if (!aClient->AllocateForSurface(mSize, flags)) {
|
||||
aClient = CreateTextureClientForDrawing(mSurfaceFormat,
|
||||
mTextureInfo.mTextureFlags | TextureFlags::ALLOC_FALLBACK | aFlags,
|
||||
gfx::BackendType::NONE,
|
||||
mSize);
|
||||
if (!aClient) {
|
||||
return false;
|
||||
}
|
||||
if (!aClient->AllocateForSurface(mSize, flags)) {
|
||||
NS_WARNING("Could not allocate texture client");
|
||||
aClient = nullptr;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
NS_WARN_IF_FALSE(aClient->IsValid(), "Created an invalid texture client");
|
||||
return true;
|
||||
}
|
||||
|
@ -276,14 +276,12 @@ ImageClientSingle::UpdateImageInternal(ImageContainer* aContainer,
|
||||
if (!mFrontBuffer) {
|
||||
gfxImageFormat format
|
||||
= gfxPlatform::GetPlatform()->OptimalFormatForContent(gfx::ContentForFormat(surface->GetFormat()));
|
||||
mFrontBuffer = CreateTextureClientForDrawing(gfx::ImageFormatToSurfaceFormat(format),
|
||||
mTextureFlags, gfx::BackendType::NONE, size);
|
||||
MOZ_ASSERT(mFrontBuffer->CanExposeDrawTarget());
|
||||
if (!mFrontBuffer->AllocateForSurface(size)) {
|
||||
mFrontBuffer = nullptr;
|
||||
mFrontBuffer = CreateTextureClientForDrawing(gfx::ImageFormatToSurfaceFormat(format), size,
|
||||
gfx::BackendType::NONE, mTextureFlags);
|
||||
if (!mFrontBuffer) {
|
||||
return false;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mFrontBuffer->CanExposeDrawTarget());
|
||||
bufferCreated = true;
|
||||
}
|
||||
|
||||
|
@ -72,12 +72,12 @@ SimpleTextureClientPool::GetTextureClient(bool aAutoRecycle)
|
||||
if (gfxPrefs::ForceShmemTiles()) {
|
||||
textureClient = TextureClient::CreateBufferTextureClient(mSurfaceAllocator,
|
||||
mFormat, TextureFlags::IMMEDIATE_UPLOAD | TextureFlags::RECYCLE, gfx::BackendType::NONE);
|
||||
if (!textureClient->AllocateForSurface(mSize, ALLOC_DEFAULT)) {
|
||||
NS_WARNING("TextureClient::AllocateForSurface failed!");
|
||||
}
|
||||
} else {
|
||||
textureClient = TextureClient::CreateTextureClientForDrawing(mSurfaceAllocator,
|
||||
mFormat, TextureFlags::DEFAULT | TextureFlags::RECYCLE, gfx::BackendType::NONE, mSize);
|
||||
}
|
||||
if (!textureClient->AllocateForSurface(mSize, ALLOC_DEFAULT)) {
|
||||
NS_WARNING("TextureClient::AllocateForSurface failed!");
|
||||
textureClient = TextureClient::CreateForDrawing(mSurfaceAllocator,
|
||||
mFormat, mSize, gfx::BackendType::NONE, TextureFlags::DEFAULT | TextureFlags::RECYCLE);
|
||||
}
|
||||
RECYCLE_LOG("%s Must allocate (0 left), returning %p\n", (mFormat == SurfaceFormat::B8G8R8A8?"poolA":"poolX"), textureClient.get());
|
||||
}
|
||||
|
@ -235,13 +235,13 @@ DisableGralloc(SurfaceFormat aFormat, const gfx::IntSize& aSizeHint)
|
||||
}
|
||||
#endif
|
||||
|
||||
// static
|
||||
static
|
||||
TemporaryRef<TextureClient>
|
||||
TextureClient::CreateTextureClientForDrawing(ISurfaceAllocator* aAllocator,
|
||||
SurfaceFormat aFormat,
|
||||
TextureFlags aTextureFlags,
|
||||
gfx::BackendType aMoz2DBackend,
|
||||
const gfx::IntSize& aSizeHint)
|
||||
CreateTextureClientForDrawing(ISurfaceAllocator* aAllocator,
|
||||
SurfaceFormat aFormat,
|
||||
TextureFlags aTextureFlags,
|
||||
gfx::BackendType aMoz2DBackend,
|
||||
const gfx::IntSize& aSizeHint)
|
||||
{
|
||||
if (aMoz2DBackend == gfx::BackendType::NONE) {
|
||||
aMoz2DBackend = gfxPlatform::GetPlatform()->GetContentBackend();
|
||||
@ -315,13 +315,81 @@ TextureClient::CreateTextureClientForDrawing(ISurfaceAllocator* aAllocator,
|
||||
|
||||
// Can't do any better than a buffer texture client.
|
||||
if (!result) {
|
||||
result = CreateBufferTextureClient(aAllocator, aFormat, aTextureFlags, aMoz2DBackend);
|
||||
result = TextureClient::CreateBufferTextureClient(aAllocator, aFormat, aTextureFlags, aMoz2DBackend);
|
||||
}
|
||||
|
||||
MOZ_ASSERT(!result || result->CanExposeDrawTarget(), "texture cannot expose a DrawTarget?");
|
||||
return result;
|
||||
}
|
||||
|
||||
// static
|
||||
TemporaryRef<TextureClient>
|
||||
TextureClient::CreateForDrawing(ISurfaceAllocator* aAllocator,
|
||||
gfx::SurfaceFormat aFormat,
|
||||
gfx::IntSize aSize,
|
||||
gfx::BackendType aMoz2DBackend,
|
||||
TextureFlags aTextureFlags,
|
||||
TextureAllocationFlags aAllocFlags)
|
||||
{
|
||||
RefPtr<TextureClient> texture =
|
||||
CreateTextureClientForDrawing(aAllocator, aFormat,
|
||||
aTextureFlags, aMoz2DBackend,
|
||||
aSize);
|
||||
if (texture) {
|
||||
if (!texture->AllocateForSurface(aSize, aAllocFlags)) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
return texture;
|
||||
}
|
||||
|
||||
// static
|
||||
TemporaryRef<BufferTextureClient>
|
||||
TextureClient::CreateForRawBufferAccess(ISurfaceAllocator* aAllocator,
|
||||
gfx::SurfaceFormat aFormat,
|
||||
gfx::IntSize aSize,
|
||||
gfx::BackendType aMoz2DBackend,
|
||||
TextureFlags aTextureFlags,
|
||||
TextureAllocationFlags aAllocFlags)
|
||||
{
|
||||
RefPtr<BufferTextureClient> texture =
|
||||
CreateBufferTextureClient(aAllocator, aFormat,
|
||||
aTextureFlags, aMoz2DBackend);
|
||||
if (texture) {
|
||||
if (!texture->AllocateForSurface(aSize, aAllocFlags)) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
return texture;
|
||||
}
|
||||
|
||||
// static
|
||||
TemporaryRef<BufferTextureClient>
|
||||
TextureClient::CreateForYCbCr(ISurfaceAllocator* aAllocator,
|
||||
gfx::IntSize aYSize,
|
||||
gfx::IntSize aCbCrSize,
|
||||
StereoMode aStereoMode,
|
||||
TextureFlags aTextureFlags)
|
||||
{
|
||||
RefPtr<BufferTextureClient> texture;
|
||||
if (aAllocator->IsSameProcess()) {
|
||||
texture = new MemoryTextureClient(aAllocator, gfx::SurfaceFormat::YUV,
|
||||
gfx::BackendType::NONE,
|
||||
aTextureFlags);
|
||||
} else {
|
||||
texture = new ShmemTextureClient(aAllocator, gfx::SurfaceFormat::YUV,
|
||||
gfx::BackendType::NONE,
|
||||
aTextureFlags);
|
||||
}
|
||||
|
||||
if (!texture->AllocateForYCbCr(aYSize, aCbCrSize, aStereoMode)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return texture;
|
||||
}
|
||||
|
||||
|
||||
// static
|
||||
TemporaryRef<BufferTextureClient>
|
||||
TextureClient::CreateBufferTextureClient(ISurfaceAllocator* aAllocator,
|
||||
|
@ -120,18 +120,42 @@ public:
|
||||
TextureClient(TextureFlags aFlags = TextureFlags::DEFAULT);
|
||||
virtual ~TextureClient();
|
||||
|
||||
// Creates a TextureClient that can be accessed through a raw pointer.
|
||||
// XXX - this doesn't allocate the texture data.
|
||||
// Prefer CreateForRawBufferAccess which returns a BufferTextureClient
|
||||
// only if allocation suceeded.
|
||||
static TemporaryRef<BufferTextureClient>
|
||||
CreateBufferTextureClient(ISurfaceAllocator* aAllocator,
|
||||
gfx::SurfaceFormat aFormat,
|
||||
TextureFlags aTextureFlags,
|
||||
gfx::BackendType aMoz2dBackend);
|
||||
|
||||
// Creates and allocates a TextureClient usable with Moz2D.
|
||||
static TemporaryRef<TextureClient>
|
||||
CreateTextureClientForDrawing(ISurfaceAllocator* aAllocator,
|
||||
gfx::SurfaceFormat aFormat,
|
||||
TextureFlags aTextureFlags,
|
||||
gfx::BackendType aMoz2dBackend,
|
||||
const gfx::IntSize& aSizeHint);
|
||||
CreateForDrawing(ISurfaceAllocator* aAllocator,
|
||||
gfx::SurfaceFormat aFormat,
|
||||
gfx::IntSize aSize,
|
||||
gfx::BackendType aMoz2dBackend,
|
||||
TextureFlags aTextureFlags,
|
||||
TextureAllocationFlags flags = ALLOC_DEFAULT);
|
||||
|
||||
// Creates and allocates a BufferTextureClient supporting the YCbCr format.
|
||||
static TemporaryRef<BufferTextureClient>
|
||||
CreateForYCbCr(ISurfaceAllocator* aAllocator,
|
||||
gfx::IntSize aYSize,
|
||||
gfx::IntSize aCbCrSize,
|
||||
StereoMode aStereoMode,
|
||||
TextureFlags aTextureFlags);
|
||||
|
||||
// Creates and allocates a BufferTextureClient (can beaccessed through raw
|
||||
// pointers).
|
||||
static TemporaryRef<BufferTextureClient>
|
||||
CreateForRawBufferAccess(ISurfaceAllocator* aAllocator,
|
||||
gfx::SurfaceFormat aFormat,
|
||||
gfx::IntSize aSize,
|
||||
gfx::BackendType aMoz2dBackend,
|
||||
TextureFlags aTextureFlags,
|
||||
TextureAllocationFlags flags = ALLOC_DEFAULT);
|
||||
|
||||
virtual TextureClientYCbCr* AsTextureClientYCbCr() { return nullptr; }
|
||||
|
||||
|
@ -57,11 +57,11 @@ TextureClientPool::GetTextureClient()
|
||||
// gfx::BackendType::NONE means use the content backend
|
||||
textureClient = TextureClient::CreateBufferTextureClient(mSurfaceAllocator,
|
||||
mFormat, TextureFlags::IMMEDIATE_UPLOAD, gfx::BackendType::NONE);
|
||||
textureClient->AllocateForSurface(mSize, ALLOC_DEFAULT);
|
||||
} else {
|
||||
textureClient = TextureClient::CreateTextureClientForDrawing(mSurfaceAllocator,
|
||||
mFormat, TextureFlags::IMMEDIATE_UPLOAD, gfx::BackendType::NONE, mSize);
|
||||
textureClient = TextureClient::CreateForDrawing(mSurfaceAllocator,
|
||||
mFormat, mSize, gfx::BackendType::NONE, TextureFlags::IMMEDIATE_UPLOAD);
|
||||
}
|
||||
textureClient->AllocateForSurface(mSize, ALLOC_DEFAULT);
|
||||
|
||||
return textureClient;
|
||||
}
|
||||
|
@ -149,7 +149,9 @@ ParamTraits<MagicGrallocBufferHandle>::Read(const Message* aMsg,
|
||||
if (sameProcess) {
|
||||
aResult->mGraphicBuffer = SharedBufferManagerParent::GetGraphicBuffer(aResult->mRef);
|
||||
} else {
|
||||
aResult->mGraphicBuffer = SharedBufferManagerChild::GetSingleton()->GetGraphicBuffer(index);
|
||||
if (SharedBufferManagerChild::GetSingleton()->IsValidKey(index)) {
|
||||
aResult->mGraphicBuffer = SharedBufferManagerChild::GetSingleton()->GetGraphicBuffer(index);
|
||||
}
|
||||
MOZ_ASSERT(!aResult->mGraphicBuffer.get());
|
||||
|
||||
// Deserialize GraphicBuffer
|
||||
|
@ -345,5 +345,16 @@ SharedBufferManagerChild::GetGraphicBuffer(int64_t key)
|
||||
}
|
||||
#endif
|
||||
|
||||
bool
|
||||
SharedBufferManagerChild::IsValidKey(int64_t key)
|
||||
{
|
||||
#ifdef MOZ_HAVE_SURFACEDESCRIPTORGRALLOC
|
||||
if (mBuffers.count(key) != 1) {
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
} /* namespace layers */
|
||||
} /* namespace mozilla */
|
||||
|
@ -107,9 +107,11 @@ public:
|
||||
virtual bool RecvDropGrallocBuffer(const mozilla::layers::MaybeMagicGrallocBufferHandle& handle);
|
||||
|
||||
#ifdef MOZ_HAVE_SURFACEDESCRIPTORGRALLOC
|
||||
android::sp<android::GraphicBuffer> GetGraphicBuffer(int64_t index);
|
||||
android::sp<android::GraphicBuffer> GetGraphicBuffer(int64_t key);
|
||||
#endif
|
||||
|
||||
bool IsValidKey(int64_t key);
|
||||
|
||||
base::Thread* GetThread() const;
|
||||
|
||||
MessageLoop* GetMessageLoop() const;
|
||||
|
@ -29,7 +29,6 @@ SharedPlanarYCbCrImage::SharedPlanarYCbCrImage(ImageClient* aCompositable)
|
||||
: PlanarYCbCrImage(nullptr)
|
||||
, mCompositable(aCompositable)
|
||||
{
|
||||
mTextureClient = aCompositable->CreateBufferTextureClient(gfx::SurfaceFormat::YUV);
|
||||
MOZ_COUNT_CTOR(SharedPlanarYCbCrImage);
|
||||
}
|
||||
|
||||
@ -69,7 +68,7 @@ SharedPlanarYCbCrImage::GetBuffer()
|
||||
TemporaryRef<gfx::SourceSurface>
|
||||
SharedPlanarYCbCrImage::GetAsSourceSurface()
|
||||
{
|
||||
if (!mTextureClient->IsAllocated()) {
|
||||
if (!mTextureClient) {
|
||||
NS_WARNING("Can't get as surface");
|
||||
return nullptr;
|
||||
}
|
||||
@ -79,15 +78,12 @@ SharedPlanarYCbCrImage::GetAsSourceSurface()
|
||||
void
|
||||
SharedPlanarYCbCrImage::SetData(const PlanarYCbCrData& aData)
|
||||
{
|
||||
// If mShmem has not been allocated (through Allocate(aData)), allocate it.
|
||||
// This code path is slower than the one used when Allocate has been called
|
||||
// since it will trigger a full copy.
|
||||
if (!mTextureClient->IsAllocated()) {
|
||||
Data data = aData;
|
||||
if (!Allocate(data)) {
|
||||
NS_WARNING("SharedPlanarYCbCrImage::SetData failed to allocate");
|
||||
return;
|
||||
}
|
||||
// If mTextureClient has not already been allocated (through Allocate(aData))
|
||||
// allocate it. This code path is slower than the one used when Allocate has
|
||||
// been called since it will trigger a full copy.
|
||||
PlanarYCbCrData data = aData;
|
||||
if (!mTextureClient && !Allocate(data)) {
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mTextureClient->AsTextureClientYCbCr());
|
||||
@ -100,17 +96,6 @@ SharedPlanarYCbCrImage::SetData(const PlanarYCbCrData& aData)
|
||||
MOZ_ASSERT(false, "Failed to copy YCbCr data into the TextureClient");
|
||||
return;
|
||||
}
|
||||
// do not set mBuffer like in PlanarYCbCrImage because the later
|
||||
// will try to manage this memory without knowing it belongs to a
|
||||
// shmem.
|
||||
mBufferSize = YCbCrImageDataSerializer::ComputeMinBufferSize(mData.mYSize,
|
||||
mData.mCbCrSize);
|
||||
mSize = mData.mPicSize;
|
||||
|
||||
YCbCrImageDataSerializer serializer(mTextureClient->GetBuffer(), mTextureClient->GetBufferSize());
|
||||
mData.mYChannel = serializer.GetYData();
|
||||
mData.mCbChannel = serializer.GetCbData();
|
||||
mData.mCrChannel = serializer.GetCrData();
|
||||
mTextureClient->MarkImmutable();
|
||||
}
|
||||
|
||||
@ -119,11 +104,13 @@ SharedPlanarYCbCrImage::SetData(const PlanarYCbCrData& aData)
|
||||
uint8_t*
|
||||
SharedPlanarYCbCrImage::AllocateAndGetNewBuffer(uint32_t aSize)
|
||||
{
|
||||
NS_ABORT_IF_FALSE(!mTextureClient->IsAllocated(), "This image already has allocated data");
|
||||
NS_ABORT_IF_FALSE(!mTextureClient, "This image already has allocated data");
|
||||
size_t size = YCbCrImageDataSerializer::ComputeMinBufferSize(aSize);
|
||||
|
||||
mTextureClient = mCompositable->CreateBufferTextureClient(gfx::SurfaceFormat::YUV);
|
||||
// get new buffer _without_ setting mBuffer.
|
||||
if (!mTextureClient->Allocate(size)) {
|
||||
mTextureClient = nullptr;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@ -137,6 +124,7 @@ SharedPlanarYCbCrImage::AllocateAndGetNewBuffer(uint32_t aSize)
|
||||
void
|
||||
SharedPlanarYCbCrImage::SetDataNoCopy(const Data &aData)
|
||||
{
|
||||
NS_ABORT_IF_FALSE(mTextureClient, "This Image should have already allocated data");
|
||||
mData = aData;
|
||||
mSize = aData.mPicSize;
|
||||
/* SetDataNoCopy is used to update YUV plane offsets without (re)allocating
|
||||
@ -163,9 +151,11 @@ SharedPlanarYCbCrImage::SetDataNoCopy(const Data &aData)
|
||||
uint8_t*
|
||||
SharedPlanarYCbCrImage::AllocateBuffer(uint32_t aSize)
|
||||
{
|
||||
NS_ABORT_IF_FALSE(!mTextureClient->IsAllocated(),
|
||||
NS_ABORT_IF_FALSE(!mTextureClient,
|
||||
"This image already has allocated data");
|
||||
mTextureClient = mCompositable->CreateBufferTextureClient(gfx::SurfaceFormat::YUV);
|
||||
if (!mTextureClient->Allocate(aSize)) {
|
||||
mTextureClient = nullptr;
|
||||
return nullptr;
|
||||
}
|
||||
return mTextureClient->GetBuffer();
|
||||
@ -173,19 +163,21 @@ SharedPlanarYCbCrImage::AllocateBuffer(uint32_t aSize)
|
||||
|
||||
bool
|
||||
SharedPlanarYCbCrImage::IsValid() {
|
||||
return mTextureClient->IsAllocated();
|
||||
return !!mTextureClient;
|
||||
}
|
||||
|
||||
bool
|
||||
SharedPlanarYCbCrImage::Allocate(PlanarYCbCrData& aData)
|
||||
{
|
||||
NS_ABORT_IF_FALSE(!mTextureClient->IsAllocated(),
|
||||
NS_ABORT_IF_FALSE(!mTextureClient,
|
||||
"This image already has allocated data");
|
||||
|
||||
size_t size = YCbCrImageDataSerializer::ComputeMinBufferSize(aData.mYSize,
|
||||
aData.mCbCrSize);
|
||||
|
||||
if (AllocateBuffer(static_cast<uint32_t>(size)) == nullptr) {
|
||||
mTextureClient = TextureClient::CreateForYCbCr(mCompositable->GetForwarder(),
|
||||
aData.mYSize, aData.mCbCrSize,
|
||||
aData.mStereoMode,
|
||||
mCompositable->GetTextureFlags());
|
||||
if (!mTextureClient) {
|
||||
NS_WARNING("SharedPlanarYCbCrImage::Allocate failed.");
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -217,6 +209,13 @@ SharedPlanarYCbCrImage::Allocate(PlanarYCbCrData& aData)
|
||||
mData.mYStride = mData.mYSize.width;
|
||||
mData.mCbCrStride = mData.mCbCrSize.width;
|
||||
|
||||
// do not set mBuffer like in PlanarYCbCrImage because the later
|
||||
// will try to manage this memory without knowing it belongs to a
|
||||
// shmem.
|
||||
mBufferSize = YCbCrImageDataSerializer::ComputeMinBufferSize(mData.mYSize,
|
||||
mData.mCbCrSize);
|
||||
mSize = mData.mPicSize;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -41,10 +41,6 @@ class gfxContext MOZ_FINAL {
|
||||
NS_INLINE_DECL_REFCOUNTING(gfxContext)
|
||||
|
||||
public:
|
||||
/**
|
||||
* Initialize this context from a surface.
|
||||
*/
|
||||
gfxContext(gfxASurface *surface);
|
||||
|
||||
/**
|
||||
* Initialize this context from a DrawTarget.
|
||||
@ -689,8 +685,6 @@ public:
|
||||
void ClearFlag(int32_t aFlag) { mFlags &= ~aFlag; }
|
||||
int32_t GetFlags() const { return mFlags; }
|
||||
|
||||
bool IsCairo() const { return !mDT; }
|
||||
|
||||
// Work out whether cairo will snap inter-glyph spacing to pixels.
|
||||
void GetRoundOffsetsToPixels(bool *aRoundX, bool *aRoundY);
|
||||
|
||||
@ -798,7 +792,6 @@ private:
|
||||
AzureState &CurrentState() { return mStateStack[mStateStack.Length() - 1]; }
|
||||
const AzureState &CurrentState() const { return mStateStack[mStateStack.Length() - 1]; }
|
||||
|
||||
cairo_t *mCairo;
|
||||
cairo_t *mRefCairo;
|
||||
nsRefPtr<gfxASurface> mSurface;
|
||||
int32_t mFlags;
|
||||
@ -965,19 +958,9 @@ public:
|
||||
gfxContextAutoDisableSubpixelAntialiasing(gfxContext *aContext, bool aDisable)
|
||||
{
|
||||
if (aDisable) {
|
||||
if (aContext->IsCairo()) {
|
||||
mSurface = aContext->CurrentSurface();
|
||||
if (!mSurface) {
|
||||
return;
|
||||
}
|
||||
mSubpixelAntialiasingEnabled = mSurface->GetSubpixelAntialiasingEnabled();
|
||||
mSurface->SetSubpixelAntialiasingEnabled(false);
|
||||
} else {
|
||||
mDT = aContext->GetDrawTarget();
|
||||
|
||||
mSubpixelAntialiasingEnabled = mDT->GetPermitSubpixelAA();
|
||||
mDT->SetPermitSubpixelAA(false);
|
||||
}
|
||||
mDT = aContext->GetDrawTarget();
|
||||
mSubpixelAntialiasingEnabled = mDT->GetPermitSubpixelAA();
|
||||
mDT->SetPermitSubpixelAA(false);
|
||||
}
|
||||
}
|
||||
~gfxContextAutoDisableSubpixelAntialiasing()
|
||||
|
@ -130,14 +130,8 @@ gfxSurfaceDrawable::Draw(gfxContext* aContext,
|
||||
{
|
||||
nsRefPtr<gfxPattern> pattern;
|
||||
if (mDrawTarget) {
|
||||
if (aContext->IsCairo()) {
|
||||
nsRefPtr<gfxASurface> source =
|
||||
gfxPlatform::GetPlatform()->GetThebesSurfaceForDrawTarget(mDrawTarget);
|
||||
pattern = new gfxPattern(source);
|
||||
} else {
|
||||
RefPtr<SourceSurface> source = mDrawTarget->Snapshot();
|
||||
pattern = new gfxPattern(source, Matrix());
|
||||
}
|
||||
RefPtr<SourceSurface> source = mDrawTarget->Snapshot();
|
||||
pattern = new gfxPattern(source, Matrix());
|
||||
} else if (mSourceSurface) {
|
||||
pattern = new gfxPattern(mSourceSurface, Matrix());
|
||||
} else {
|
||||
|
@ -3159,7 +3159,6 @@ gfxFont::Draw(gfxTextRun *aTextRun, uint32_t aStart, uint32_t aEnd,
|
||||
const double devUnitsPerAppUnit = 1.0/double(appUnitsPerDevUnit);
|
||||
bool isRTL = aTextRun->IsRightToLeft();
|
||||
double direction = aTextRun->GetDirection();
|
||||
gfxMatrix globalMatrix = aContext->CurrentMatrix();
|
||||
|
||||
bool haveSVGGlyphs = GetFontEntry()->TryGetSVGData(this);
|
||||
bool haveColorGlyphs = GetFontEntry()->TryGetColorGlyphs();
|
||||
@ -3191,202 +3190,12 @@ gfxFont::Draw(gfxTextRun *aTextRun, uint32_t aStart, uint32_t aEnd,
|
||||
double x = aPt->x;
|
||||
double y = aPt->y;
|
||||
|
||||
cairo_t *cr = aContext->GetCairo();
|
||||
RefPtr<DrawTarget> dt = aContext->GetDrawTarget();
|
||||
|
||||
bool paintSVGGlyphs = !aCallbacks || aCallbacks->mShouldPaintSVGGlyphs;
|
||||
bool emittedGlyphs = false;
|
||||
|
||||
if (aContext->IsCairo()) {
|
||||
bool success = SetupCairoFont(aContext);
|
||||
if (MOZ_UNLIKELY(!success))
|
||||
return;
|
||||
|
||||
::GlyphBuffer glyphs;
|
||||
cairo_glyph_t *glyph;
|
||||
|
||||
if (aSpacing) {
|
||||
x += direction*aSpacing[0].mBefore;
|
||||
}
|
||||
for (i = aStart; i < aEnd; ++i) {
|
||||
const gfxTextRun::CompressedGlyph *glyphData = &charGlyphs[i];
|
||||
if (glyphData->IsSimpleGlyph()) {
|
||||
double advance = glyphData->GetSimpleAdvance();
|
||||
double glyphX;
|
||||
if (isRTL) {
|
||||
x -= advance;
|
||||
glyphX = x;
|
||||
} else {
|
||||
glyphX = x;
|
||||
x += advance;
|
||||
}
|
||||
|
||||
if (haveSVGGlyphs) {
|
||||
if (!paintSVGGlyphs) {
|
||||
continue;
|
||||
}
|
||||
gfxPoint point(ToDeviceUnits(glyphX, devUnitsPerAppUnit),
|
||||
ToDeviceUnits(y, devUnitsPerAppUnit));
|
||||
DrawMode mode = ForcePaintingDrawMode(aDrawMode);
|
||||
if (RenderSVGGlyph(aContext, point, mode,
|
||||
glyphData->GetSimpleGlyph(), aContextPaint,
|
||||
aCallbacks, emittedGlyphs)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (haveColorGlyphs) {
|
||||
gfxPoint point(ToDeviceUnits(glyphX, devUnitsPerAppUnit),
|
||||
ToDeviceUnits(y, devUnitsPerAppUnit));
|
||||
if (RenderColorGlyph(aContext, point, glyphData->GetSimpleGlyph())) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Perhaps we should put a scale in the cairo context instead of
|
||||
// doing this scaling here...
|
||||
// Multiplying by the reciprocal may introduce tiny error here,
|
||||
// but we assume cairo is going to round coordinates at some stage
|
||||
// and this is faster
|
||||
glyph = glyphs.AppendGlyph();
|
||||
glyph->index = glyphData->GetSimpleGlyph();
|
||||
glyph->x = ToDeviceUnits(glyphX, devUnitsPerAppUnit);
|
||||
glyph->y = ToDeviceUnits(y, devUnitsPerAppUnit);
|
||||
glyphs.Flush(cr, aDrawMode, isRTL, aContextPaint, globalMatrix);
|
||||
|
||||
// synthetic bolding by multi-striking with 1-pixel offsets
|
||||
// at least once, more if there's room (large font sizes)
|
||||
if (IsSyntheticBold()) {
|
||||
double strikeOffset = synBoldOnePixelOffset;
|
||||
int32_t strikeCount = strikes;
|
||||
do {
|
||||
cairo_glyph_t *doubleglyph;
|
||||
doubleglyph = glyphs.AppendGlyph();
|
||||
doubleglyph->index = glyph->index;
|
||||
doubleglyph->x =
|
||||
ToDeviceUnits(glyphX + strikeOffset * appUnitsPerDevUnit,
|
||||
devUnitsPerAppUnit);
|
||||
doubleglyph->y = glyph->y;
|
||||
strikeOffset += synBoldOnePixelOffset;
|
||||
glyphs.Flush(cr, aDrawMode, isRTL, aContextPaint, globalMatrix);
|
||||
} while (--strikeCount > 0);
|
||||
}
|
||||
emittedGlyphs = true;
|
||||
} else {
|
||||
uint32_t glyphCount = glyphData->GetGlyphCount();
|
||||
if (glyphCount > 0) {
|
||||
const gfxTextRun::DetailedGlyph *details =
|
||||
aTextRun->GetDetailedGlyphs(i);
|
||||
NS_ASSERTION(details, "detailedGlyph should not be missing!");
|
||||
double advance;
|
||||
for (uint32_t j = 0; j < glyphCount; ++j, ++details, x += direction * advance) {
|
||||
advance = details->mAdvance;
|
||||
if (glyphData->IsMissing()) {
|
||||
// default ignorable characters will have zero advance width.
|
||||
// we don't have to draw the hexbox for them
|
||||
if (aDrawMode != DrawMode::GLYPH_PATH && advance > 0) {
|
||||
double glyphX = x;
|
||||
if (isRTL) {
|
||||
glyphX -= advance;
|
||||
}
|
||||
gfxPoint pt(ToDeviceUnits(glyphX, devUnitsPerAppUnit),
|
||||
ToDeviceUnits(y, devUnitsPerAppUnit));
|
||||
gfxFloat advanceDevUnits = ToDeviceUnits(advance, devUnitsPerAppUnit);
|
||||
gfxFloat height = GetMetrics().maxAscent;
|
||||
gfxRect glyphRect(pt.x, pt.y - height, advanceDevUnits, height);
|
||||
gfxFontMissingGlyphs::DrawMissingGlyph(aContext,
|
||||
glyphRect,
|
||||
details->mGlyphID,
|
||||
appUnitsPerDevUnit);
|
||||
}
|
||||
} else {
|
||||
double glyphX = x + details->mXOffset;
|
||||
if (isRTL) {
|
||||
glyphX -= advance;
|
||||
}
|
||||
|
||||
if (haveSVGGlyphs) {
|
||||
if (!paintSVGGlyphs) {
|
||||
continue;
|
||||
}
|
||||
|
||||
gfxPoint point(ToDeviceUnits(glyphX, devUnitsPerAppUnit),
|
||||
ToDeviceUnits(y, devUnitsPerAppUnit));
|
||||
|
||||
DrawMode mode = ForcePaintingDrawMode(aDrawMode);
|
||||
if (RenderSVGGlyph(aContext, point, mode,
|
||||
details->mGlyphID,
|
||||
aContextPaint, aCallbacks,
|
||||
emittedGlyphs)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (haveColorGlyphs) {
|
||||
gfxPoint point(ToDeviceUnits(glyphX,
|
||||
devUnitsPerAppUnit),
|
||||
ToDeviceUnits(y + details->mYOffset,
|
||||
devUnitsPerAppUnit));
|
||||
if (RenderColorGlyph(aContext, point,
|
||||
details->mGlyphID)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
glyph = glyphs.AppendGlyph();
|
||||
glyph->index = details->mGlyphID;
|
||||
glyph->x = ToDeviceUnits(glyphX, devUnitsPerAppUnit);
|
||||
glyph->y = ToDeviceUnits(y + details->mYOffset, devUnitsPerAppUnit);
|
||||
glyphs.Flush(cr, aDrawMode, isRTL, aContextPaint, globalMatrix);
|
||||
|
||||
if (IsSyntheticBold()) {
|
||||
double strikeOffset = synBoldOnePixelOffset;
|
||||
int32_t strikeCount = strikes;
|
||||
do {
|
||||
cairo_glyph_t *doubleglyph;
|
||||
doubleglyph = glyphs.AppendGlyph();
|
||||
doubleglyph->index = glyph->index;
|
||||
doubleglyph->x =
|
||||
ToDeviceUnits(glyphX + strikeOffset *
|
||||
appUnitsPerDevUnit,
|
||||
devUnitsPerAppUnit);
|
||||
doubleglyph->y = glyph->y;
|
||||
strikeOffset += synBoldOnePixelOffset;
|
||||
glyphs.Flush(cr, aDrawMode, isRTL, aContextPaint, globalMatrix);
|
||||
} while (--strikeCount > 0);
|
||||
}
|
||||
emittedGlyphs = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (aSpacing) {
|
||||
double space = aSpacing[i - aStart].mAfter;
|
||||
if (i + 1 < aEnd) {
|
||||
space += aSpacing[i + 1 - aStart].mBefore;
|
||||
}
|
||||
x += direction*space;
|
||||
}
|
||||
}
|
||||
|
||||
if (gfxFontTestStore::CurrentStore()) {
|
||||
/* This assumes that the tests won't have anything that results
|
||||
* in more than GLYPH_BUFFER_SIZE glyphs. Do this before we
|
||||
* flush, since that'll blow away the num_glyphs.
|
||||
*/
|
||||
gfxFontTestStore::CurrentStore()->AddItem(GetName(),
|
||||
glyphs.mGlyphBuffer,
|
||||
glyphs.mNumGlyphs);
|
||||
}
|
||||
|
||||
// draw any remaining glyphs
|
||||
glyphs.Flush(cr, aDrawMode, isRTL, aContextPaint, globalMatrix, true);
|
||||
if (aCallbacks && emittedGlyphs) {
|
||||
aCallbacks->NotifyGlyphPathEmitted();
|
||||
}
|
||||
|
||||
} else {
|
||||
{
|
||||
RefPtr<ScaledFont> scaledFont = GetScaledFont(dt);
|
||||
|
||||
if (!scaledFont) {
|
||||
|
@ -827,20 +827,6 @@ gfxPlatform::GetScaledFontForFont(DrawTarget* aTarget, gfxFont *aFont)
|
||||
return scaledFont;
|
||||
}
|
||||
|
||||
cairo_user_data_key_t kDrawSourceSurface;
|
||||
static void
|
||||
DataSourceSurfaceDestroy(void *dataSourceSurface)
|
||||
{
|
||||
static_cast<DataSourceSurface*>(dataSourceSurface)->Release();
|
||||
}
|
||||
|
||||
cairo_user_data_key_t kDrawTargetForSurface;
|
||||
static void
|
||||
DataDrawTargetDestroy(void *aTarget)
|
||||
{
|
||||
static_cast<DrawTarget*>(aTarget)->Release();
|
||||
}
|
||||
|
||||
bool
|
||||
gfxPlatform::SupportsAzureContentForDrawTarget(DrawTarget* aTarget)
|
||||
{
|
||||
@ -926,49 +912,6 @@ gfxPlatform::PurgeSkiaCache()
|
||||
#endif
|
||||
}
|
||||
|
||||
already_AddRefed<gfxASurface>
|
||||
gfxPlatform::GetThebesSurfaceForDrawTarget(DrawTarget *aTarget)
|
||||
{
|
||||
if (aTarget->GetBackendType() == BackendType::CAIRO) {
|
||||
cairo_surface_t* csurf =
|
||||
static_cast<cairo_surface_t*>(aTarget->GetNativeSurface(NativeSurfaceType::CAIRO_SURFACE));
|
||||
if (csurf) {
|
||||
return gfxASurface::Wrap(csurf);
|
||||
}
|
||||
}
|
||||
|
||||
// The semantics of this part of the function are sort of weird. If we
|
||||
// don't have direct support for the backend, we snapshot the first time
|
||||
// and then return the snapshotted surface for the lifetime of the draw
|
||||
// target. Sometimes it seems like this works out, but it seems like it
|
||||
// might result in no updates ever.
|
||||
RefPtr<SourceSurface> source = aTarget->Snapshot();
|
||||
RefPtr<DataSourceSurface> data = source->GetDataSurface();
|
||||
|
||||
if (!data) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
IntSize size = data->GetSize();
|
||||
gfxImageFormat format = SurfaceFormatToImageFormat(data->GetFormat());
|
||||
|
||||
|
||||
nsRefPtr<gfxASurface> surf =
|
||||
new gfxImageSurface(data->GetData(), gfxIntSize(size.width, size.height),
|
||||
data->Stride(), format);
|
||||
|
||||
if (surf->CairoStatus()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
surf->SetData(&kDrawSourceSurface, data.forget().drop(), DataSourceSurfaceDestroy);
|
||||
// keep the draw target alive as long as we need its data
|
||||
aTarget->AddRef();
|
||||
surf->SetData(&kDrawTargetForSurface, aTarget, DataDrawTargetDestroy);
|
||||
|
||||
return surf.forget();
|
||||
}
|
||||
|
||||
TemporaryRef<DrawTarget>
|
||||
gfxPlatform::CreateDrawTargetForBackend(BackendType aBackend, const IntSize& aSize, SurfaceFormat aFormat)
|
||||
{
|
||||
|
@ -222,9 +222,6 @@ public:
|
||||
virtual mozilla::TemporaryRef<mozilla::gfx::ScaledFont>
|
||||
GetScaledFontForFont(mozilla::gfx::DrawTarget* aTarget, gfxFont *aFont);
|
||||
|
||||
virtual already_AddRefed<gfxASurface>
|
||||
GetThebesSurfaceForDrawTarget(mozilla::gfx::DrawTarget *aTarget);
|
||||
|
||||
mozilla::TemporaryRef<DrawTarget>
|
||||
CreateOffscreenContentDrawTarget(const mozilla::gfx::IntSize& aSize, mozilla::gfx::SurfaceFormat aFormat);
|
||||
|
||||
|
@ -380,35 +380,6 @@ gfxPlatformMac::ReadAntiAliasingThreshold()
|
||||
return threshold;
|
||||
}
|
||||
|
||||
already_AddRefed<gfxASurface>
|
||||
gfxPlatformMac::GetThebesSurfaceForDrawTarget(DrawTarget *aTarget)
|
||||
{
|
||||
if (aTarget->GetBackendType() == BackendType::COREGRAPHICS_ACCELERATED) {
|
||||
RefPtr<SourceSurface> source = aTarget->Snapshot();
|
||||
RefPtr<DataSourceSurface> sourceData = source->GetDataSurface();
|
||||
unsigned char* data = sourceData->GetData();
|
||||
nsRefPtr<gfxImageSurface> surf = new gfxImageSurface(data, ThebesIntSize(sourceData->GetSize()), sourceData->Stride(),
|
||||
gfxImageFormat::ARGB32);
|
||||
// We could fix this by telling gfxImageSurface it owns data.
|
||||
nsRefPtr<gfxImageSurface> cpy = new gfxImageSurface(ThebesIntSize(sourceData->GetSize()), gfxImageFormat::ARGB32);
|
||||
cpy->CopyFrom(surf);
|
||||
return cpy.forget();
|
||||
} else if (aTarget->GetBackendType() == BackendType::COREGRAPHICS) {
|
||||
CGContextRef cg = static_cast<CGContextRef>(aTarget->GetNativeSurface(NativeSurfaceType::CGCONTEXT));
|
||||
|
||||
//XXX: it would be nice to have an implicit conversion from IntSize to gfxIntSize
|
||||
IntSize intSize = aTarget->GetSize();
|
||||
gfxIntSize size(intSize.width, intSize.height);
|
||||
|
||||
nsRefPtr<gfxASurface> surf =
|
||||
new gfxQuartzSurface(cg, size);
|
||||
|
||||
return surf.forget();
|
||||
}
|
||||
|
||||
return gfxPlatform::GetThebesSurfaceForDrawTarget(aTarget);
|
||||
}
|
||||
|
||||
bool
|
||||
gfxPlatformMac::UseAcceleratedCanvas()
|
||||
{
|
||||
|
@ -64,8 +64,6 @@ public:
|
||||
// lower threshold on font anti-aliasing
|
||||
uint32_t GetAntiAliasingThreshold() { return mFontAntiAliasingThreshold; }
|
||||
|
||||
virtual already_AddRefed<gfxASurface>
|
||||
GetThebesSurfaceForDrawTarget(mozilla::gfx::DrawTarget *aTarget);
|
||||
private:
|
||||
virtual void GetPlatformCMSOutputProfile(void* &mem, size_t &size);
|
||||
|
||||
|
@ -27,13 +27,6 @@ gfxQuartzNativeDrawing::BeginNativeDrawing()
|
||||
{
|
||||
NS_ASSERTION(!mCGContext, "BeginNativeDrawing called when drawing already in progress");
|
||||
|
||||
if (mContext->IsCairo()) {
|
||||
// We're past that now. Any callers that still supply a Cairo context
|
||||
// don't deserve native theming.
|
||||
NS_WARNING("gfxQuartzNativeDrawing being used with a gfxContext that is not backed by a DrawTarget");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
DrawTarget *dt = mContext->GetDrawTarget();
|
||||
if (dt->GetBackendType() != BackendType::COREGRAPHICS || dt->IsDualDrawTarget()) {
|
||||
IntSize backingSize(NSToIntFloor(mNativeRect.width * mBackingScale),
|
||||
@ -62,7 +55,6 @@ void
|
||||
gfxQuartzNativeDrawing::EndNativeDrawing()
|
||||
{
|
||||
NS_ASSERTION(mCGContext, "EndNativeDrawing called without BeginNativeDrawing");
|
||||
MOZ_ASSERT(!mContext->IsCairo(), "BeginNativeDrawing succeeded with cairo context?");
|
||||
|
||||
mBorrowedContext.Finish();
|
||||
if (mDrawTarget) {
|
||||
|
@ -183,9 +183,8 @@ gfxWindowsNativeDrawing::BeginNativeDrawing()
|
||||
bool
|
||||
gfxWindowsNativeDrawing::IsDoublePass()
|
||||
{
|
||||
if (!mContext->IsCairo() &&
|
||||
(mContext->GetDrawTarget()->GetBackendType() != mozilla::gfx::BackendType::CAIRO ||
|
||||
mContext->GetDrawTarget()->IsDualDrawTarget())) {
|
||||
if (mContext->GetDrawTarget()->GetBackendType() != mozilla::gfx::BackendType::CAIRO ||
|
||||
mContext->GetDrawTarget()->IsDualDrawTarget()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -647,37 +647,6 @@ gfxWindowsPlatform::GetScaledFontForFont(DrawTarget* aTarget, gfxFont *aFont)
|
||||
return Factory::CreateScaledFontForNativeFont(nativeFont, aFont->GetAdjustedSize());
|
||||
}
|
||||
|
||||
already_AddRefed<gfxASurface>
|
||||
gfxWindowsPlatform::GetThebesSurfaceForDrawTarget(DrawTarget *aTarget)
|
||||
{
|
||||
#ifdef XP_WIN
|
||||
if (aTarget->GetBackendType() == BackendType::DIRECT2D) {
|
||||
if (!GetD2DDevice()) {
|
||||
// We no longer have a D2D device, can't do this.
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RefPtr<ID3D10Texture2D> texture =
|
||||
static_cast<ID3D10Texture2D*>(aTarget->GetNativeSurface(NativeSurfaceType::D3D10_TEXTURE));
|
||||
|
||||
if (!texture) {
|
||||
return gfxPlatform::GetThebesSurfaceForDrawTarget(aTarget);
|
||||
}
|
||||
|
||||
aTarget->Flush();
|
||||
|
||||
nsRefPtr<gfxASurface> surf =
|
||||
new gfxD2DSurface(texture, ContentForFormat(aTarget->GetFormat()));
|
||||
|
||||
// shouldn't this hold a reference?
|
||||
surf->SetData(&kDrawTarget, aTarget, nullptr);
|
||||
return surf.forget();
|
||||
}
|
||||
#endif
|
||||
|
||||
return gfxPlatform::GetThebesSurfaceForDrawTarget(aTarget);
|
||||
}
|
||||
|
||||
nsresult
|
||||
gfxWindowsPlatform::GetFontList(nsIAtom *aLangGroup,
|
||||
const nsACString& aGenericFamily,
|
||||
|
@ -60,7 +60,6 @@ struct DCFromContext {
|
||||
DCFromContext(gfxContext *aContext) {
|
||||
dc = nullptr;
|
||||
nsRefPtr<gfxASurface> aSurface = aContext->CurrentSurface();
|
||||
NS_ASSERTION(aSurface || !aContext->IsCairo(), "DCFromContext: null surface");
|
||||
if (aSurface &&
|
||||
(aSurface->GetType() == gfxSurfaceType::Win32 ||
|
||||
aSurface->GetType() == gfxSurfaceType::Win32Printing))
|
||||
@ -131,8 +130,6 @@ public:
|
||||
|
||||
virtual mozilla::TemporaryRef<mozilla::gfx::ScaledFont>
|
||||
GetScaledFontForFont(mozilla::gfx::DrawTarget* aTarget, gfxFont *aFont);
|
||||
virtual already_AddRefed<gfxASurface>
|
||||
GetThebesSurfaceForDrawTarget(mozilla::gfx::DrawTarget *aTarget);
|
||||
|
||||
enum RenderMode {
|
||||
/* Use GDI and windows surfaces */
|
||||
|
@ -140,10 +140,6 @@ gfxXlibNativeRenderer::DrawDirect(gfxContext *ctx, nsIntSize size,
|
||||
uint32_t flags,
|
||||
Screen *screen, Visual *visual)
|
||||
{
|
||||
if (ctx->IsCairo()) {
|
||||
return DrawCairo(ctx->GetCairo(), size, flags, screen, visual);
|
||||
}
|
||||
|
||||
// We need to actually borrow the context because we want to read out the
|
||||
// clip rectangles.
|
||||
BorrowedCairoContext borrowed(ctx->GetDrawTarget());
|
||||
@ -529,19 +525,11 @@ gfxXlibNativeRenderer::Draw(gfxContext* ctx, nsIntSize size,
|
||||
gfxPoint offset(drawingRect.x, drawingRect.y);
|
||||
|
||||
DrawingMethod method;
|
||||
cairo_surface_t* cairoTarget = nullptr;
|
||||
DrawTarget* drawTarget = nullptr;
|
||||
gfxPoint deviceTranslation;
|
||||
if (ctx->IsCairo()) {
|
||||
cairoTarget = cairo_get_group_target(ctx->GetCairo());
|
||||
deviceTranslation = ctx->CurrentMatrix().GetTranslation();
|
||||
} else {
|
||||
drawTarget = ctx->GetDrawTarget();
|
||||
Matrix dtTransform = drawTarget->GetTransform();
|
||||
deviceTranslation = gfxPoint(dtTransform._31, dtTransform._32);
|
||||
cairoTarget = static_cast<cairo_surface_t*>
|
||||
DrawTarget* drawTarget = ctx->GetDrawTarget();
|
||||
Matrix dtTransform = drawTarget->GetTransform();
|
||||
gfxPoint deviceTranslation = gfxPoint(dtTransform._31, dtTransform._32);
|
||||
cairo_surface_t* cairoTarget = static_cast<cairo_surface_t*>
|
||||
(drawTarget->GetNativeSurface(NativeSurfaceType::CAIRO_SURFACE));
|
||||
}
|
||||
|
||||
cairo_surface_t* tempXlibSurface =
|
||||
CreateTempXlibSurface(cairoTarget, drawTarget, size,
|
||||
|
@ -393,20 +393,6 @@ bool imgFrame::Draw(gfxContext *aContext, GraphicsFilter aFilter,
|
||||
if (mSinglePixelColor.a == 0.0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (aContext->IsCairo()) {
|
||||
gfxContext::GraphicsOperator op = aContext->CurrentOperator();
|
||||
if (op == gfxContext::OPERATOR_OVER && mSinglePixelColor.a == 1.0) {
|
||||
aContext->SetOperator(gfxContext::OPERATOR_SOURCE);
|
||||
}
|
||||
aContext->SetDeviceColor(ThebesColor(mSinglePixelColor));
|
||||
aContext->NewPath();
|
||||
aContext->Rectangle(aFill);
|
||||
aContext->Fill();
|
||||
aContext->SetOperator(op);
|
||||
aContext->SetDeviceColor(gfxRGBA(0,0,0,0));
|
||||
return true;
|
||||
}
|
||||
RefPtr<DrawTarget> dt = aContext->GetDrawTarget();
|
||||
dt->FillRect(ToRect(aFill),
|
||||
ColorPattern(mSinglePixelColor),
|
||||
|
@ -32,7 +32,9 @@ export-preqs = \
|
||||
$(call mkdir_deps,$(CURDIR)/third_party/libevent) \
|
||||
$(NULL)
|
||||
|
||||
export:: $(export-preqs)
|
||||
export:: $(DIST)/third_party/libevent/event.h
|
||||
|
||||
$(DIST)/third_party/libevent/event.h:: $(export-preqs)
|
||||
echo '#include <event.h>' > $(CURDIR)/third_party/libevent/event.h
|
||||
|
||||
endif # }
|
||||
|
@ -333,6 +333,7 @@ static const char * const statementName[] = {
|
||||
"for/in loop", /* FOR_IN_LOOP */
|
||||
"for/of loop", /* FOR_OF_LOOP */
|
||||
"while loop", /* WHILE_LOOP */
|
||||
"spread", /* SPREAD */
|
||||
};
|
||||
|
||||
JS_STATIC_ASSERT(JS_ARRAY_LENGTH(statementName) == STMT_LIMIT);
|
||||
@ -603,6 +604,10 @@ NonLocalExitScope::prepareForNonLocalJump(StmtInfoBCE *toStmt)
|
||||
return false;
|
||||
break;
|
||||
|
||||
case STMT_SPREAD:
|
||||
MOZ_ASSERT_UNREACHABLE("can't break/continue/return from inside a spread");
|
||||
break;
|
||||
|
||||
case STMT_SUBROUTINE:
|
||||
/*
|
||||
* There's a [exception or hole, retsub pc-index] pair on the
|
||||
@ -706,13 +711,17 @@ PushLoopStatement(BytecodeEmitter *bce, LoopStmtInfo *stmt, StmtType type, ptrdi
|
||||
stmt->loopDepth = downLoop ? downLoop->loopDepth + 1 : 1;
|
||||
|
||||
int loopSlots;
|
||||
if (type == STMT_FOR_OF_LOOP)
|
||||
if (type == STMT_SPREAD)
|
||||
loopSlots = 3;
|
||||
else if (type == STMT_FOR_OF_LOOP)
|
||||
loopSlots = 2;
|
||||
else if (type == STMT_FOR_IN_LOOP)
|
||||
loopSlots = 1;
|
||||
else
|
||||
loopSlots = 0;
|
||||
|
||||
MOZ_ASSERT(loopSlots <= stmt->stackDepth);
|
||||
|
||||
if (downLoop)
|
||||
stmt->canIonOsr = (downLoop->canIonOsr &&
|
||||
stmt->stackDepth == downLoop->stackDepth + loopSlots);
|
||||
@ -4436,13 +4445,26 @@ EmitIterator(ExclusiveContext *cx, BytecodeEmitter *bce)
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* If type is STMT_FOR_OF_LOOP, it emits bytecode for for-of loop.
|
||||
* pn should be PNK_FOR, and pn->pn_left should be PNK_FOROF.
|
||||
*
|
||||
* If type is STMT_SPREAD, it emits bytecode for spread operator.
|
||||
* pn should be nullptr.
|
||||
* Please refer the comment above EmitSpread for additional information about
|
||||
* stack convention.
|
||||
*/
|
||||
static bool
|
||||
EmitForOf(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn, ptrdiff_t top)
|
||||
EmitForOf(ExclusiveContext *cx, BytecodeEmitter *bce, StmtType type, ParseNode *pn, ptrdiff_t top)
|
||||
{
|
||||
ParseNode *forHead = pn->pn_left;
|
||||
ParseNode *forBody = pn->pn_right;
|
||||
JS_ASSERT(type == STMT_FOR_OF_LOOP || type == STMT_SPREAD);
|
||||
JS_ASSERT_IF(type == STMT_FOR_OF_LOOP, pn && pn->pn_left->isKind(PNK_FOROF));
|
||||
JS_ASSERT_IF(type == STMT_SPREAD, !pn);
|
||||
|
||||
ParseNode *pn1 = forHead->pn_kid1;
|
||||
ParseNode *forHead = pn ? pn->pn_left : nullptr;
|
||||
ParseNode *forBody = pn ? pn->pn_right : nullptr;
|
||||
|
||||
ParseNode *pn1 = forHead ? forHead->pn_kid1 : nullptr;
|
||||
bool letDecl = pn1 && pn1->isKind(PNK_LEXICALSCOPE);
|
||||
JS_ASSERT_IF(letDecl, pn1->isLet());
|
||||
|
||||
@ -4457,19 +4479,27 @@ EmitForOf(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn, ptrdiff_t t
|
||||
bce->emittingForInit = false;
|
||||
}
|
||||
|
||||
// For-of loops run with two values on the stack: the iterator and the
|
||||
// current result object.
|
||||
if (type == STMT_FOR_OF_LOOP) {
|
||||
// For-of loops run with two values on the stack: the iterator and the
|
||||
// current result object.
|
||||
|
||||
// Compile the object expression to the right of 'of'.
|
||||
if (!EmitTree(cx, bce, forHead->pn_kid3))
|
||||
return false;
|
||||
// Compile the object expression to the right of 'of'.
|
||||
if (!EmitTree(cx, bce, forHead->pn_kid3))
|
||||
return false;
|
||||
if (!EmitIterator(cx, bce))
|
||||
return false;
|
||||
|
||||
if (!EmitIterator(cx, bce))
|
||||
return false;
|
||||
|
||||
// Push a dummy result so that we properly enter iteration midstream.
|
||||
if (Emit1(cx, bce, JSOP_UNDEFINED) < 0) // ITER RESULT
|
||||
return false;
|
||||
// Push a dummy result so that we properly enter iteration midstream.
|
||||
if (Emit1(cx, bce, JSOP_UNDEFINED) < 0) // ITER RESULT
|
||||
return false;
|
||||
} else {
|
||||
// If type is STMT_SPREAD, it expects that iterator to be already on
|
||||
// the stack.
|
||||
if (Emit2(cx, bce, JSOP_PICK, (jsbytecode)2) < 0) // I ITER ARR
|
||||
return false;
|
||||
if (Emit2(cx, bce, JSOP_PICK, (jsbytecode)2) < 0) // ITER ARR I
|
||||
return false;
|
||||
}
|
||||
|
||||
// Enter the block before the loop body, after evaluating the obj.
|
||||
StmtInfoBCE letStmt(cx);
|
||||
@ -4479,7 +4509,7 @@ EmitForOf(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn, ptrdiff_t t
|
||||
}
|
||||
|
||||
LoopStmtInfo stmtInfo(cx);
|
||||
PushLoopStatement(bce, &stmtInfo, STMT_FOR_OF_LOOP, top);
|
||||
PushLoopStatement(bce, &stmtInfo, type, top);
|
||||
|
||||
// Jump down to the loop condition to minimize overhead assuming at least
|
||||
// one iteration, as the other loop forms do. Annotate so IonMonkey can
|
||||
@ -4496,59 +4526,76 @@ EmitForOf(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn, ptrdiff_t t
|
||||
if (EmitLoopHead(cx, bce, nullptr) < 0)
|
||||
return false;
|
||||
|
||||
if (type == STMT_SPREAD)
|
||||
bce->stackDepth++;
|
||||
|
||||
#ifdef DEBUG
|
||||
int loopDepth = bce->stackDepth;
|
||||
#endif
|
||||
|
||||
// Emit code to assign result.value to the iteration variable.
|
||||
if (Emit1(cx, bce, JSOP_DUP) < 0) // ITER RESULT RESULT
|
||||
return false;
|
||||
if (!EmitAtomOp(cx, cx->names().value, JSOP_GETPROP, bce)) // ITER RESULT VALUE
|
||||
return false;
|
||||
if (!EmitAssignment(cx, bce, forHead->pn_kid2, JSOP_NOP, nullptr)) // ITER RESULT VALUE
|
||||
return false;
|
||||
if (Emit1(cx, bce, JSOP_POP) < 0) // ITER RESULT
|
||||
if (type == STMT_FOR_OF_LOOP) {
|
||||
if (Emit1(cx, bce, JSOP_DUP) < 0) // ITER RESULT RESULT
|
||||
return false;
|
||||
}
|
||||
if (!EmitAtomOp(cx, cx->names().value, JSOP_GETPROP, bce)) // ... RESULT VALUE
|
||||
return false;
|
||||
if (type == STMT_FOR_OF_LOOP) {
|
||||
if (!EmitAssignment(cx, bce, forHead->pn_kid2, JSOP_NOP, nullptr)) // ITER RESULT VALUE
|
||||
return false;
|
||||
if (Emit1(cx, bce, JSOP_POP) < 0) // ITER RESULT
|
||||
return false;
|
||||
|
||||
// The stack should be balanced around the assignment opcode sequence.
|
||||
JS_ASSERT(bce->stackDepth == loopDepth);
|
||||
// The stack should be balanced around the assignment opcode sequence.
|
||||
JS_ASSERT(bce->stackDepth == loopDepth);
|
||||
|
||||
// Emit code for the loop body.
|
||||
if (!EmitTree(cx, bce, forBody))
|
||||
return false;
|
||||
// Emit code for the loop body.
|
||||
if (!EmitTree(cx, bce, forBody))
|
||||
return false;
|
||||
|
||||
// Set loop and enclosing "update" offsets, for continue.
|
||||
StmtInfoBCE *stmt = &stmtInfo;
|
||||
do {
|
||||
stmt->update = bce->offset();
|
||||
} while ((stmt = stmt->down) != nullptr && stmt->type == STMT_LABEL);
|
||||
// Set loop and enclosing "update" offsets, for continue.
|
||||
StmtInfoBCE *stmt = &stmtInfo;
|
||||
do {
|
||||
stmt->update = bce->offset();
|
||||
} while ((stmt = stmt->down) != nullptr && stmt->type == STMT_LABEL);
|
||||
} else {
|
||||
if (Emit1(cx, bce, JSOP_INITELEM_INC) < 0) // ITER ARR (I+1)
|
||||
return false;
|
||||
|
||||
JS_ASSERT(bce->stackDepth == loopDepth - 1);
|
||||
|
||||
// STMT_SPREAD never contain continue, so do not set "update" offset.
|
||||
}
|
||||
|
||||
// COME FROM the beginning of the loop to here.
|
||||
SetJumpOffsetAt(bce, jmp);
|
||||
if (!EmitLoopEntry(cx, bce, nullptr))
|
||||
return false;
|
||||
|
||||
if (Emit1(cx, bce, JSOP_POP) < 0) // ITER
|
||||
if (type == STMT_FOR_OF_LOOP) {
|
||||
if (Emit1(cx, bce, JSOP_POP) < 0) // ITER
|
||||
return false;
|
||||
if (Emit1(cx, bce, JSOP_DUP) < 0) // ITER ITER
|
||||
return false;
|
||||
} else {
|
||||
if (!EmitDupAt(cx, bce, bce->stackDepth - 1 - 2)) // ITER ARR I ITER
|
||||
return false;
|
||||
}
|
||||
if (Emit1(cx, bce, JSOP_DUP) < 0) // ... ITER ITER
|
||||
return false;
|
||||
if (Emit1(cx, bce, JSOP_DUP) < 0) // ITER ITER
|
||||
if (!EmitAtomOp(cx, cx->names().next, JSOP_CALLPROP, bce)) // ... ITER NEXT
|
||||
return false;
|
||||
if (Emit1(cx, bce, JSOP_DUP) < 0) // ITER ITER ITER
|
||||
if (Emit1(cx, bce, JSOP_SWAP) < 0) // ... NEXT ITER
|
||||
return false;
|
||||
if (!EmitAtomOp(cx, cx->names().next, JSOP_CALLPROP, bce)) // ITER ITER NEXT
|
||||
return false;
|
||||
if (Emit1(cx, bce, JSOP_SWAP) < 0) // ITER NEXT ITER
|
||||
return false;
|
||||
if (Emit1(cx, bce, JSOP_UNDEFINED) < 0) // ITER NEXT ITER UNDEFINED
|
||||
return false;
|
||||
if (EmitCall(cx, bce, JSOP_CALL, 1, forHead) < 0) // ITER RESULT
|
||||
if (EmitCall(cx, bce, JSOP_CALL, 0, forHead) < 0) // ... RESULT
|
||||
return false;
|
||||
CheckTypeSet(cx, bce, JSOP_CALL);
|
||||
if (Emit1(cx, bce, JSOP_DUP) < 0) // ITER RESULT RESULT
|
||||
if (Emit1(cx, bce, JSOP_DUP) < 0) // ... RESULT RESULT
|
||||
return false;
|
||||
if (!EmitAtomOp(cx, cx->names().done, JSOP_GETPROP, bce)) // ITER RESULT DONE?
|
||||
if (!EmitAtomOp(cx, cx->names().done, JSOP_GETPROP, bce)) // ... RESULT DONE?
|
||||
return false;
|
||||
|
||||
ptrdiff_t beq = EmitJump(cx, bce, JSOP_IFEQ, top - bce->offset()); // ITER RESULT
|
||||
ptrdiff_t beq = EmitJump(cx, bce, JSOP_IFEQ, top - bce->offset()); // ... RESULT
|
||||
if (beq < 0)
|
||||
return false;
|
||||
|
||||
@ -4559,6 +4606,7 @@ EmitForOf(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn, ptrdiff_t t
|
||||
return false;
|
||||
|
||||
// Fixup breaks and continues.
|
||||
// For STMT_SPREAD, just pop pc->topStmt.
|
||||
if (!PopStatementBCE(cx, bce))
|
||||
return false;
|
||||
|
||||
@ -4567,6 +4615,11 @@ EmitForOf(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn, ptrdiff_t t
|
||||
return false;
|
||||
}
|
||||
|
||||
if (type == STMT_SPREAD) {
|
||||
if (Emit2(cx, bce, JSOP_PICK, (jsbytecode)3) < 0) // ARR I RESULT ITER
|
||||
return false;
|
||||
}
|
||||
|
||||
// Pop the result and the iter.
|
||||
EMIT_UINT16_IMM_OP(JSOP_POPN, 2);
|
||||
|
||||
@ -4856,7 +4909,7 @@ EmitFor(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn, ptrdiff_t top
|
||||
return EmitForIn(cx, bce, pn, top);
|
||||
|
||||
if (pn->pn_left->isKind(PNK_FOROF))
|
||||
return EmitForOf(cx, bce, pn, top);
|
||||
return EmitForOf(cx, bce, STMT_FOR_OF_LOOP, pn, top);
|
||||
|
||||
JS_ASSERT(pn->pn_left->isKind(PNK_FORHEAD));
|
||||
return EmitNormalFor(cx, bce, pn, top);
|
||||
@ -6079,6 +6132,19 @@ EmitArrayComp(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn)
|
||||
return Emit1(cx, bce, JSOP_ENDINIT) >= 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* EmitSpread expects the iterator, the current index (I) of the array, and the
|
||||
* array itself to be on the stack in that order (iterator on the top). It will
|
||||
* pop the iterator and I, then iterate over the iterator by calling |.next()|
|
||||
* and put the results into the I-th element of array with incrementing I, then
|
||||
* push the result I (it will be original I + iteration count).
|
||||
*/
|
||||
static bool
|
||||
EmitSpread(ExclusiveContext *cx, BytecodeEmitter *bce)
|
||||
{
|
||||
return EmitForOf(cx, bce, STMT_SPREAD, nullptr, -1);
|
||||
}
|
||||
|
||||
static bool
|
||||
EmitArray(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn, uint32_t count)
|
||||
{
|
||||
@ -6129,7 +6195,7 @@ EmitArray(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn, uint32_t co
|
||||
if (pn2->isKind(PNK_SPREAD)) {
|
||||
if (!EmitIterator(cx, bce))
|
||||
return false;
|
||||
if (Emit1(cx, bce, JSOP_SPREAD) < 0)
|
||||
if (!EmitSpread(cx, bce))
|
||||
return false;
|
||||
} else if (afterSpread) {
|
||||
if (Emit1(cx, bce, JSOP_INITELEM_INC) < 0)
|
||||
|
@ -359,6 +359,7 @@ enum StmtType {
|
||||
STMT_FOR_IN_LOOP, /* for/in loop statement */
|
||||
STMT_FOR_OF_LOOP, /* for/of loop statement */
|
||||
STMT_WHILE_LOOP, /* while loop statement */
|
||||
STMT_SPREAD, /* spread operator (pseudo for/of) */
|
||||
STMT_LIMIT
|
||||
};
|
||||
|
||||
|
@ -7,7 +7,7 @@ var log = '';
|
||||
function Iter() {
|
||||
function next() {
|
||||
log += 'n';
|
||||
assertEq(arguments.length, 1)
|
||||
assertEq(arguments.length, 0)
|
||||
assertEq(arguments[0], undefined)
|
||||
return { get value() { throw 42; }, done: true }
|
||||
}
|
||||
|
@ -2370,34 +2370,6 @@ BaselineCompiler::emit_JSOP_INITELEM_INC()
|
||||
return true;
|
||||
}
|
||||
|
||||
typedef bool (*SpreadFn)(JSContext *, HandleObject, HandleValue,
|
||||
HandleValue, MutableHandleValue);
|
||||
static const VMFunction SpreadInfo = FunctionInfo<SpreadFn>(js::SpreadOperation);
|
||||
|
||||
bool
|
||||
BaselineCompiler::emit_JSOP_SPREAD()
|
||||
{
|
||||
// Load index and iterator in R0 and R1, but keep values on the stack for
|
||||
// the decompiler.
|
||||
frame.syncStack(0);
|
||||
masm.loadValue(frame.addressOfStackValue(frame.peek(-2)), R0);
|
||||
masm.loadValue(frame.addressOfStackValue(frame.peek(-1)), R1);
|
||||
|
||||
prepareVMCall();
|
||||
|
||||
pushArg(R1);
|
||||
pushArg(R0);
|
||||
masm.extractObject(frame.addressOfStackValue(frame.peek(-3)), R0.scratchReg());
|
||||
pushArg(R0.scratchReg());
|
||||
|
||||
if (!callVM(SpreadInfo))
|
||||
return false;
|
||||
|
||||
frame.popn(2);
|
||||
frame.push(R0);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
BaselineCompiler::emit_JSOP_GETLOCAL()
|
||||
{
|
||||
|
@ -98,7 +98,6 @@ namespace jit {
|
||||
_(JSOP_INITELEM_GETTER) \
|
||||
_(JSOP_INITELEM_SETTER) \
|
||||
_(JSOP_INITELEM_INC) \
|
||||
_(JSOP_SPREAD) \
|
||||
_(JSOP_MUTATEPROTO) \
|
||||
_(JSOP_INITPROP) \
|
||||
_(JSOP_INITPROP_GETTER) \
|
||||
|
@ -1,13 +1,11 @@
|
||||
// Test corner cases of for-of iteration over Arrays.
|
||||
// The current spidermonky JSOP_SPREAD implementation for function calls
|
||||
// with '...rest' arguments uses a ForOfIterator to extract values from
|
||||
// the array, so we use that mechanism to test ForOfIterator here.
|
||||
|
||||
// The current SetObject::construct method uses a ForOfIterator to extract
|
||||
// values from the array, so we use that mechanism to test ForOfIterator here.
|
||||
|
||||
// Test the properties and prototype of a generator object.
|
||||
function TestManySmallArrays() {
|
||||
function doIter(f, arr) {
|
||||
return f(...arr)
|
||||
return f(...new Set(arr));
|
||||
}
|
||||
|
||||
function fun(a, b, c) {
|
||||
@ -37,7 +35,7 @@ TestManySmallArrays();
|
||||
// Test the properties and prototype of a generator object.
|
||||
function TestSingleSmallArray() {
|
||||
function doIter(f, arr) {
|
||||
return f(...arr)
|
||||
return f(...new Set(arr));
|
||||
}
|
||||
|
||||
function fun(a, b, c) {
|
||||
@ -69,7 +67,7 @@ TestSingleSmallArray();
|
||||
|
||||
function TestChangeArrayPrototype() {
|
||||
function doIter(f, arr) {
|
||||
return f(...arr)
|
||||
return f(...new Set(arr));
|
||||
}
|
||||
|
||||
function fun(a, b, c) {
|
||||
@ -106,7 +104,7 @@ TestChangeArrayPrototype();
|
||||
|
||||
function TestChangeManyArrayShape() {
|
||||
function doIter(f, arr) {
|
||||
return f(...arr)
|
||||
return f(...new Set(arr));
|
||||
}
|
||||
|
||||
function fun(a, b, c) {
|
||||
|
@ -1,14 +1,13 @@
|
||||
// Test corner cases of for-of iteration over Arrays.
|
||||
// The current spidermonky JSOP_SPREAD implementation for function calls
|
||||
// with '...rest' arguments uses a ForOfIterator to extract values from
|
||||
// the array, so we use that mechanism to test ForOfIterator here.
|
||||
// The current SetObject::construct method uses a ForOfIterator to extract
|
||||
// values from the array, so we use that mechanism to test ForOfIterator here.
|
||||
|
||||
//
|
||||
// Check case where ArrayIterator.prototype.next changes in the middle of iteration.
|
||||
//
|
||||
function TestChangeArrayIteratorNext() {
|
||||
function doIter(f, arr) {
|
||||
return f(...arr)
|
||||
return f(...new Set(arr));
|
||||
}
|
||||
|
||||
function fun(a, b, c) {
|
||||
|
@ -1,14 +1,13 @@
|
||||
// Test corner cases of for-of iteration over Arrays.
|
||||
// The current spidermonkey JSOP_SPREAD implementation for function calls
|
||||
// with '...rest' arguments uses a ForOfIterator to extract values from
|
||||
// the array, so we use that mechanism to test ForOfIterator here.
|
||||
// The current SetObject::construct method uses a ForOfIterator to extract
|
||||
// values from the array, so we use that mechanism to test ForOfIterator here.
|
||||
|
||||
//
|
||||
// Check array length increases changes during iteration.
|
||||
//
|
||||
function TestIncreaseArrayLength() {
|
||||
function doIter(f, arr) {
|
||||
return f(...arr)
|
||||
return f(...new Set(arr));
|
||||
}
|
||||
|
||||
function fun(a, b, c) {
|
||||
|
@ -1,14 +1,13 @@
|
||||
// Test corner cases of for-of iteration over Arrays.
|
||||
// The current spidermonkey JSOP_SPREAD implementation for function calls
|
||||
// with '...rest' arguments uses a ForOfIterator to extract values from
|
||||
// the array, so we use that mechanism to test ForOfIterator here.
|
||||
// The current SetObject::construct method uses a ForOfIterator to extract
|
||||
// values from the array, so we use that mechanism to test ForOfIterator here.
|
||||
|
||||
//
|
||||
// Check array length decreases changes during iteration.
|
||||
//
|
||||
function TestDecreaseArrayLength() {
|
||||
function doIter(f, arr) {
|
||||
return f(...arr)
|
||||
return f(...new Set(arr));
|
||||
}
|
||||
|
||||
function fun(a, b, c) {
|
||||
|
@ -1597,6 +1597,7 @@ CASE(JSOP_UNUSED50)
|
||||
CASE(JSOP_UNUSED51)
|
||||
CASE(JSOP_UNUSED52)
|
||||
CASE(JSOP_UNUSED57)
|
||||
CASE(JSOP_UNUSED83)
|
||||
CASE(JSOP_UNUSED101)
|
||||
CASE(JSOP_UNUSED102)
|
||||
CASE(JSOP_UNUSED103)
|
||||
@ -3178,21 +3179,6 @@ CASE(JSOP_INITELEM_INC)
|
||||
}
|
||||
END_CASE(JSOP_INITELEM_INC)
|
||||
|
||||
CASE(JSOP_SPREAD)
|
||||
{
|
||||
HandleValue countVal = REGS.stackHandleAt(-2);
|
||||
RootedObject &arr = rootObject0;
|
||||
arr = ®S.sp[-3].toObject();
|
||||
HandleValue iterator = REGS.stackHandleAt(-1);
|
||||
MutableHandleValue resultCountVal = REGS.stackHandleAt(-2);
|
||||
|
||||
if (!SpreadOperation(cx, arr, countVal, iterator, resultCountVal))
|
||||
goto error;
|
||||
|
||||
REGS.sp--;
|
||||
}
|
||||
END_CASE(JSOP_SPREAD)
|
||||
|
||||
CASE(JSOP_GOSUB)
|
||||
{
|
||||
PUSH_BOOLEAN(false);
|
||||
@ -3897,34 +3883,6 @@ js::InitGetterSetterOperation(JSContext *cx, jsbytecode *pc, HandleObject obj, H
|
||||
return InitGetterSetterOperation(cx, pc, obj, id, val);
|
||||
}
|
||||
|
||||
bool
|
||||
js::SpreadOperation(JSContext *cx, HandleObject arr, HandleValue countVal,
|
||||
HandleValue iterator, MutableHandleValue resultCountVal)
|
||||
{
|
||||
int32_t count = countVal.toInt32();
|
||||
ForOfIterator iter(cx);
|
||||
RootedValue iterVal(cx, iterator);
|
||||
if (!iter.initWithIterator(iterVal))
|
||||
return false;
|
||||
while (true) {
|
||||
bool done;
|
||||
if (!iter.next(&iterVal, &done))
|
||||
return false;
|
||||
if (done)
|
||||
break;
|
||||
if (count == INT32_MAX) {
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr,
|
||||
JSMSG_SPREAD_TOO_LARGE);
|
||||
return false;
|
||||
}
|
||||
if (!JSObject::defineElement(cx, arr, count++, iterVal, nullptr, nullptr,
|
||||
JSPROP_ENUMERATE))
|
||||
return false;
|
||||
}
|
||||
resultCountVal.setInt32(count);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
js::SpreadCallOperation(JSContext *cx, HandleScript script, jsbytecode *pc, HandleValue thisv,
|
||||
HandleValue callee, HandleValue arr, MutableHandleValue res)
|
||||
|
@ -462,10 +462,6 @@ bool
|
||||
InitGetterSetterOperation(JSContext *cx, jsbytecode *pc, HandleObject obj, HandleValue idval,
|
||||
HandleObject val);
|
||||
|
||||
bool
|
||||
SpreadOperation(JSContext *cx, HandleObject arr, HandleValue countVal,
|
||||
HandleValue iterable, MutableHandleValue resultCountVal);
|
||||
|
||||
bool
|
||||
SpreadCallOperation(JSContext *cx, HandleScript script, jsbytecode *pc, HandleValue thisv,
|
||||
HandleValue callee, HandleValue arr, MutableHandleValue res);
|
||||
|
@ -690,20 +690,8 @@
|
||||
* nuses: (argc+2)
|
||||
*/ \
|
||||
macro(JSOP_NEW, 82, js_new_str, NULL, 3, -1, 1, JOF_UINT16|JOF_INVOKE|JOF_TYPESET) \
|
||||
/*
|
||||
* Pops the top three values on the stack as 'iterator', 'index' and 'obj',
|
||||
* iterates over 'iterator' and stores the iteration values as 'index + i'
|
||||
* elements of 'obj', pushes 'obj' and 'index + iteration count' onto the
|
||||
* stack.
|
||||
*
|
||||
* This opcode is used in Array literals with spread and spreadcall
|
||||
* arguments as well as in destructing assignment with rest element.
|
||||
* Category: Literals
|
||||
* Type: Array
|
||||
* Operands:
|
||||
* Stack: obj, index, iterator => obj, (index + iteration count)
|
||||
*/ \
|
||||
macro(JSOP_SPREAD, 83, "spread", NULL, 1, 3, 2, JOF_BYTE|JOF_ELEM|JOF_SET) \
|
||||
\
|
||||
macro(JSOP_UNUSED83, 83, "unused83", NULL, 1, 0, 0, JOF_BYTE) \
|
||||
\
|
||||
/*
|
||||
* Fast get op for function arguments and local variables.
|
||||
|
@ -28,7 +28,7 @@ namespace js {
|
||||
*
|
||||
* https://developer.mozilla.org/en-US/docs/SpiderMonkey/Internals/Bytecode
|
||||
*/
|
||||
static const uint32_t XDR_BYTECODE_VERSION = uint32_t(0xb973c0de - 175);
|
||||
static const uint32_t XDR_BYTECODE_VERSION = uint32_t(0xb973c0de - 176);
|
||||
|
||||
class XDRBuffer {
|
||||
public:
|
||||
|
@ -3751,7 +3751,6 @@ FrameLayerBuilder::PaintItems(nsTArray<ClippedDisplayItem>& aItems,
|
||||
static bool ShouldDrawRectsSeparately(gfxContext* aContext, DrawRegionClip aClip)
|
||||
{
|
||||
if (!gfxPrefs::LayoutPaintRectsSeparately() ||
|
||||
aContext->IsCairo() ||
|
||||
aClip == DrawRegionClip::CLIP_NONE) {
|
||||
return false;
|
||||
}
|
||||
|
@ -465,7 +465,6 @@ TouchCaret::HandleEvent(WidgetEvent* aEvent)
|
||||
|
||||
switch (aEvent->message) {
|
||||
case NS_TOUCH_START:
|
||||
case NS_TOUCH_ENTER:
|
||||
status = HandleTouchDownEvent(aEvent->AsTouchEvent());
|
||||
break;
|
||||
case NS_MOUSE_BUTTON_DOWN:
|
||||
|
@ -2528,34 +2528,23 @@ nsCSSRendering::PaintGradient(nsPresContext* aPresContext,
|
||||
bool isRepeat = aGradient->mRepeating || forceRepeatToCoverTiles;
|
||||
|
||||
// Now set normalized color stops in pattern.
|
||||
if (!ctx->IsCairo()) {
|
||||
// Offscreen gradient surface cache (not a tile):
|
||||
// On some backends (e.g. D2D), the GradientStops object holds an offscreen surface
|
||||
// which is a lookup table used to evaluate the gradient. This surface can use
|
||||
// much memory (ram and/or GPU ram) and can be expensive to create. So we cache it.
|
||||
// The cache key correlates 1:1 with the arguments for CreateGradientStops (also the implied backend type)
|
||||
// Note that GradientStop is a simple struct with a stop value (while GradientStops has the surface).
|
||||
nsTArray<gfx::GradientStop> rawStops(stops.Length());
|
||||
rawStops.SetLength(stops.Length());
|
||||
for(uint32_t i = 0; i < stops.Length(); i++) {
|
||||
rawStops[i].color = gfx::Color(stops[i].mColor.r, stops[i].mColor.g, stops[i].mColor.b, stops[i].mColor.a);
|
||||
rawStops[i].offset = stopScale * (stops[i].mPosition - stopOrigin);
|
||||
}
|
||||
mozilla::RefPtr<mozilla::gfx::GradientStops> gs =
|
||||
gfxGradientCache::GetOrCreateGradientStops(ctx->GetDrawTarget(),
|
||||
rawStops,
|
||||
isRepeat ? gfx::ExtendMode::REPEAT : gfx::ExtendMode::CLAMP);
|
||||
gradientPattern->SetColorStops(gs);
|
||||
} else {
|
||||
for (uint32_t i = 0; i < stops.Length(); i++) {
|
||||
double pos = stopScale*(stops[i].mPosition - stopOrigin);
|
||||
gradientPattern->AddColorStop(pos, stops[i].mColor);
|
||||
}
|
||||
// Set repeat mode. Default cairo extend mode is PAD.
|
||||
if (isRepeat) {
|
||||
gradientPattern->SetExtend(gfxPattern::EXTEND_REPEAT);
|
||||
}
|
||||
// Offscreen gradient surface cache (not a tile):
|
||||
// On some backends (e.g. D2D), the GradientStops object holds an offscreen surface
|
||||
// which is a lookup table used to evaluate the gradient. This surface can use
|
||||
// much memory (ram and/or GPU ram) and can be expensive to create. So we cache it.
|
||||
// The cache key correlates 1:1 with the arguments for CreateGradientStops (also the implied backend type)
|
||||
// Note that GradientStop is a simple struct with a stop value (while GradientStops has the surface).
|
||||
nsTArray<gfx::GradientStop> rawStops(stops.Length());
|
||||
rawStops.SetLength(stops.Length());
|
||||
for(uint32_t i = 0; i < stops.Length(); i++) {
|
||||
rawStops[i].color = gfx::Color(stops[i].mColor.r, stops[i].mColor.g, stops[i].mColor.b, stops[i].mColor.a);
|
||||
rawStops[i].offset = stopScale * (stops[i].mPosition - stopOrigin);
|
||||
}
|
||||
mozilla::RefPtr<mozilla::gfx::GradientStops> gs =
|
||||
gfxGradientCache::GetOrCreateGradientStops(ctx->GetDrawTarget(),
|
||||
rawStops,
|
||||
isRepeat ? gfx::ExtendMode::REPEAT : gfx::ExtendMode::CLAMP);
|
||||
gradientPattern->SetColorStops(gs);
|
||||
|
||||
// Paint gradient tiles. This isn't terribly efficient, but doing it this
|
||||
// way is simple and sure to get pixel-snapping right. We could speed things
|
||||
|
@ -1068,21 +1068,9 @@ nsCSSBorderRenderer::CreateCornerGradient(mozilla::css::Corner aCorner,
|
||||
pat2.y = cornerOrigin.y -
|
||||
mBorderWidths[cornerWidth[aCorner]] * gradientCoeff[aCorner].b;
|
||||
|
||||
float gradientOffset;
|
||||
|
||||
if (mContext->IsCairo() &&
|
||||
(mContext->OriginalSurface()->GetType() == gfxSurfaceType::D2D ||
|
||||
mContext->OriginalSurface()->GetType() == gfxSurfaceType::Quartz))
|
||||
{
|
||||
// On quarz this doesn't do exactly the right thing, but it does do what
|
||||
// most other browsers do and doing the 'right' thing seems to be
|
||||
// hard with the quartz cairo backend.
|
||||
gradientOffset = 0;
|
||||
} else {
|
||||
// When cairo/Azure does the gradient drawing this gives us pretty nice behavior!
|
||||
gradientOffset = 0.25 / sqrt(pow(mBorderWidths[cornerHeight[aCorner]], 2) +
|
||||
pow(mBorderWidths[cornerHeight[aCorner]], 2));
|
||||
}
|
||||
float gradientOffset =
|
||||
0.25 / sqrt(pow(mBorderWidths[cornerHeight[aCorner]], 2) +
|
||||
pow(mBorderWidths[cornerHeight[aCorner]], 2));
|
||||
|
||||
nsRefPtr<gfxPattern> pattern = new gfxPattern(pat1.x, pat1.y, pat2.x, pat2.y);
|
||||
pattern->AddColorStop(0.5 - gradientOffset, gfxRGBA(aFirstColor));
|
||||
@ -1188,154 +1176,6 @@ nsCSSBorderRenderer::DrawSingleWidthSolidBorder()
|
||||
|
||||
void
|
||||
nsCSSBorderRenderer::DrawNoCompositeColorSolidBorder()
|
||||
{
|
||||
const gfxFloat alpha = 0.55191497064665766025;
|
||||
|
||||
const twoFloats cornerMults[4] = { { -1, 0 },
|
||||
{ 0, -1 },
|
||||
{ +1, 0 },
|
||||
{ 0, +1 } };
|
||||
|
||||
const twoFloats centerAdjusts[4] = { { 0, +0.5 },
|
||||
{ -0.5, 0 },
|
||||
{ 0, -0.5 },
|
||||
{ +0.5, 0 } };
|
||||
|
||||
gfxPoint pc, pci, p0, p1, p2, p3, pd, p3i;
|
||||
|
||||
gfxCornerSizes innerRadii;
|
||||
ComputeInnerRadii(mBorderRadii, mBorderWidths, &innerRadii);
|
||||
|
||||
gfxRect strokeRect = mOuterRect;
|
||||
strokeRect.Deflate(gfxMargin(mBorderWidths[0] / 2.0, mBorderWidths[1] / 2.0,
|
||||
mBorderWidths[2] / 2.0, mBorderWidths[3] / 2.0));
|
||||
|
||||
NS_FOR_CSS_CORNERS(i) {
|
||||
// the corner index -- either 1 2 3 0 (cw) or 0 3 2 1 (ccw)
|
||||
mozilla::css::Corner c = mozilla::css::Corner((i+1) % 4);
|
||||
mozilla::css::Corner prevCorner = mozilla::css::Corner(i);
|
||||
|
||||
// i+2 and i+3 respectively. These are used to index into the corner
|
||||
// multiplier table, and were deduced by calculating out the long form
|
||||
// of each corner and finding a pattern in the signs and values.
|
||||
int i1 = (i+1) % 4;
|
||||
int i2 = (i+2) % 4;
|
||||
int i3 = (i+3) % 4;
|
||||
|
||||
pc = mOuterRect.AtCorner(c);
|
||||
pci = mInnerRect.AtCorner(c);
|
||||
mContext->SetLineWidth(mBorderWidths[i]);
|
||||
|
||||
nscolor firstColor, secondColor;
|
||||
if (IsVisible(mBorderStyles[i]) && IsVisible(mBorderStyles[i1])) {
|
||||
firstColor = mBorderColors[i];
|
||||
secondColor = mBorderColors[i1];
|
||||
} else if (IsVisible(mBorderStyles[i])) {
|
||||
firstColor = mBorderColors[i];
|
||||
secondColor = mBorderColors[i];
|
||||
} else {
|
||||
firstColor = mBorderColors[i1];
|
||||
secondColor = mBorderColors[i1];
|
||||
}
|
||||
|
||||
mContext->NewPath();
|
||||
|
||||
gfxPoint strokeStart, strokeEnd;
|
||||
|
||||
strokeStart.x = mOuterRect.AtCorner(prevCorner).x +
|
||||
mBorderCornerDimensions[prevCorner].width * cornerMults[i2].a;
|
||||
strokeStart.y = mOuterRect.AtCorner(prevCorner).y +
|
||||
mBorderCornerDimensions[prevCorner].height * cornerMults[i2].b;
|
||||
|
||||
strokeEnd.x = pc.x + mBorderCornerDimensions[c].width * cornerMults[i].a;
|
||||
strokeEnd.y = pc.y + mBorderCornerDimensions[c].height * cornerMults[i].b;
|
||||
|
||||
strokeStart.x += centerAdjusts[i].a * mBorderWidths[i];
|
||||
strokeStart.y += centerAdjusts[i].b * mBorderWidths[i];
|
||||
strokeEnd.x += centerAdjusts[i].a * mBorderWidths[i];
|
||||
strokeEnd.y += centerAdjusts[i].b * mBorderWidths[i];
|
||||
|
||||
mContext->MoveTo(strokeStart);
|
||||
mContext->LineTo(strokeEnd);
|
||||
mContext->SetColor(gfxRGBA(mBorderColors[i]));
|
||||
mContext->Stroke();
|
||||
|
||||
if (firstColor != secondColor) {
|
||||
nsRefPtr<gfxPattern> pattern =
|
||||
CreateCornerGradient(c, firstColor, secondColor);
|
||||
mContext->SetPattern(pattern);
|
||||
} else {
|
||||
mContext->SetColor(firstColor);
|
||||
}
|
||||
|
||||
if (mBorderRadii[c].width > 0 && mBorderRadii[c].height > 0) {
|
||||
p0.x = pc.x + cornerMults[i].a * mBorderRadii[c].width;
|
||||
p0.y = pc.y + cornerMults[i].b * mBorderRadii[c].height;
|
||||
|
||||
p3.x = pc.x + cornerMults[i3].a * mBorderRadii[c].width;
|
||||
p3.y = pc.y + cornerMults[i3].b * mBorderRadii[c].height;
|
||||
|
||||
p1.x = p0.x + alpha * cornerMults[i2].a * mBorderRadii[c].width;
|
||||
p1.y = p0.y + alpha * cornerMults[i2].b * mBorderRadii[c].height;
|
||||
|
||||
p2.x = p3.x - alpha * cornerMults[i3].a * mBorderRadii[c].width;
|
||||
p2.y = p3.y - alpha * cornerMults[i3].b * mBorderRadii[c].height;
|
||||
|
||||
mContext->NewPath();
|
||||
|
||||
gfxPoint cornerStart;
|
||||
cornerStart.x = pc.x + cornerMults[i].a * mBorderCornerDimensions[c].width;
|
||||
cornerStart.y = pc.y + cornerMults[i].b * mBorderCornerDimensions[c].height;
|
||||
|
||||
mContext->MoveTo(cornerStart);
|
||||
mContext->LineTo(p0);
|
||||
|
||||
mContext->CurveTo(p1, p2, p3);
|
||||
|
||||
gfxPoint outerCornerEnd;
|
||||
outerCornerEnd.x = pc.x + cornerMults[i3].a * mBorderCornerDimensions[c].width;
|
||||
outerCornerEnd.y = pc.y + cornerMults[i3].b * mBorderCornerDimensions[c].height;
|
||||
|
||||
mContext->LineTo(outerCornerEnd);
|
||||
|
||||
p0.x = pci.x + cornerMults[i].a * innerRadii[c].width;
|
||||
p0.y = pci.y + cornerMults[i].b * innerRadii[c].height;
|
||||
|
||||
p3i.x = pci.x + cornerMults[i3].a * innerRadii[c].width;
|
||||
p3i.y = pci.y + cornerMults[i3].b * innerRadii[c].height;
|
||||
|
||||
p1.x = p0.x + alpha * cornerMults[i2].a * innerRadii[c].width;
|
||||
p1.y = p0.y + alpha * cornerMults[i2].b * innerRadii[c].height;
|
||||
|
||||
p2.x = p3i.x - alpha * cornerMults[i3].a * innerRadii[c].width;
|
||||
p2.y = p3i.y - alpha * cornerMults[i3].b * innerRadii[c].height;
|
||||
mContext->LineTo(p3i);
|
||||
mContext->CurveTo(p2, p1, p0);
|
||||
mContext->ClosePath();
|
||||
mContext->Fill();
|
||||
} else {
|
||||
gfxPoint c1, c2, c3, c4;
|
||||
|
||||
c1.x = pc.x + cornerMults[i].a * mBorderCornerDimensions[c].width;
|
||||
c1.y = pc.y + cornerMults[i].b * mBorderCornerDimensions[c].height;
|
||||
c2 = pc;
|
||||
c3.x = pc.x + cornerMults[i3].a * mBorderCornerDimensions[c].width;
|
||||
c3.y = pc.y + cornerMults[i3].b * mBorderCornerDimensions[c].height;
|
||||
|
||||
mContext->NewPath();
|
||||
mContext->MoveTo(c1);
|
||||
mContext->LineTo(c2);
|
||||
mContext->LineTo(c3);
|
||||
mContext->LineTo(pci);
|
||||
mContext->ClosePath();
|
||||
|
||||
mContext->Fill();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsCSSBorderRenderer::DrawNoCompositeColorSolidBorderAzure()
|
||||
{
|
||||
DrawTarget *dt = mContext->GetDrawTarget();
|
||||
|
||||
@ -1714,11 +1554,7 @@ nsCSSBorderRenderer::DrawBorders()
|
||||
if (allBordersSolid && !hasCompositeColors &&
|
||||
!mAvoidStroke)
|
||||
{
|
||||
if (mContext->IsCairo()) {
|
||||
DrawNoCompositeColorSolidBorder();
|
||||
} else {
|
||||
DrawNoCompositeColorSolidBorderAzure();
|
||||
}
|
||||
DrawNoCompositeColorSolidBorder();
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -203,9 +203,6 @@ struct nsCSSBorderRenderer {
|
||||
// Draw any border which is solid on all sides and does not use
|
||||
// CompositeColors.
|
||||
void DrawNoCompositeColorSolidBorder();
|
||||
// Draw any border which is solid on all sides and does not use
|
||||
// CompositeColors. Using Azure.
|
||||
void DrawNoCompositeColorSolidBorderAzure();
|
||||
|
||||
// Draw a solid border that has no border radius (i.e. is rectangular) and
|
||||
// uses CompositeColors.
|
||||
|
@ -7179,6 +7179,9 @@ PresShell::HandleEvent(nsIFrame* aFrame,
|
||||
|
||||
if (pointerCapturingContent) {
|
||||
if (nsIFrame* capturingFrame = pointerCapturingContent->GetPrimaryFrame()) {
|
||||
// If pointer capture is set, we should suppress pointerover/pointerenter events
|
||||
// for all elements except element which have pointer capture. (Code in EventStateManager)
|
||||
pointerEvent->retargetedByPointerCapture = (frame != capturingFrame);
|
||||
frame = capturingFrame;
|
||||
}
|
||||
|
||||
|
243
layout/base/tests/bug976963_inner.html
Normal file
243
layout/base/tests/bug976963_inner.html
Normal file
@ -0,0 +1,243 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=976963
|
||||
-->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for Bug 976963</title>
|
||||
<meta name="author" content="Maksim Lebedev" />
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
<style>
|
||||
div#listener {
|
||||
background: yellow;
|
||||
position: absolute;
|
||||
top: -100px;
|
||||
}
|
||||
div#middler {
|
||||
background: yellow;
|
||||
margin: 10px;
|
||||
}
|
||||
div#target {
|
||||
background: yellow;
|
||||
}
|
||||
</style>
|
||||
<script type="application/javascript">
|
||||
/** Test for Bug 976963 **/
|
||||
var All_Pointer_Events = ["pointerover", "pointerenter",
|
||||
"pointermove",
|
||||
"pointerdown", "pointerup",
|
||||
"pointerout", "pointerleave",
|
||||
"pointercancel",
|
||||
"gotpointercapture", "lostpointercapture"];
|
||||
|
||||
function on_event(object, event, callback) {
|
||||
object.addEventListener(event, callback, false);
|
||||
}
|
||||
function ok(check, msg) {
|
||||
parent.ok(check, msg);
|
||||
}
|
||||
function is(a, b, msg) {
|
||||
parent.is(a, b, msg);
|
||||
}
|
||||
|
||||
var listener = undefined;
|
||||
var middler = undefined;
|
||||
var target = undefined;
|
||||
|
||||
var test_ListenerGotCapture = 0;
|
||||
var test_ListenerUnwanted = 0;
|
||||
var test_ListenerLostCapture = 0;
|
||||
var test_ListenerAfterCapture = 0;
|
||||
var test_MiddlerGotCapture = 0;
|
||||
var test_MiddlerOver = 0;
|
||||
var test_MiddlerLeave = 0;
|
||||
var test_MiddlerUp = 0;
|
||||
var test_MiddlerLostCapture = 0;
|
||||
var test_TargetDown = 0;
|
||||
var test_TargetUnwanted = 0;
|
||||
var test_TargetUp = 0;
|
||||
|
||||
var captured_event = undefined;
|
||||
var f_gotPointerCapture = false;
|
||||
var f_lostPointerCapture = false;
|
||||
var f_gotMiddlerPointerCapture = false;
|
||||
|
||||
function listenerEventHandler(event) {
|
||||
logger("Listener: " + event.type + ". Captured_event: " + captured_event);
|
||||
if(test_ListenerLostCapture)
|
||||
test_ListenerAfterCapture++;
|
||||
if (event.type == "gotpointercapture") {
|
||||
f_gotPointerCapture = true;
|
||||
test_ListenerGotCapture++;
|
||||
}
|
||||
else if (event.type == "lostpointercapture") {
|
||||
f_lostPointerCapture = true;
|
||||
f_gotPointerCapture = false;
|
||||
test_ListenerLostCapture++;
|
||||
}
|
||||
else if (event.type == "pointermove") {
|
||||
ok(captured_event && captured_event.pointerId == event.pointerId, "Listener: equals pointerId for lostpointercapture event");
|
||||
if (f_gotPointerCapture) {
|
||||
// on first event received for capture, release capture
|
||||
logger("Listener call release");
|
||||
ok(!!listener, "Listener should be live!");
|
||||
ok(typeof(listener.releasePointerCapture) == "function", "Listener should have a function releasePointerCapture");
|
||||
listener.releasePointerCapture(event.pointerId);
|
||||
}
|
||||
else {
|
||||
logger("Listener.ASSERT: " + event.type);
|
||||
test_ListenerUnwanted++;
|
||||
// if any other events are received after releaseCapture, then the test fails
|
||||
ok(false, event.target.id + "-" + event.type + " should be handled by target element handler");
|
||||
}
|
||||
}
|
||||
else {
|
||||
test_ListenerUnwanted++;
|
||||
logger("Listener.ASSERT: " + event.type);
|
||||
ok(false, event.type + "should be never handled by listener");
|
||||
}
|
||||
}
|
||||
|
||||
function middlerEventHandler(event) {
|
||||
logger("Middler: " + event.type + ". Captured_event: " + captured_event);
|
||||
if (event.type == "gotpointercapture") {
|
||||
test_MiddlerGotCapture++;
|
||||
f_gotMiddlerPointerCapture = true;
|
||||
ok(captured_event && captured_event.pointerId == event.pointerId, "Middler: equals pointerId for gotpointercapture event");
|
||||
}
|
||||
else if (event.type == "pointerover") {
|
||||
test_MiddlerOver++;
|
||||
ok(captured_event && captured_event.pointerId == event.pointerId, "Middler: equals pointerId for pointerover event");
|
||||
}
|
||||
else if (event.type == "pointerleave") {
|
||||
test_MiddlerLeave++;
|
||||
ok(captured_event && captured_event.pointerId == event.pointerId, "Middler: equals pointerId for pointerleave event");
|
||||
ok(!!listener, "Listener should be live!");
|
||||
ok(typeof(listener.setPointerCapture) == "function", "Listener should have a function setPointerCapture");
|
||||
listener.setPointerCapture(event.pointerId);
|
||||
}
|
||||
else if (event.type == "lostpointercapture") {
|
||||
test_MiddlerLostCapture++;
|
||||
f_gotMiddlerPointerCapture = false;
|
||||
ok(captured_event && captured_event.pointerId == event.pointerId, "Middler: equals pointerId for lostpointercapture event");
|
||||
}
|
||||
else if (event.type == "pointerup" ) {
|
||||
test_MiddlerUp++;
|
||||
}
|
||||
}
|
||||
|
||||
function targetEventHandler(event) {
|
||||
logger("Target: " + event.type + ". Captured_event: " + captured_event);
|
||||
if (f_gotPointerCapture || f_gotMiddlerPointerCapture) {
|
||||
if (event.type != "pointerout" && event.type != "pointerleave") {
|
||||
logger("Target.ASSERT: " + event.type + " " + event.pointerId);
|
||||
test_TargetUnwanted++;
|
||||
ok(false, "The Target element should not have received any events while capture is active. Event recieved:" + event.type + ". ");
|
||||
}
|
||||
}
|
||||
if (event.type == "pointerdown") {
|
||||
logger("Target.pointerdown 1: " + captured_event);
|
||||
test_TargetDown++;
|
||||
captured_event = event;
|
||||
ok(!!middler, "Middler should be live!");
|
||||
ok(typeof(middler.setPointerCapture) == "function", "Middler should have a function setPointerCapture");
|
||||
middler.setPointerCapture(event.pointerId);
|
||||
logger("Target.pointerdown 2: " + captured_event);
|
||||
}
|
||||
else if (event.type == "pointerup") {
|
||||
ok(f_lostPointerCapture, "Target should have received pointerup");
|
||||
ok(captured_event && captured_event.pointerId == event.pointerId, "Target: equals pointerId for lostpointercapture event");
|
||||
test_TargetUp++; // complete test
|
||||
}
|
||||
}
|
||||
|
||||
function colorerHandler(event) {
|
||||
if(event.type == "pointerover")
|
||||
event.target.style.background = "red";
|
||||
else if(event.type == "pointerout")
|
||||
event.target.style.background = "yellow";
|
||||
}
|
||||
|
||||
function setEventHandlers() {
|
||||
listener = document.getElementById("listener");
|
||||
middler = document.getElementById("middler");
|
||||
target = document.getElementById("target");
|
||||
target.style["touchAction"] = "none";
|
||||
|
||||
// target and listener - handle all events
|
||||
for (var i = 0; i < All_Pointer_Events.length; i++) {
|
||||
on_event(target, All_Pointer_Events[i], targetEventHandler);
|
||||
on_event(listener, All_Pointer_Events[i], listenerEventHandler);
|
||||
on_event(middler, All_Pointer_Events[i], middlerEventHandler);
|
||||
on_event(target, All_Pointer_Events[i], colorerHandler);
|
||||
on_event(middler, All_Pointer_Events[i], colorerHandler);
|
||||
}
|
||||
}
|
||||
|
||||
function prepareTest() {
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
SpecialPowers.pushPrefEnv({
|
||||
"set": [
|
||||
["dom.w3c_pointer_events.enabled", true]
|
||||
]
|
||||
}, executeTest);
|
||||
}
|
||||
|
||||
function executeTest()
|
||||
{
|
||||
logger("executeTest");
|
||||
setEventHandlers();
|
||||
document.body.offsetLeft;
|
||||
var rect = target.getBoundingClientRect();
|
||||
synthesizePointer(target, rect.width/2, rect.height/2, {type: "pointermove"});
|
||||
synthesizePointer(target, rect.width/2, rect.height/2, {type: "pointerdown"});
|
||||
synthesizePointer(target, rect.width/3, rect.height/3, {type: "pointermove"});
|
||||
synthesizePointer(middler, rect.width/2, rect.height/2, {type: "pointermove"});
|
||||
synthesizePointer(target, rect.width/2, rect.height/2, {type: "pointermove"});
|
||||
synthesizePointer(middler, rect.width/2, rect.height/2, {type: "pointermove"});
|
||||
synthesizePointer(target, rect.width/2, rect.height/2, {type: "pointermove"});
|
||||
synthesizePointer(target, rect.width/2, rect.height/2, {type: "pointerup"});
|
||||
finishTest();
|
||||
}
|
||||
|
||||
function finishTest() {
|
||||
setTimeout(function() {
|
||||
is(test_ListenerGotCapture, 1, "Listener should receive gotpointercapture event");
|
||||
is(test_ListenerUnwanted, 0, "Listener should not receive any unwanted events");
|
||||
is(test_ListenerLostCapture, 1, "Listener should receive lostpointercapture event");
|
||||
is(test_ListenerAfterCapture, 0, "Listener should not receive any events after release pointer capture");
|
||||
is(test_MiddlerGotCapture, 1, "Middler should receive gotpointercapture event");
|
||||
is(test_MiddlerOver, 1, "Middler should receive pointerover event");
|
||||
is(test_MiddlerLeave, 1, "Middler should receive pointerleave event");
|
||||
is(test_MiddlerUp, 0, "Middler should not receive pointerup event");
|
||||
is(test_MiddlerLostCapture, 1, "Middler should receive lostpointercapture event");
|
||||
is(test_TargetDown, 1, "Target should receive pointerdown event");
|
||||
is(test_TargetUnwanted, 0, "Target should not receive any event while pointer capture is active");
|
||||
is(test_TargetUp, 1, "Target should receive pointerup event");
|
||||
logger("finishTest");
|
||||
parent.finishTest();
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
function logger(message) {
|
||||
console.log(message);
|
||||
var log = document.getElementById('log');
|
||||
log.innerHTML = message + "<br>" + log.innerHTML;
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body onload="prepareTest()">
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=976963">Mozilla Bug 976963</a>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
</div>
|
||||
<div id="listener">div id=listener</div>
|
||||
<div id="middler">div id=middler</div>
|
||||
<div id="target">div id=target</div>
|
||||
<pre id="log">
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
@ -209,6 +209,8 @@ skip-if = (buildapp == 'b2g' && toolkit != 'gonk') #Bug 931116, b2g desktop spec
|
||||
support-files = bug851445_helper.html
|
||||
[test_bug970964.html]
|
||||
support-files = bug970964_inner.html
|
||||
[test_bug976963.html]
|
||||
support-files = bug976963_inner.html
|
||||
[test_emulateMedium.html]
|
||||
[test_getClientRects_emptytext.html]
|
||||
[test_bug858459.html]
|
||||
|
33
layout/base/tests/test_bug976963.html
Normal file
33
layout/base/tests/test_bug976963.html
Normal file
@ -0,0 +1,33 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=976963
|
||||
-->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="author" content="Maksim Lebedev" />
|
||||
<title>Test for Bug 976963</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
<script type="text/javascript">
|
||||
function prepareTest() {
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
SpecialPowers.pushPrefEnv({
|
||||
"set": [
|
||||
["dom.w3c_pointer_events.enabled", true]
|
||||
]
|
||||
}, startTest);
|
||||
}
|
||||
function startTest() {
|
||||
var iframe = document.getElementById("testFrame");
|
||||
iframe.src = "bug976963_inner.html";
|
||||
}
|
||||
function finishTest() {
|
||||
SimpleTest.finish();
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body onload="prepareTest()">
|
||||
<iframe id="testFrame" height="700" width="700"></iframe>
|
||||
</body>
|
||||
</html>
|
@ -3034,7 +3034,10 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
|
||||
// on the childs available space.
|
||||
// XXX building a complete nsHTMLReflowState just to get the margin-top
|
||||
// seems like a waste. And we do this for almost every block!
|
||||
nsSize availSpace(aState.ContentISize(), NS_UNCONSTRAINEDSIZE);
|
||||
nsSize availSpace =
|
||||
LogicalSize(aState.mReflowState.GetWritingMode(),
|
||||
aState.ContentISize(), NS_UNCONSTRAINEDSIZE).
|
||||
GetPhysicalSize(aState.mReflowState.GetWritingMode());
|
||||
nsHTMLReflowState reflowState(aState.mPresContext, aState.mReflowState,
|
||||
frame, availSpace);
|
||||
|
||||
@ -5752,7 +5755,7 @@ nsBlockFrame::AdjustFloatAvailableSpace(nsBlockReflowState& aState,
|
||||
availISize, availBSize);
|
||||
|
||||
// for now return a physical rect
|
||||
return availSpace.GetPhysicalRect(wm, aState.ContentISize());
|
||||
return availSpace.GetPhysicalRect(wm, aState.mContainerWidth);
|
||||
}
|
||||
|
||||
nscoord
|
||||
|
@ -329,9 +329,9 @@ nsHTMLReflowState::Init(nsPresContext* aPresContext,
|
||||
const nsMargin* aBorder,
|
||||
const nsMargin* aPadding)
|
||||
{
|
||||
NS_WARN_IF_FALSE(AvailableWidth() != NS_UNCONSTRAINEDSIZE,
|
||||
"have unconstrained width; this should only result from "
|
||||
"very large sizes, not attempts at intrinsic width "
|
||||
NS_WARN_IF_FALSE(AvailableISize() != NS_UNCONSTRAINEDSIZE,
|
||||
"have unconstrained inline-size; this should only result from "
|
||||
"very large sizes, not attempts at intrinsic inline-size "
|
||||
"calculation");
|
||||
|
||||
mStylePosition = frame->StylePosition();
|
||||
@ -405,9 +405,9 @@ nsHTMLReflowState::Init(nsPresContext* aPresContext,
|
||||
NS_WARN_IF_FALSE((mFrameType == NS_CSS_FRAME_TYPE_INLINE &&
|
||||
!frame->IsFrameOfType(nsIFrame::eReplaced)) ||
|
||||
type == nsGkAtoms::textFrame ||
|
||||
ComputedWidth() != NS_UNCONSTRAINEDSIZE,
|
||||
"have unconstrained width; this should only result from "
|
||||
"very large sizes, not attempts at intrinsic width "
|
||||
ComputedISize() != NS_UNCONSTRAINEDSIZE,
|
||||
"have unconstrained inline-size; this should only result from "
|
||||
"very large sizes, not attempts at intrinsic inline-size "
|
||||
"calculation");
|
||||
}
|
||||
|
||||
|
@ -722,15 +722,15 @@ nsInlineFrame::ReflowFrames(nsPresContext* aPresContext,
|
||||
// and bottom border and padding. The height of children do not
|
||||
// affect our height.
|
||||
aMetrics.SetBlockStartAscent(fm->MaxAscent());
|
||||
aMetrics.Height() = fm->MaxHeight();
|
||||
aMetrics.BSize(lineWM) = fm->MaxHeight();
|
||||
} else {
|
||||
NS_WARNING("Cannot get font metrics - defaulting sizes to 0");
|
||||
aMetrics.SetBlockStartAscent(aMetrics.Height() = 0);
|
||||
}
|
||||
aMetrics.SetBlockStartAscent(aMetrics.BlockStartAscent() +
|
||||
framePadding.BStart(frameWM));
|
||||
aMetrics.Height() += aReflowState.ComputedPhysicalBorderPadding().top +
|
||||
aReflowState.ComputedPhysicalBorderPadding().bottom;
|
||||
aMetrics.BSize(lineWM) +=
|
||||
aReflowState.ComputedLogicalBorderPadding().BStartEnd(frameWM);
|
||||
|
||||
// For now our overflow area is zero. The real value will be
|
||||
// computed in |nsLineLayout::RelativePositionFrames|.
|
||||
|
@ -773,11 +773,6 @@ nsLineLayout::ReflowFrame(nsIFrame* aFrame,
|
||||
nsIAtom* frameType = aFrame->GetType();
|
||||
bool isText = frameType == nsGkAtoms::textFrame;
|
||||
|
||||
// Compute the available size for the frame. This available width
|
||||
// includes room for the side margins.
|
||||
// For now, set the available height to unconstrained always.
|
||||
nsSize availSize(mBlockReflowState->ComputedWidth(), NS_UNCONSTRAINEDSIZE);
|
||||
|
||||
// Inline-ish and text-ish things don't compute their width;
|
||||
// everything else does. We need to give them an available width that
|
||||
// reflects the space left on the line.
|
||||
@ -790,6 +785,13 @@ nsLineLayout::ReflowFrame(nsIFrame* aFrame,
|
||||
// Setup reflow state for reflowing the frame
|
||||
Maybe<nsHTMLReflowState> reflowStateHolder;
|
||||
if (!isText) {
|
||||
// Compute the available size for the frame. This available width
|
||||
// includes room for the side margins.
|
||||
// For now, set the available block-size to unconstrained always.
|
||||
nsSize availSize =
|
||||
LogicalSize(mBlockReflowState->GetWritingMode(),
|
||||
mBlockReflowState->ComputedISize(), NS_UNCONSTRAINEDSIZE).
|
||||
GetPhysicalSize(mBlockReflowState->GetWritingMode());
|
||||
reflowStateHolder.construct(mPresContext, *psd->mReflowState,
|
||||
aFrame, availSize);
|
||||
nsHTMLReflowState& reflowState = reflowStateHolder.ref();
|
||||
|
@ -24,9 +24,7 @@ nsSVGPaintServerFrame::SetupPaintServer(gfxContext *aContext,
|
||||
if (!pattern)
|
||||
return false;
|
||||
|
||||
if (!aContext->IsCairo()) {
|
||||
pattern->CacheColorStops(aContext->GetDrawTarget());
|
||||
}
|
||||
pattern->CacheColorStops(aContext->GetDrawTarget());
|
||||
|
||||
aContext->SetPattern(pattern);
|
||||
return true;
|
||||
|
@ -540,7 +540,7 @@ MozMillElement.prototype.rightClick = function (aOffsetX, aOffsetY, aExpectedEve
|
||||
* @param {Touch[]} [aEvent.touches]
|
||||
* A TouchList of all the Touch objects representing all current points
|
||||
* of contact with the surface, regardless of target or changed status
|
||||
* @param {Number} [aEvent.type=*|touchstart|touchend|touchmove|touchenter|touchleave|touchcancel]
|
||||
* @param {Number} [aEvent.type=*|touchstart|touchend|touchmove|touchcancel]
|
||||
* The type of touch event that occurred
|
||||
* @param {Element} [aEvent.target]
|
||||
* The target of the touches associated with this event. This target
|
||||
|
@ -307,14 +307,14 @@ function synthesizePointerAtPoint(left, top, aEvent, aWindow)
|
||||
var synthesized = ("isSynthesized" in aEvent) ? aEvent.isSynthesized : true;
|
||||
|
||||
if (("type" in aEvent) && aEvent.type) {
|
||||
defaultPrevented = utils.sendPointerEvent(aEvent.type, left, top, button,
|
||||
clickCount, modifiers, false,
|
||||
pressure, inputSource,
|
||||
synthesized);
|
||||
defaultPrevented = utils.sendPointerEventToWindow(aEvent.type, left, top, button,
|
||||
clickCount, modifiers, false,
|
||||
pressure, inputSource,
|
||||
synthesized);
|
||||
}
|
||||
else {
|
||||
utils.sendPointerEvent("pointerdown", left, top, button, clickCount, modifiers, false, pressure, inputSource);
|
||||
utils.sendPointerEvent("pointerup", left, top, button, clickCount, modifiers, false, pressure, inputSource);
|
||||
utils.sendPointerEventToWindow("pointerdown", left, top, button, clickCount, modifiers, false, pressure, inputSource);
|
||||
utils.sendPointerEventToWindow("pointerup", left, top, button, clickCount, modifiers, false, pressure, inputSource);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -200,6 +200,10 @@ ADBAndroid
|
||||
``````````
|
||||
.. autoclass:: ADBAndroid
|
||||
|
||||
Informational methods
|
||||
+++++++++++++++++++++
|
||||
.. automethod:: ADBAndroid.get_battery_percentage(self, timeout=None)
|
||||
|
||||
System control methods
|
||||
++++++++++++++++++++++
|
||||
.. automethod:: ADBAndroid.is_device_ready(self, timeout=None)
|
||||
|
@ -224,10 +224,8 @@ class ADBCommand(object):
|
||||
set in the ADBCommand constructor is used.
|
||||
:returns: string - content of stdout.
|
||||
|
||||
:raises: * ADBTimeoutError - raised if the command takes longer than
|
||||
timeout seconds.
|
||||
* ADBError - raised if the command exits with a
|
||||
non-zero exit code.
|
||||
:raises: * ADBTimeoutError
|
||||
* ADBError
|
||||
|
||||
"""
|
||||
adb_process = None
|
||||
@ -335,10 +333,8 @@ class ADBHost(ADBCommand):
|
||||
set in the ADBHost constructor is used.
|
||||
:returns: string - content of stdout.
|
||||
|
||||
:raises: * ADBTimeoutError - raised if the command takes longer than
|
||||
timeout seconds.
|
||||
* ADBError - raised if the command exits with a
|
||||
non-zero exit code.
|
||||
:raises: * ADBTimeoutError
|
||||
* ADBError
|
||||
|
||||
"""
|
||||
return ADBCommand.command_output(self, cmds, timeout=timeout)
|
||||
@ -351,10 +347,8 @@ class ADBHost(ADBCommand):
|
||||
throwing an ADBTimeoutError. This timeout is per adb call. The
|
||||
total time spent may exceed this value. If it is not
|
||||
specified, the value set in the ADBHost constructor is used.
|
||||
:raises: * ADBTimeoutError - raised if the command takes longer than
|
||||
timeout seconds.
|
||||
* ADBError - raised if the command exits with a
|
||||
non-zero exit code.
|
||||
:raises: * ADBTimeoutError
|
||||
* ADBError
|
||||
|
||||
"""
|
||||
self.command_output(["start-server"], timeout=timeout)
|
||||
@ -367,10 +361,8 @@ class ADBHost(ADBCommand):
|
||||
throwing an ADBTimeoutError. This timeout is per adb call. The
|
||||
total time spent may exceed this value. If it is not
|
||||
specified, the value set in the ADBHost constructor is used.
|
||||
:raises: * ADBTimeoutError - raised if the command takes longer than
|
||||
timeout seconds.
|
||||
* ADBError - raised if the command exits with a
|
||||
non-zero exit code.
|
||||
:raises: * ADBTimeoutError
|
||||
* ADBError
|
||||
|
||||
"""
|
||||
self.command_output(["kill-server"], timeout=timeout)
|
||||
@ -384,10 +376,8 @@ class ADBHost(ADBCommand):
|
||||
total time spent may exceed this value. If it is not
|
||||
specified, the value set in the ADBHost constructor is used.
|
||||
:returns: an object contain
|
||||
:raises: * ADBTimeoutError - raised if the command takes longer than
|
||||
timeout seconds.
|
||||
* ADBError - raised if the command exits with a
|
||||
non-zero exit code.
|
||||
:raises: * ADBTimeoutError
|
||||
* ADBError
|
||||
|
||||
The output of adb devices -l ::
|
||||
|
||||
@ -592,8 +582,7 @@ class ADBDevice(ADBCommand):
|
||||
:param root: optional boolean specifying if the command should
|
||||
be executed as root.
|
||||
:raises: * ADBTimeoutError
|
||||
* ADBRootError - raised if root is requested but the
|
||||
device is not rooted.
|
||||
* ADBRootError
|
||||
* ADBError
|
||||
|
||||
"""
|
||||
@ -690,10 +679,8 @@ class ADBDevice(ADBCommand):
|
||||
set in the ADBDevice constructor is used.
|
||||
:returns: string - content of stdout.
|
||||
|
||||
:raises: * ADBTimeoutError - raised if the command takes longer than
|
||||
timeout seconds.
|
||||
* ADBError - raised if the command exits with a
|
||||
non-zero exit code.
|
||||
:raises: * ADBTimeoutError
|
||||
* ADBError
|
||||
|
||||
"""
|
||||
return ADBCommand.command_output(self, cmds,
|
||||
@ -718,8 +705,7 @@ class ADBDevice(ADBCommand):
|
||||
:param root: optional boolean specifying if the command should
|
||||
be executed as root.
|
||||
:returns: :class:`mozdevice.ADBProcess`
|
||||
:raises: ADBRootError - raised if root is requested but the
|
||||
device is not rooted.
|
||||
:raises: ADBRootError
|
||||
|
||||
shell() provides a low level interface for executing commands
|
||||
on the device via adb shell.
|
||||
@ -826,10 +812,8 @@ class ADBDevice(ADBCommand):
|
||||
be executed as root.
|
||||
:returns: boolean
|
||||
|
||||
:raises: * ADBTimeoutError - raised if the command takes longer than
|
||||
timeout seconds.
|
||||
* ADBRootError - raised if root is requested but the
|
||||
device is not rooted.
|
||||
:raises: * ADBTimeoutError
|
||||
* ADBRootError
|
||||
|
||||
"""
|
||||
adb_process = None
|
||||
@ -861,12 +845,9 @@ class ADBDevice(ADBCommand):
|
||||
optional boolean specifying if the command
|
||||
should be executed as root.
|
||||
:returns: string - content of stdout.
|
||||
:raises: * ADBTimeoutError - raised if the command takes longer than
|
||||
timeout seconds.
|
||||
* ADBRootError - raised if root is requested but the
|
||||
device is not rooted.
|
||||
* ADBError - raised if the command exits with a
|
||||
non-zero exit code.
|
||||
:raises: * ADBTimeoutError
|
||||
* ADBRootError
|
||||
* ADBError
|
||||
|
||||
"""
|
||||
adb_process = None
|
||||
@ -907,10 +888,8 @@ class ADBDevice(ADBCommand):
|
||||
adb call. The total time spent may exceed this
|
||||
value. If it is not specified, the value set
|
||||
in the ADBDevice constructor is used.
|
||||
:raises: * ADBTimeoutError - raised if adb logcat takes longer than
|
||||
timeout seconds.
|
||||
* ADBError - raised if adb logcat exits with a non-zero
|
||||
exit code.
|
||||
:raises: * ADBTimeoutError
|
||||
* ADBError
|
||||
|
||||
"""
|
||||
self.command_output(["logcat", "-c"], timeout=timeout)
|
||||
@ -940,10 +919,8 @@ class ADBDevice(ADBCommand):
|
||||
may exceed this value. If it is not specified, the value
|
||||
set in the ADBDevice constructor is used.
|
||||
:returns: list of lines logcat output.
|
||||
:raises: * ADBTimeoutError - raised if adb logcat takes longer than
|
||||
timeout seconds.
|
||||
* ADBError - raised if adb logcat exits with a non-zero
|
||||
exit code.
|
||||
:raises: * ADBTimeoutError
|
||||
* ADBError
|
||||
|
||||
"""
|
||||
cmds = ["logcat", "-v", format, "-d"] + filter_specs
|
||||
@ -965,10 +942,8 @@ class ADBDevice(ADBCommand):
|
||||
may exceed this value. If it is not specified, the value
|
||||
set in the ADBDevice constructor is used.
|
||||
:returns: string value of property.
|
||||
:raises: * ADBTimeoutError - raised if the command takes longer than
|
||||
timeout seconds.
|
||||
* ADBError - raised if adb shell getprop exits with a
|
||||
non-zero exit code.
|
||||
:raises: * ADBTimeoutError
|
||||
* ADBError
|
||||
|
||||
"""
|
||||
output = self.shell_output('getprop %s' % prop, timeout=timeout)
|
||||
@ -984,10 +959,8 @@ class ADBDevice(ADBCommand):
|
||||
may exceed this value. If it is not specified, the value
|
||||
set in the ADBDevice constructor is used.
|
||||
:returns: string value of adb get-state.
|
||||
:raises: * ADBTimeoutError - raised if adb get-state takes longer
|
||||
than timeout seconds.
|
||||
* ADBError - raised if adb get-state exits with a
|
||||
non-zero exit code.
|
||||
:raises: * ADBTimeoutError
|
||||
* ADBError
|
||||
|
||||
"""
|
||||
output = self.command_output(["get-state"], timeout=timeout).strip()
|
||||
@ -1011,12 +984,9 @@ class ADBDevice(ADBCommand):
|
||||
set in the ADBDevice constructor is used.
|
||||
:param root: optional boolean specifying if the command should
|
||||
be executed as root.
|
||||
:raises: * ADBTimeoutError - raised if any of the adb commands takes
|
||||
longer than timeout seconds.
|
||||
* ADBRootError - raised if root is requested but the
|
||||
device is not rooted.
|
||||
* ADBError - raised if any of the adb commands raises
|
||||
an uncaught ADBError.
|
||||
:raises: * ADBTimeoutError
|
||||
* ADBRootError
|
||||
* ADBError
|
||||
|
||||
"""
|
||||
path = posixpath.normpath(path.strip())
|
||||
@ -1061,10 +1031,8 @@ class ADBDevice(ADBCommand):
|
||||
:param root: optional boolean specifying if the command should be
|
||||
executed as root.
|
||||
:returns: boolean - True if path exists.
|
||||
:raises: * ADBTimeoutError - raised if the command takes longer than
|
||||
timeout seconds.
|
||||
* ADBRootError - raised if root is requested but the
|
||||
device is not rooted.
|
||||
:raises: * ADBTimeoutError
|
||||
* ADBRootError
|
||||
|
||||
"""
|
||||
path = posixpath.normpath(path)
|
||||
@ -1084,10 +1052,8 @@ class ADBDevice(ADBCommand):
|
||||
be executed as root.
|
||||
:returns: boolean - True if path exists on the device and is a
|
||||
directory.
|
||||
:raises: * ADBTimeoutError - raised if the command takes longer than
|
||||
timeout seconds.
|
||||
* ADBRootError - raised if root is requested but the
|
||||
device is not rooted.
|
||||
:raises: * ADBTimeoutError
|
||||
* ADBRootError
|
||||
|
||||
"""
|
||||
path = posixpath.normpath(path)
|
||||
@ -1107,10 +1073,8 @@ class ADBDevice(ADBCommand):
|
||||
be executed as root.
|
||||
:returns: boolean - True if path exists on the device and is a
|
||||
file.
|
||||
:raises: * ADBTimeoutError - raised if the command takes longer than
|
||||
timeout seconds.
|
||||
* ADBRootError - raised if root is requested but the
|
||||
device is not rooted.
|
||||
:raises: * ADBTimeoutError
|
||||
* ADBRootError
|
||||
|
||||
"""
|
||||
path = posixpath.normpath(path)
|
||||
@ -1132,10 +1096,8 @@ class ADBDevice(ADBCommand):
|
||||
:param root: optional boolean specifying if the command should
|
||||
be executed as root.
|
||||
:returns: list of files/directories contained in the directory.
|
||||
:raises: * ADBTimeoutError - raised if the command takes longer than
|
||||
timeout seconds.
|
||||
* ADBRootError - raised if root is requested but the
|
||||
device is not rooted.
|
||||
:raises: * ADBTimeoutError
|
||||
* ADBRootError
|
||||
|
||||
"""
|
||||
path = posixpath.normpath(path.strip())
|
||||
@ -1168,13 +1130,9 @@ class ADBDevice(ADBCommand):
|
||||
set in the ADBDevice constructor is used.
|
||||
:param root: optional boolean specifying if the command should
|
||||
be executed as root.
|
||||
:raises: * ADBTimeoutError - raised if any adb command takes longer
|
||||
than timeout seconds.
|
||||
* ADBRootError - raised if root is requested but the
|
||||
device is not rooted.
|
||||
* ADBError - raised if adb shell mkdir exits with a
|
||||
non-zero exit code or if the directory is not
|
||||
created.
|
||||
:raises: * ADBTimeoutError
|
||||
* ADBRootError
|
||||
* ADBError
|
||||
|
||||
"""
|
||||
path = posixpath.normpath(path)
|
||||
@ -1215,10 +1173,8 @@ class ADBDevice(ADBCommand):
|
||||
This timeout is per adb call. The total time spent
|
||||
may exceed this value. If it is not specified, the value
|
||||
set in the ADBDevice constructor is used.
|
||||
:raises: * ADBTimeoutError - raised if the adb push takes longer than
|
||||
timeout seconds.
|
||||
* ADBError - raised if the adb push exits with a
|
||||
non-zero exit code.
|
||||
:raises: * ADBTimeoutError
|
||||
* ADBError
|
||||
|
||||
"""
|
||||
self.command_output(["push", os.path.realpath(local), remote],
|
||||
@ -1241,14 +1197,9 @@ class ADBDevice(ADBCommand):
|
||||
set in the ADBDevice constructor is used.
|
||||
:param root: optional boolean specifying if the command should
|
||||
be executed as root.
|
||||
:raises: * ADBTimeoutError - raised if any of the adb commands takes
|
||||
longer than timeout seconds.
|
||||
* ADBRootError - raised if root is requested but the
|
||||
device is not rooted.
|
||||
* ADBError - raised if the adb shell rm command exits
|
||||
with a non-zero exit code or if the file is not
|
||||
removed, or if force was not specified and the
|
||||
file did not exist.
|
||||
:raises: * ADBTimeoutError
|
||||
* ADBRootError
|
||||
* ADBError
|
||||
|
||||
"""
|
||||
cmd = "rm"
|
||||
@ -1274,13 +1225,9 @@ class ADBDevice(ADBCommand):
|
||||
set in the ADBDevice constructor is used.
|
||||
:param root: optional boolean specifying if the command should
|
||||
be executed as root.
|
||||
:raises: * ADBTimeoutError - raised if the command takes longer than
|
||||
timeout seconds.
|
||||
* ADBRootError - raised if root is requested but the
|
||||
device is not rooted.
|
||||
* ADBError - raised if the adb shell rmdir command
|
||||
exits with a non-zero exit code or if the
|
||||
directory was not removed..
|
||||
:raises: * ADBTimeoutError
|
||||
* ADBRootError
|
||||
* ADBError
|
||||
|
||||
"""
|
||||
self.shell_output("rmdir %s" % path, timeout=timeout, root=root)
|
||||
@ -1301,11 +1248,8 @@ class ADBDevice(ADBCommand):
|
||||
the value set in the ADBDevice constructor is used.
|
||||
:returns: list of (pid, name, user) tuples for running processes
|
||||
on the device.
|
||||
:raises: * ADBTimeoutError - raised if the adb shell ps command
|
||||
takes longer than timeout seconds.
|
||||
* ADBError - raised if the adb shell ps command exits
|
||||
with a non-zero exit code or if the ps output
|
||||
is not in the expected format.
|
||||
:raises: * ADBTimeoutError
|
||||
* ADBError
|
||||
|
||||
"""
|
||||
adb_process = None
|
||||
@ -1365,13 +1309,9 @@ class ADBDevice(ADBCommand):
|
||||
set in the ADBDevice constructor is used.
|
||||
:param root: optional boolean specifying if the command should
|
||||
be executed as root.
|
||||
:raises: * ADBTimeoutError - raised if adb shell kill takes longer
|
||||
than timeout seconds.
|
||||
* ADBRootError - raised if root is requested but the
|
||||
device is not rooted.
|
||||
* ADBError - raised if adb shell kill exits with a
|
||||
non-zero exit code or not all of the processes have
|
||||
been killed.
|
||||
:raises: * ADBTimeoutError
|
||||
* ADBRootError
|
||||
* ADBError
|
||||
|
||||
"""
|
||||
pid_list = [str(pid) for pid in pids]
|
||||
@ -1417,12 +1357,9 @@ class ADBDevice(ADBCommand):
|
||||
:param root: optional boolean specifying if the command should
|
||||
be executed as root.
|
||||
|
||||
:raises: * ADBTimeoutError - raised if any of the adb commands takes
|
||||
longer than timeout seconds.
|
||||
* ADBRootError - raised if root is requested but the
|
||||
device is not rooted.
|
||||
* ADBError - raised if any of the adb commands raises
|
||||
ADBError or if the process is not killed.
|
||||
:raises: * ADBTimeoutError
|
||||
* ADBRootError
|
||||
* ADBError
|
||||
|
||||
"""
|
||||
procs = self.get_process_list(timeout=timeout)
|
||||
@ -1454,11 +1391,8 @@ class ADBDevice(ADBCommand):
|
||||
set in the ADBDevice constructor is used.
|
||||
:returns: boolean - True if process exists.
|
||||
|
||||
:raises: * ADBTimeoutError - raised if any of the adb commands takes
|
||||
longer than timeout seconds.
|
||||
* ADBError - raised if the adb shell ps command exits
|
||||
with a non-zero exit code or if the ps output is
|
||||
not in the expected format.
|
||||
:raises: * ADBTimeoutError
|
||||
* ADBError
|
||||
|
||||
"""
|
||||
if not isinstance(process_name, basestring):
|
||||
|
@ -3,6 +3,7 @@
|
||||
# You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
import os
|
||||
import re
|
||||
import time
|
||||
|
||||
from adb import ADBDevice, ADBError
|
||||
@ -12,6 +13,42 @@ from distutils.version import StrictVersion
|
||||
class ADBAndroidMixin(object):
|
||||
"""Mixin to extend ADB with Android-specific functionality"""
|
||||
|
||||
# Informational methods
|
||||
|
||||
def get_battery_percentage(self, timeout=None):
|
||||
"""Returns the battery charge as a percentage.
|
||||
|
||||
:param timeout: optional integer specifying the maximum time in
|
||||
seconds for any spawned adb process to complete before
|
||||
throwing an ADBTimeoutError.
|
||||
This timeout is per adb call. The total time spent
|
||||
may exceed this value. If it is not specified, the value
|
||||
set in the ADBDevice constructor is used.
|
||||
:returns: battery charge as a percentage.
|
||||
:raises: * ADBTimeoutError
|
||||
* ADBError
|
||||
|
||||
"""
|
||||
level = None
|
||||
scale = None
|
||||
percentage = 0
|
||||
cmd = "dumpsys battery"
|
||||
re_parameter = re.compile(r'\s+(\w+):\s+(\d+)')
|
||||
lines = self.shell_output(cmd, timeout=timeout).split('\r')
|
||||
for line in lines:
|
||||
match = re_parameter.match(line)
|
||||
if match:
|
||||
parameter = match.group(1)
|
||||
value = match.group(2)
|
||||
if parameter == 'level':
|
||||
level = float(value)
|
||||
elif parameter == 'scale':
|
||||
scale = float(value)
|
||||
if parameter is not None and scale is not None:
|
||||
percentage = 100.0*level/scale
|
||||
break
|
||||
return percentage
|
||||
|
||||
# System control methods
|
||||
|
||||
def is_device_ready(self, timeout=None):
|
||||
@ -26,9 +63,8 @@ class ADBAndroidMixin(object):
|
||||
This timeout is per adb call. The total time spent
|
||||
may exceed this value. If it is not specified, the value
|
||||
set in the ADB constructor is used.
|
||||
:raises: * ADBTimeoutError - raised if the command takes longer than
|
||||
timeout seconds.
|
||||
* ADBError - raised if the wait-for-device command fails.
|
||||
:raises: * ADBTimeoutError
|
||||
* ADBError
|
||||
|
||||
"""
|
||||
self.command_output(["wait-for-device"], timeout=timeout)
|
||||
@ -75,10 +111,8 @@ class ADBAndroidMixin(object):
|
||||
This timeout is per adb call. The total time spent
|
||||
may exceed this value. If it is not specified, the value
|
||||
set in the ADB constructor is used.
|
||||
:raises: * ADBTimeoutError - raised if the command takes longer than
|
||||
timeout seconds.
|
||||
* ADBError - raised if the command exits with a
|
||||
non-zero exit code.
|
||||
:raises: * ADBTimeoutError
|
||||
* ADBError
|
||||
|
||||
"""
|
||||
try:
|
||||
@ -102,10 +136,8 @@ class ADBAndroidMixin(object):
|
||||
This timeout is per adb call. The total time spent
|
||||
may exceed this value. If it is not specified, the value
|
||||
set in the ADB constructor is used.
|
||||
:raises: * ADBTimeoutError - raised if the command takes longer than
|
||||
timeout seconds.
|
||||
* ADBError - raised if the command exits with a
|
||||
non-zero exit code.
|
||||
:raises: * ADBTimeoutError
|
||||
* ADBError
|
||||
|
||||
reboot() reboots the device, issues an adb wait-for-device in order to
|
||||
wait for the device to complete rebooting, then calls is_device_ready()
|
||||
@ -129,10 +161,8 @@ class ADBAndroidMixin(object):
|
||||
This timeout is per adb call. The total time spent
|
||||
may exceed this value. If it is not specified, the value
|
||||
set in the ADB constructor is used.
|
||||
:raises: * ADBTimeoutError - raised if the command takes longer than
|
||||
timeout seconds.
|
||||
* ADBError - raised if the command exits with a
|
||||
non-zero exit code.
|
||||
:raises: * ADBTimeoutError
|
||||
* ADBError
|
||||
|
||||
"""
|
||||
data = self.command_output(["install", apk_path], timeout=timeout)
|
||||
@ -151,10 +181,8 @@ class ADBAndroidMixin(object):
|
||||
This timeout is per adb call. The total time spent
|
||||
may exceed this value. If it is not specified, the value
|
||||
set in the ADB constructor is used.
|
||||
:raises: * ADBTimeoutError - raised if the command takes longer than
|
||||
timeout seconds.
|
||||
* ADBError - raised if the command exits with a
|
||||
non-zero exit code.
|
||||
:raises: * ADBTimeoutError
|
||||
* ADBError
|
||||
|
||||
"""
|
||||
pm_error_string = 'Error: Could not access the Package Manager'
|
||||
@ -185,10 +213,8 @@ class ADBAndroidMixin(object):
|
||||
This timeout is per adb call. The total time spent
|
||||
may exceed this value. If it is not specified, the value
|
||||
set in the ADB constructor is used.
|
||||
:raises: * ADBTimeoutError - raised if the command takes longer than
|
||||
timeout seconds.
|
||||
* ADBError - raised if the command exits with a
|
||||
non-zero exit code.
|
||||
:raises: * ADBTimeoutError
|
||||
* ADBError
|
||||
|
||||
"""
|
||||
# If fail_if_running is True, we throw an exception here. Only one
|
||||
@ -244,10 +270,8 @@ class ADBAndroidMixin(object):
|
||||
This timeout is per adb call. The total time spent
|
||||
may exceed this value. If it is not specified, the value
|
||||
set in the ADB constructor is used.
|
||||
:raises: * ADBTimeoutError - raised if the command takes longer than
|
||||
timeout seconds.
|
||||
* ADBError - raised if the command exits with a
|
||||
non-zero exit code.
|
||||
:raises: * ADBTimeoutError
|
||||
* ADBError
|
||||
|
||||
"""
|
||||
extras = {}
|
||||
@ -283,10 +307,8 @@ class ADBAndroidMixin(object):
|
||||
This timeout is per adb call. The total time spent
|
||||
may exceed this value. If it is not specified, the value
|
||||
set in the ADB constructor is used.
|
||||
:raises: * ADBTimeoutError - raised if the command takes longer than
|
||||
timeout seconds.
|
||||
* ADBError - raised if the command exits with a
|
||||
non-zero exit code.
|
||||
:raises: * ADBTimeoutError
|
||||
* ADBError
|
||||
|
||||
"""
|
||||
version = self.shell_output("getprop ro.build.version.release",
|
||||
@ -324,10 +346,8 @@ class ADBAndroidMixin(object):
|
||||
This timeout is per adb call. The total time spent
|
||||
may exceed this value. If it is not specified, the value
|
||||
set in the ADB constructor is used.
|
||||
:raises: * ADBTimeoutError - raised if the command takes longer than
|
||||
timeout seconds.
|
||||
* ADBError - raised if the command exits with a
|
||||
non-zero exit code.
|
||||
:raises: * ADBTimeoutError
|
||||
* ADBError
|
||||
|
||||
"""
|
||||
if self.is_app_installed(app_name, timeout=timeout):
|
||||
@ -349,10 +369,8 @@ class ADBAndroidMixin(object):
|
||||
This timeout is per adb call. The total time spent
|
||||
may exceed this value. If it is not specified, the value
|
||||
set in the ADB constructor is used.
|
||||
:raises: * ADBTimeoutError - raised if the command takes longer than
|
||||
timeout seconds.
|
||||
* ADBError - raised if the command exits with a
|
||||
non-zero exit code.
|
||||
:raises: * ADBTimeoutError
|
||||
* ADBError
|
||||
|
||||
"""
|
||||
output = self.command_output(["install", "-r", apk_path],
|
||||
|
@ -153,7 +153,8 @@ class StructuredLogger(object):
|
||||
"""
|
||||
self._log_data("test_start", {"test": test})
|
||||
|
||||
def test_status(self, test, subtest, status, expected="PASS", message=None):
|
||||
def test_status(self, test, subtest, status, expected="PASS", message=None,
|
||||
stack=None, extra=None):
|
||||
"""
|
||||
Log a test_status message indicating a subtest result. Tests that
|
||||
do not have subtests are not expected to produce test_status messages.
|
||||
@ -163,6 +164,8 @@ class StructuredLogger(object):
|
||||
:param status: Status string indicating the subtest result
|
||||
:param expected: Status string indicating the expected subtest result.
|
||||
:param message: String containing a message associated with the result.
|
||||
:param stack: a stack trace encountered during test execution.
|
||||
:param extra: suite-specific data associated with the test result.
|
||||
"""
|
||||
if status.upper() not in ["PASS", "FAIL", "TIMEOUT", "NOTRUN", "ASSERT"]:
|
||||
raise ValueError("Unrecognised status %s" % status)
|
||||
@ -173,9 +176,14 @@ class StructuredLogger(object):
|
||||
data["message"] = message
|
||||
if expected != data["status"]:
|
||||
data["expected"] = expected
|
||||
if stack is not None:
|
||||
data["stack"] = stack
|
||||
if extra is not None:
|
||||
data["extra"] = extra
|
||||
self._log_data("test_status", data)
|
||||
|
||||
def test_end(self, test, status, expected="OK", message=None, extra=None):
|
||||
def test_end(self, test, status, expected="OK", message=None, stack=None,
|
||||
extra=None):
|
||||
"""
|
||||
Log a test_end message indicating that a test completed. For tests
|
||||
with subtests this indicates whether the overall test completed without
|
||||
@ -186,6 +194,7 @@ class StructuredLogger(object):
|
||||
:param status: Status string indicating the test result
|
||||
:param expected: Status string indicating the expected test result.
|
||||
:param message: String containing a message associated with the result.
|
||||
:param stack: a stack trace encountered during test execution.
|
||||
:param extra: suite-specific data associated with the test result.
|
||||
"""
|
||||
if status.upper() not in ["PASS", "FAIL", "OK", "ERROR", "TIMEOUT",
|
||||
@ -197,6 +206,8 @@ class StructuredLogger(object):
|
||||
data["message"] = message
|
||||
if expected != data["status"] and status != "SKIP":
|
||||
data["expected"] = expected
|
||||
if stack is not None:
|
||||
data["stack"] = stack
|
||||
if extra is not None:
|
||||
data["extra"] = extra
|
||||
self._log_data("test_end", data)
|
||||
|
@ -86,6 +86,26 @@ class TestStructuredLog(BaseStructuredTest):
|
||||
def test_status_2(self):
|
||||
self.assertRaises(ValueError, self.logger.test_status, "test1", "subtest name", "XXXUNKNOWNXXX")
|
||||
|
||||
def test_status_extra(self):
|
||||
self.logger.test_status("test1", "subtest name", "FAIL", expected="PASS", extra={"data": 42})
|
||||
self.assert_log_equals({"action": "test_status",
|
||||
"subtest": "subtest name",
|
||||
"status": "FAIL",
|
||||
"expected": "PASS",
|
||||
"test": "test1",
|
||||
"extra": {"data":42}
|
||||
})
|
||||
|
||||
def test_status_stack(self):
|
||||
self.logger.test_status("test1", "subtest name", "FAIL", expected="PASS", stack="many\nlines\nof\nstack")
|
||||
self.assert_log_equals({"action": "test_status",
|
||||
"subtest": "subtest name",
|
||||
"status": "FAIL",
|
||||
"expected": "PASS",
|
||||
"test": "test1",
|
||||
"stack": "many\nlines\nof\nstack"
|
||||
})
|
||||
|
||||
def test_end(self):
|
||||
self.logger.test_end("test1", "fail", message="Test message")
|
||||
self.assert_log_equals({"action": "test_end",
|
||||
@ -104,6 +124,14 @@ class TestStructuredLog(BaseStructuredTest):
|
||||
def test_end_2(self):
|
||||
self.assertRaises(ValueError, self.logger.test_end, "test1", "XXXUNKNOWNXXX")
|
||||
|
||||
def test_end_stack(self):
|
||||
self.logger.test_end("test1", "PASS", expected="PASS", stack="many\nlines\nof\nstack")
|
||||
self.assert_log_equals({"action": "test_end",
|
||||
"status": "PASS",
|
||||
"test": "test1",
|
||||
"stack": "many\nlines\nof\nstack"
|
||||
})
|
||||
|
||||
def test_process(self):
|
||||
self.logger.process_output(1234, "test output")
|
||||
self.assert_log_equals({"action": "process_output",
|
||||
|
@ -723,6 +723,9 @@ function todo_check_neq(left, right, stack) {
|
||||
}
|
||||
|
||||
function do_report_result(passed, text, stack, todo) {
|
||||
while (stack.filename.contains("head.js") && stack.caller) {
|
||||
stack = stack.caller;
|
||||
}
|
||||
if (passed) {
|
||||
if (todo) {
|
||||
do_throw_todo(text, stack);
|
||||
|
@ -537,6 +537,19 @@ tail =
|
||||
self.assertEquals(1, self.x.passCount)
|
||||
self.assertEquals(0, self.x.failCount)
|
||||
|
||||
def testLogCorrectFileName(self):
|
||||
"""
|
||||
Make sure a meaningful filename and line number is logged
|
||||
by a passing test.
|
||||
"""
|
||||
self.writeFile("test_add_test_simple.js", ADD_TEST_SIMPLE)
|
||||
self.writeManifest(["test_add_test_simple.js"])
|
||||
|
||||
self.assertTestResult(True, verbose=True)
|
||||
self.assertInLog("true == true")
|
||||
self.assertNotInLog("[do_check_true :")
|
||||
self.assertInLog("[test_simple : 5]")
|
||||
|
||||
def testAddTestFailing(self):
|
||||
"""
|
||||
Ensure add_test() with a failing test is reported.
|
||||
|
@ -10,6 +10,7 @@
|
||||
#define _WIN32_WINNT 0x602
|
||||
#include <objbase.h>
|
||||
#include <shobjidl.h>
|
||||
#pragma comment(lib, "ole32.lib")
|
||||
#endif
|
||||
|
||||
#include <windows.h>
|
||||
|
@ -434,9 +434,7 @@ enum nsEventStructType
|
||||
#define NS_TOUCH_START (NS_TOUCH_EVENT_START)
|
||||
#define NS_TOUCH_MOVE (NS_TOUCH_EVENT_START+1)
|
||||
#define NS_TOUCH_END (NS_TOUCH_EVENT_START+2)
|
||||
#define NS_TOUCH_ENTER (NS_TOUCH_EVENT_START+3)
|
||||
#define NS_TOUCH_LEAVE (NS_TOUCH_EVENT_START+4)
|
||||
#define NS_TOUCH_CANCEL (NS_TOUCH_EVENT_START+5)
|
||||
#define NS_TOUCH_CANCEL (NS_TOUCH_EVENT_START+3)
|
||||
|
||||
// Pointerlock DOM API
|
||||
#define NS_POINTERLOCK_START 5300
|
||||
|
@ -165,8 +165,6 @@ public:
|
||||
MULTITOUCH_START,
|
||||
MULTITOUCH_MOVE,
|
||||
MULTITOUCH_END,
|
||||
MULTITOUCH_ENTER,
|
||||
MULTITOUCH_LEAVE,
|
||||
MULTITOUCH_CANCEL
|
||||
};
|
||||
|
||||
|
@ -47,8 +47,10 @@ public:
|
||||
uint32_t pointerId;
|
||||
uint32_t tiltX;
|
||||
uint32_t tiltY;
|
||||
bool retargetedByPointerCapture;
|
||||
|
||||
WidgetPointerHelper() : convertToPointer(true), pointerId(0), tiltX(0), tiltY(0) {}
|
||||
WidgetPointerHelper() : convertToPointer(true), pointerId(0), tiltX(0), tiltY(0),
|
||||
retargetedByPointerCapture(false) {}
|
||||
|
||||
void AssignPointerHelperData(const WidgetPointerHelper& aEvent)
|
||||
{
|
||||
@ -56,6 +58,7 @@ public:
|
||||
pointerId = aEvent.pointerId;
|
||||
tiltX = aEvent.tiltX;
|
||||
tiltY = aEvent.tiltY;
|
||||
retargetedByPointerCapture = aEvent.retargetedByPointerCapture;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -2256,14 +2256,9 @@ nsNativeThemeCocoa::DrawWidgetBackground(nsRenderingContext* aContext,
|
||||
|
||||
case NS_THEME_MENUITEM:
|
||||
case NS_THEME_CHECKMENUITEM: {
|
||||
bool isTransparent;
|
||||
if (thebesCtx->IsCairo()) {
|
||||
isTransparent = thebesCtx->OriginalSurface()->GetContentType() == gfxContentType::COLOR_ALPHA;
|
||||
} else {
|
||||
SurfaceFormat format = thebesCtx->GetDrawTarget()->GetFormat();
|
||||
isTransparent = (format == SurfaceFormat::R8G8B8A8) ||
|
||||
(format == SurfaceFormat::B8G8R8A8);
|
||||
}
|
||||
SurfaceFormat format = thebesCtx->GetDrawTarget()->GetFormat();
|
||||
bool isTransparent = (format == SurfaceFormat::R8G8B8A8) ||
|
||||
(format == SurfaceFormat::B8G8R8A8);
|
||||
if (isTransparent) {
|
||||
// Clear the background to get correct transparency.
|
||||
CGContextClearRect(cgContext, macRect);
|
||||
|
@ -44,12 +44,6 @@ MultiTouchInput::MultiTouchInput(const WidgetTouchEvent& aTouchEvent)
|
||||
case NS_TOUCH_END:
|
||||
mType = MULTITOUCH_END;
|
||||
break;
|
||||
case NS_TOUCH_ENTER:
|
||||
mType = MULTITOUCH_ENTER;
|
||||
break;
|
||||
case NS_TOUCH_LEAVE:
|
||||
mType = MULTITOUCH_LEAVE;
|
||||
break;
|
||||
case NS_TOUCH_CANCEL:
|
||||
mType = MULTITOUCH_CANCEL;
|
||||
break;
|
||||
|
@ -709,6 +709,11 @@ nsTimerEvent::Run()
|
||||
#endif
|
||||
|
||||
mTimer->Fire();
|
||||
// Since nsTimerImpl is not thread-safe, we should release |mTimer|
|
||||
// here in the target thread to avoid race condition. Otherwise,
|
||||
// ~nsTimerEvent() which calls nsTimerImpl::Release() could run in the
|
||||
// timer thread and result in race condition.
|
||||
mTimer = nullptr;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user