Merge mozilla-central and inbound

This commit is contained in:
Ed Morley 2014-07-10 16:29:53 +01:00
commit 7eca339c27
94 changed files with 1615 additions and 2348 deletions

View File

@ -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")

View File

@ -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);

View File

@ -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]

View 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>

View File

@ -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);
}
}

View File

@ -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;
}

View File

@ -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);

View File

@ -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);
};

View File

@ -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();

View File

@ -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,

View File

@ -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;

View File

@ -74,8 +74,6 @@ var events =
["touchstart",
"touchend",
"touchmove",
"touchenter",
"touchleave",
"touchcancel"];
function runEventTest(type) {

View File

@ -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.
*/

View File

@ -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;
};

View File

@ -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;
};

View File

@ -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;

View File

@ -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;
}

View File

@ -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

View File

@ -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

View File

@ -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) {

View File

@ -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;

View File

@ -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();

View File

@ -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
}

View File

@ -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;
};

View File

@ -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

View File

@ -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;

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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());
}

View File

@ -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,

View File

@ -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; }

View File

@ -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;
}

View File

@ -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

View File

@ -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 */

View File

@ -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;

View File

@ -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

View File

@ -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()

View File

@ -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 {

View File

@ -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) {

View File

@ -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)
{

View File

@ -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);

View File

@ -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()
{

View File

@ -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);

View File

@ -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) {

View File

@ -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;
}

View File

@ -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,

View File

@ -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 */

View File

@ -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,

View File

@ -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),

View File

@ -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 # }

View File

@ -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)

View File

@ -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
};

View File

@ -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 }
}

View File

@ -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()
{

View File

@ -98,7 +98,6 @@ namespace jit {
_(JSOP_INITELEM_GETTER) \
_(JSOP_INITELEM_SETTER) \
_(JSOP_INITELEM_INC) \
_(JSOP_SPREAD) \
_(JSOP_MUTATEPROTO) \
_(JSOP_INITPROP) \
_(JSOP_INITPROP_GETTER) \

View File

@ -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) {

View File

@ -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) {

View File

@ -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) {

View File

@ -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) {

View File

@ -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 = &REGS.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)

View File

@ -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);

View File

@ -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.

View File

@ -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:

View File

@ -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;
}

View File

@ -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:

View File

@ -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

View File

@ -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;
}

View File

@ -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.

View File

@ -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;
}

View 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>

View File

@ -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]

View 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>

View File

@ -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

View File

@ -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");
}

View File

@ -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|.

View File

@ -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();

View File

@ -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;

View File

@ -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

View File

@ -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);
}
}

View File

@ -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)

View File

@ -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):

View File

@ -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],

View File

@ -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)

View File

@ -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",

View File

@ -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);

View File

@ -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.

View File

@ -10,6 +10,7 @@
#define _WIN32_WINNT 0x602
#include <objbase.h>
#include <shobjidl.h>
#pragma comment(lib, "ole32.lib")
#endif
#include <windows.h>

View File

@ -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

View File

@ -165,8 +165,6 @@ public:
MULTITOUCH_START,
MULTITOUCH_MOVE,
MULTITOUCH_END,
MULTITOUCH_ENTER,
MULTITOUCH_LEAVE,
MULTITOUCH_CANCEL
};

View File

@ -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;
}
};

View File

@ -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);

View File

@ -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;

View File

@ -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;
}