Merge inbound to mozilla-central r=merge a=merge

This commit is contained in:
Attila Craciun 2017-10-25 12:30:28 +03:00
commit 7bcf901c3b
42 changed files with 344 additions and 115 deletions

View File

@ -24,6 +24,7 @@ using mozilla::wr::ImageKey from "mozilla/webrender/WebRenderTypes.h";
using mozilla::wr::PipelineId from "mozilla/webrender/WebRenderTypes.h";
using mozilla::gfx::MaybeIntSize from "mozilla/gfx/Point.h";
using mozilla::LayoutDeviceRect from "Units.h";
using mozilla::ImageIntRect from "Units.h";
using class mozilla::gfx::Matrix4x4 from "mozilla/gfx/Matrix.h";
using struct mozilla::void_t from "ipc/IPCMessageUtils.h";
@ -96,6 +97,7 @@ struct OpUpdateBlobImage {
ImageDescriptor descriptor;
OffsetRange bytes;
ImageKey key;
ImageIntRect dirtyRect;
};
struct OpDeleteImage {

View File

@ -279,13 +279,14 @@ IpcResourceUpdateQueue::UpdateImageBuffer(ImageKey aKey,
bool
IpcResourceUpdateQueue::UpdateBlobImage(ImageKey aKey,
const ImageDescriptor& aDescriptor,
Range<uint8_t> aBytes)
Range<uint8_t> aBytes,
ImageIntRect aDirtyRect)
{
auto bytes = mWriter.Write(aBytes);
if (!bytes.length()) {
return false;
}
mUpdates.AppendElement(layers::OpUpdateBlobImage(aDescriptor, bytes, aKey));
mUpdates.AppendElement(layers::OpUpdateBlobImage(aDescriptor, bytes, aKey, aDirtyRect));
return true;
}

View File

@ -83,7 +83,8 @@ public:
bool UpdateBlobImage(wr::ImageKey aKey,
const ImageDescriptor& aDescriptor,
Range<uint8_t> aBytes);
Range<uint8_t> aBytes,
ImageIntRect aDirtyRect);
void UpdateExternalImage(ImageKey aKey,
const ImageDescriptor& aDescriptor,

View File

@ -285,7 +285,7 @@ WebRenderBridgeParent::UpdateResources(const nsTArray<OpUpdateResource>& aResour
if (!reader.Read(op.bytes(), bytes)) {
return false;
}
aUpdates.UpdateBlobImage(op.key(), op.descriptor(), bytes);
aUpdates.UpdateBlobImage(op.key(), op.descriptor(), bytes, wr::ToDeviceUintRect(op.dirtyRect()));
break;
}
case OpUpdateResource::TOpAddExternalImage: {

View File

@ -528,12 +528,14 @@ ResourceUpdateQueue::UpdateImageBuffer(ImageKey aKey,
void
ResourceUpdateQueue::UpdateBlobImage(ImageKey aKey,
const ImageDescriptor& aDescriptor,
wr::Vec_u8& aBytes)
wr::Vec_u8& aBytes,
const wr::DeviceUintRect& aDirtyRect)
{
wr_resource_updates_update_blob_image(mUpdates,
aKey,
&aDescriptor,
&aBytes.inner);
&aBytes.inner,
aDirtyRect);
}
void

View File

@ -86,7 +86,8 @@ public:
void UpdateBlobImage(wr::ImageKey aKey,
const ImageDescriptor& aDescriptor,
wr::Vec_u8& aBytes);
wr::Vec_u8& aBytes,
const wr::DeviceUintRect& aDirtyRect);
void UpdateExternalImage(ImageKey aKey,
const ImageDescriptor& aDescriptor,

View File

@ -304,6 +304,16 @@ static inline wr::LayoutRect ToLayoutRect(const gfxRect rect)
return r;
}
static inline wr::DeviceUintRect ToDeviceUintRect(const mozilla::ImageIntRect& rect)
{
wr::DeviceUintRect r;
r.origin.x = rect.x;
r.origin.y = rect.y;
r.size.width = rect.width;
r.size.height = rect.height;
return r;
}
static inline wr::LayoutRect ToLayoutRect(const mozilla::LayoutDeviceIntRect& rect)
{
return ToLayoutRect(IntRectToRect(rect));

View File

@ -794,12 +794,13 @@ pub extern "C" fn wr_resource_updates_update_blob_image(
image_key: WrImageKey,
descriptor: &WrImageDescriptor,
bytes: &mut WrVecU8,
dirty_rect: DeviceUintRect,
) {
resources.update_image(
image_key,
descriptor.into(),
ImageData::new_blob_image(bytes.flush_into_vec()),
None
Some(dirty_rect)
);
}

View File

@ -832,6 +832,40 @@ struct FontInstancePlatformOptions {
};
#endif
// A 2d Point tagged with a unit.
struct TypedPoint2D_u32__DevicePixel {
uint32_t x;
uint32_t y;
bool operator==(const TypedPoint2D_u32__DevicePixel& aOther) const {
return x == aOther.x &&
y == aOther.y;
}
};
struct TypedSize2D_u32__DevicePixel {
uint32_t width;
uint32_t height;
bool operator==(const TypedSize2D_u32__DevicePixel& aOther) const {
return width == aOther.width &&
height == aOther.height;
}
};
// A 2d Rectangle optionally tagged with a unit.
struct TypedRect_u32__DevicePixel {
TypedPoint2D_u32__DevicePixel origin;
TypedSize2D_u32__DevicePixel size;
bool operator==(const TypedRect_u32__DevicePixel& aOther) const {
return origin == aOther.origin &&
size == aOther.size;
}
};
typedef TypedRect_u32__DevicePixel DeviceUintRect;
/* DO NOT MODIFY THIS MANUALLY! This file was generated using cbindgen.
* To generate this file:
* 1. Get the latest cbindgen using `cargo install --force cbindgen`
@ -1374,7 +1408,8 @@ WR_INLINE
void wr_resource_updates_update_blob_image(ResourceUpdates *aResources,
WrImageKey aImageKey,
const WrImageDescriptor *aDescriptor,
WrVecU8 *aBytes)
WrVecU8 *aBytes,
DeviceUintRect aDirtyRect)
WR_FUNC;
WR_INLINE

View File

@ -2884,6 +2884,36 @@ js::str_replace_string_raw(JSContext* cx, HandleString string, HandleString patt
return BuildFlatReplacement(cx, string, repl, match, patternLength);
}
static ArrayObject*
NewFullyAllocatedStringArray(JSContext* cx, HandleObjectGroup group, uint32_t length)
{
ArrayObject* array = NewFullyAllocatedArrayTryUseGroup(cx, group, length);
if (!array)
return nullptr;
// Only string values will be added to this array. Inform TI early about
// the element type, so we can directly initialize all elements using
// NativeObject::initDenseElement() instead of the slightly more expensive
// NativeObject::initDenseElementWithType() method.
// Since this function is never called to create a zero-length array, it's
// always necessary and correct to call AddTypePropertyId here.
MOZ_ASSERT(length > 0);
AddTypePropertyId(cx, array, JSID_VOID, TypeSet::StringType());
return array;
}
static ArrayObject*
SingleElementStringArray(JSContext* cx, HandleObjectGroup group, HandleLinearString str)
{
ArrayObject* array = NewFullyAllocatedStringArray(cx, group, 1);
if (!array)
return nullptr;
array->setDenseInitializedLength(1);
array->initDenseElement(0, StringValue(str));
return array;
}
// ES 2016 draft Mar 25, 2016 21.1.3.17 steps 4, 8, 12-18.
static ArrayObject*
SplitHelper(JSContext* cx, HandleLinearString str, uint32_t limit, HandleLinearString sep,
@ -2903,8 +2933,7 @@ SplitHelper(JSContext* cx, HandleLinearString str, uint32_t limit, HandleLinearS
return NewFullyAllocatedArrayTryUseGroup(cx, group, 0);
// Steps 12.c-e.
RootedValue v(cx, StringValue(str));
return NewCopiedArrayTryUseGroup(cx, group, v.address(), 1);
return SingleElementStringArray(cx, group, str);
}
// Step 3 (reordered).
@ -2991,19 +3020,22 @@ CharSplitHelper(JSContext* cx, HandleLinearString str, uint32_t limit, HandleObj
js::StaticStrings& staticStrings = cx->staticStrings();
uint32_t resultlen = (limit < strLength ? limit : strLength);
MOZ_ASSERT(limit > 0 && resultlen > 0,
"Neither limit nor strLength is zero, so resultlen is greater than zero.");
AutoValueVector splits(cx);
if (!splits.reserve(resultlen))
RootedArrayObject splits(cx, NewFullyAllocatedStringArray(cx, group, resultlen));
if (!splits)
return nullptr;
splits->ensureDenseInitializedLength(cx, 0, resultlen);
for (size_t i = 0; i < resultlen; ++i) {
JSString* sub = staticStrings.getUnitStringForElement(cx, str, i);
if (!sub)
return nullptr;
splits.infallibleAppend(StringValue(sub));
splits->initDenseElement(i, StringValue(sub));
}
return NewCopiedArrayTryUseGroup(cx, group, splits.begin(), splits.length());
return splits;
}
template <typename TextChar>
@ -3019,34 +3051,36 @@ SplitSingleCharHelper(JSContext* cx, HandleLinearString str, const TextChar* tex
}
// Handle zero-occurrence case - return input string in an array.
if (count == 0) {
RootedValue strValue(cx, StringValue(str.get()));
return NewCopiedArrayTryUseGroup(cx, group, &strValue.get(), 1);
}
if (count == 0)
return SingleElementStringArray(cx, group, str);
// Reserve memory for substring values.
AutoValueVector splits(cx);
if (!splits.reserve(count + 1))
// Create the result array for the substring values.
RootedArrayObject splits(cx, NewFullyAllocatedStringArray(cx, group, count + 1));
if (!splits)
return nullptr;
splits->ensureDenseInitializedLength(cx, 0, count + 1);
// Add substrings.
uint32_t splitsIndex = 0;
size_t lastEndIndex = 0;
for (size_t index = 0; index < textLen; index++) {
if (static_cast<char16_t>(text[index]) == patCh) {
size_t subLength = size_t(index - lastEndIndex);
JSString* sub = NewDependentString(cx, str, lastEndIndex, subLength);
if (!sub || !splits.append(StringValue(sub)))
if (!sub)
return nullptr;
splits->initDenseElement(splitsIndex++, StringValue(sub));
lastEndIndex = index + 1;
}
}
// Add substring for tail of string (after last match).
JSString* sub = NewDependentString(cx, str, lastEndIndex, textLen - lastEndIndex);
if (!sub || !splits.append(StringValue(sub)))
if (!sub)
return nullptr;
splits->initDenseElement(splitsIndex++, StringValue(sub));
return NewCopiedArrayTryUseGroup(cx, group, splits.begin(), splits.length());
return splits;
}
// ES 2016 draft Mar 25, 2016 21.1.3.17 steps 4, 8, 12-18.
@ -3071,6 +3105,8 @@ ArrayObject*
js::str_split_string(JSContext* cx, HandleObjectGroup group, HandleString str, HandleString sep,
uint32_t limit)
{
MOZ_ASSERT(limit > 0, "Only called for strictly positive limit.");
RootedLinearString linearStr(cx, str->ensureLinear(cx));
if (!linearStr)
return nullptr;

View File

@ -4411,8 +4411,7 @@ js::LambdaArrow(JSContext* cx, HandleFunction fun, HandleObject parent, HandleVa
{
MOZ_ASSERT(fun->isArrow());
JSFunction* clone = CloneFunctionObjectIfNotSingleton(cx, fun, parent, nullptr,
TenuredObject);
JSFunction* clone = CloneFunctionObjectIfNotSingleton(cx, fun, parent);
if (!clone)
return nullptr;

View File

@ -1721,6 +1721,7 @@ intrinsic_StringSplitStringLimit(JSContext* cx, unsigned argc, Value* vp)
// args[2] should be already in UInt32 range, but it could be double typed,
// because of Ion optimization.
uint32_t limit = uint32_t(args[2].toNumber());
MOZ_ASSERT(limit > 0, "Zero limit case is already handled in self-hosted code.");
RootedObjectGroup group(cx, ObjectGroupCompartment::getStringSplitStringGroup(cx));
if (!group)

View File

@ -288,12 +288,12 @@ public:
* Remove and destroy all property values for the frame.
*/
void DeleteAll(const nsIFrame* aFrame) {
mozilla::DebugOnly<size_t> len = mProperties.Length();
for (auto& prop : mProperties) {
nsTArray<PropertyValue> toDelete;
toDelete.SwapElements(mProperties);
for (auto& prop : toDelete) {
prop.DestroyValueFor(aFrame);
MOZ_ASSERT(mProperties.Length() == len);
}
mProperties.Clear();
MOZ_ASSERT(mProperties.IsEmpty(), "a property dtor added new properties");
}
size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const {

View File

@ -32,12 +32,14 @@ struct RenderTargetPixel;
struct ScreenPixel;
struct ParentLayerPixel;
struct DesktopPixel;
struct ImagePixel;
template<> struct IsPixel<CSSPixel> : TrueType {};
template<> struct IsPixel<LayoutDevicePixel> : TrueType {};
template<> struct IsPixel<LayerPixel> : TrueType {};
template<> struct IsPixel<CSSTransformedLayerPixel> : TrueType {};
template<> struct IsPixel<RenderTargetPixel> : TrueType {};
template<> struct IsPixel<ImagePixel> : TrueType {};
template<> struct IsPixel<ScreenPixel> : TrueType {};
template<> struct IsPixel<ParentLayerPixel> : TrueType {};
template<> struct IsPixel<DesktopPixel> : TrueType {};
@ -100,6 +102,8 @@ typedef gfx::MarginTyped<RenderTargetPixel> RenderTargetMargin;
typedef gfx::IntMarginTyped<RenderTargetPixel> RenderTargetIntMargin;
typedef gfx::IntRegionTyped<RenderTargetPixel> RenderTargetIntRegion;
typedef gfx::IntRectTyped<ImagePixel> ImageIntRect;
typedef gfx::CoordTyped<ScreenPixel> ScreenCoord;
typedef gfx::IntCoordTyped<ScreenPixel> ScreenIntCoord;
typedef gfx::PointTyped<ScreenPixel> ScreenPoint;
@ -408,6 +412,13 @@ struct CSSTransformedLayerPixel {
struct RenderTargetPixel {
};
/*
* This unit represents one pixel in an image. Image space
* is largely independent of any other space.
*/
struct ImagePixel {
};
/*
* The pixels that are displayed on the screen.
* On non-OMTC platforms this should be equivalent to LayerPixel units.

View File

@ -121,7 +121,7 @@ BuildDisplayListForTopLayerFrame(nsDisplayListBuilder* aBuilder,
clipState.SetClipChainForContainingBlockDescendants(
savedOutOfFlowData->mCombinedClipChain);
clipState.ClipContainingBlockDescendantsExtra(
dirty + aBuilder->ToReferenceFrame(aFrame), nullptr);
visible + aBuilder->ToReferenceFrame(aFrame), nullptr);
asrSetter.SetCurrentActiveScrolledRoot(
savedOutOfFlowData->mContainingBlockActiveScrolledRoot);
}

View File

@ -957,8 +957,12 @@ nsIFrame::RemoveDisplayItemDataForDeletion()
DisplayItemArray* items = RemoveProperty(DisplayItems());
if (items) {
for (nsDisplayItem* item : *items) {
item->RemoveFrame(this);
for (nsDisplayItem* i : *items) {
if (i->GetDependentFrame() == this &&
!i->HasDeletedFrame()) {
i->Frame()->MarkNeedsDisplayItemRebuild();
}
i->RemoveFrame(this);
}
delete items;
}
@ -2518,7 +2522,8 @@ WrapSeparatorTransform(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
void
nsIFrame::BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder,
nsDisplayList* aList) {
nsDisplayList* aList,
bool* aCreatedContainerItem) {
if (GetStateBits() & NS_FRAME_TOO_DEEP_IN_FRAME_TREE)
return;
@ -2897,6 +2902,10 @@ nsIFrame::BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder,
// Get the ASR to use for the container items that we create here.
const ActiveScrolledRoot* containerItemASR = contASRTracker.GetContainerASR();
if (aCreatedContainerItem) {
*aCreatedContainerItem = false;
}
/* If adding both a nsDisplayBlendContainer and a nsDisplayBlendMode to the
* same list, the nsDisplayBlendContainer should be added first. This only
* happens when the element creating this stacking context has mix-blend-mode
@ -2910,6 +2919,9 @@ nsIFrame::BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder,
resultList.AppendNewToTop(
nsDisplayBlendContainer::CreateForMixBlendMode(aBuilder, this, &resultList,
containerItemASR));
if (aCreatedContainerItem) {
*aCreatedContainerItem = true;
}
}
/* If there are any SVG effects, wrap the list up in an SVG effects item
@ -2953,6 +2965,9 @@ nsIFrame::BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder,
// because nsDisplayMask items can't build active layers.
aBuilder->ExitSVGEffectsContents();
resultList.AppendToTop(&hoistedScrollInfoItemsStorage);
if (aCreatedContainerItem) {
*aCreatedContainerItem = false;
}
}
/* If the list is non-empty and there is CSS group opacity without SVG
@ -2968,6 +2983,9 @@ nsIFrame::BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder,
new (aBuilder) nsDisplayOpacity(aBuilder, this, &resultList,
containerItemASR,
opacityItemForEventsAndPluginsOnly));
if (aCreatedContainerItem) {
*aCreatedContainerItem = true;
}
}
/* If we're going to apply a transformation and don't have preserve-3d set, wrap
@ -3043,6 +3061,10 @@ nsIFrame::BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder,
GetContainingBlock(0, disp)->GetContent()->GetPrimaryFrame(),
&resultList));
}
if (aCreatedContainerItem) {
*aCreatedContainerItem = true;
}
}
if (clipCapturedBy == ContainerItemType::eOwnLayerForTransformWithRoundedClip) {
@ -3052,6 +3074,9 @@ nsIFrame::BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder,
aBuilder->CurrentActiveScrolledRoot(), 0,
mozilla::layers::FrameMetrics::NULL_SCROLL_ID,
ScrollThumbData{}, /* aForceActive = */ false));
if (aCreatedContainerItem) {
*aCreatedContainerItem = true;
}
}
/* If we have sticky positioning, wrap it in a sticky position item.
@ -3068,6 +3093,9 @@ nsIFrame::BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder,
ActiveScrolledRoot::PickAncestor(containerItemASR, aBuilder->CurrentActiveScrolledRoot());
resultList.AppendNewToTop(
new (aBuilder) nsDisplayFixedPosition(aBuilder, this, &resultList, fixedASR));
if (aCreatedContainerItem) {
*aCreatedContainerItem = true;
}
} else if (useStickyPosition) {
// For position:sticky, the clip needs to be applied both to the sticky
// container item and to the contents. The container item needs the clip
@ -3081,6 +3109,9 @@ nsIFrame::BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder,
ActiveScrolledRoot::PickAncestor(containerItemASR, aBuilder->CurrentActiveScrolledRoot());
resultList.AppendNewToTop(
new (aBuilder) nsDisplayStickyPosition(aBuilder, this, &resultList, stickyASR));
if (aCreatedContainerItem) {
*aCreatedContainerItem = true;
}
}
/* If there's blending, wrap up the list in a blend-mode item. Note
@ -3095,9 +3126,12 @@ nsIFrame::BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder,
new (aBuilder) nsDisplayBlendMode(aBuilder, this, &resultList,
effects->mMixBlendMode,
containerItemASR));
if (aCreatedContainerItem) {
*aCreatedContainerItem = true;
}
}
CreateOwnLayerIfNeeded(aBuilder, &resultList);
CreateOwnLayerIfNeeded(aBuilder, &resultList, aCreatedContainerItem);
aList->AppendToTop(&resultList);
}
@ -3105,28 +3139,21 @@ nsIFrame::BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder,
static nsDisplayItem*
WrapInWrapList(nsDisplayListBuilder* aBuilder,
nsIFrame* aFrame, nsDisplayList* aList,
const ActiveScrolledRoot* aContainerASR)
const ActiveScrolledRoot* aContainerASR,
bool aCanSkipWrapList = false)
{
nsDisplayItem* item = aList->GetBottom();
if (!item) {
return nullptr;
}
// For perspective items we want to treat the 'frame' as being the transform
// frame that created it. This stops the transform frame from wrapping another
// nsDisplayWrapList around it (with mismatching reference frames), but still
// makes the perspective frame create one (so we have an atomic entry for z-index
// sorting).
nsIFrame *itemFrame = item->Frame();
if (item->GetType() == DisplayItemType::TYPE_PERSPECTIVE) {
itemFrame = static_cast<nsDisplayPerspective*>(item)->TransformFrame();
if (aCanSkipWrapList) {
MOZ_ASSERT(!item->GetAbove());
aList->RemoveBottom();
return item;
}
if (item->GetAbove() || itemFrame != aFrame) {
return new (aBuilder) nsDisplayWrapList(aBuilder, aFrame, aList, aContainerASR);
}
aList->RemoveBottom();
return item;
return new (aBuilder) nsDisplayWrapList(aBuilder, aFrame, aList, aContainerASR);
}
/**
@ -3416,6 +3443,7 @@ nsIFrame::BuildDisplayListForChild(nsDisplayListBuilder* aBuilder,
nsDisplayList list(aBuilder);
nsDisplayList extraPositionedDescendants(aBuilder);
const ActiveScrolledRoot* wrapListASR = aBuilder->CurrentActiveScrolledRoot();
bool canSkipWrapList = false;
if (isStackingContext) {
if (effects->mMixBlendMode != NS_STYLE_BLEND_NORMAL) {
aBuilder->SetContainsBlendMode(true);
@ -3424,7 +3452,7 @@ nsIFrame::BuildDisplayListForChild(nsDisplayListBuilder* aBuilder,
// For stacking contexts, BuildDisplayListForStackingContext handles
// clipping and MarkAbsoluteFramesForDisplayList.
nsDisplayListBuilder::AutoContainerASRTracker contASRTracker(aBuilder);
child->BuildDisplayListForStackingContext(aBuilder, &list);
child->BuildDisplayListForStackingContext(aBuilder, &list, &canSkipWrapList);
wrapListASR = contASRTracker.GetContainerASR();
aBuilder->DisplayCaret(child, &list);
} else {
@ -3517,7 +3545,7 @@ nsIFrame::BuildDisplayListForChild(nsDisplayListBuilder* aBuilder,
// Genuine stacking contexts, and positioned pseudo-stacking-contexts,
// go in this level.
if (!list.IsEmpty()) {
nsDisplayItem* item = WrapInWrapList(aBuilder, child, &list, wrapListASR);
nsDisplayItem* item = WrapInWrapList(aBuilder, child, &list, wrapListASR, canSkipWrapList);
if (isSVG) {
aLists.Content()->AppendNewToTop(item);
} else {
@ -10643,13 +10671,17 @@ nsIFrame::SetParent(nsContainerFrame* aParent)
void
nsIFrame::CreateOwnLayerIfNeeded(nsDisplayListBuilder* aBuilder,
nsDisplayList* aList)
nsDisplayList* aList,
bool* aCreatedContainerItem)
{
if (GetContent() &&
GetContent()->IsXULElement() &&
GetContent()->HasAttr(kNameSpaceID_None, nsGkAtoms::layer)) {
aList->AppendNewToTop(new (aBuilder)
nsDisplayOwnLayer(aBuilder, this, aList, aBuilder->CurrentActiveScrolledRoot()));
if (aCreatedContainerItem) {
*aCreatedContainerItem = true;
}
}
}

View File

@ -1701,9 +1701,13 @@ public:
/**
* Builds a display list for the content represented by this frame,
* treating this frame as the root of a stacking context.
* Optionally sets aCreatedContainerItem to true if we created a
* single container display item for the stacking context, and no
* other wrapping items are needed.
*/
void BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder,
nsDisplayList* aList);
nsDisplayList* aList,
bool* aCreatedContainerItem = nullptr);
enum {
DISPLAY_CHILD_FORCE_PSEUDO_STACKING_CONTEXT = 0x01,
@ -3938,7 +3942,8 @@ public:
uint8_t VerticalAlignEnum() const;
enum { eInvalidVerticalAlign = 0xFF };
void CreateOwnLayerIfNeeded(nsDisplayListBuilder* aBuilder, nsDisplayList* aList);
void CreateOwnLayerIfNeeded(nsDisplayListBuilder* aBuilder, nsDisplayList* aList,
bool* aCreatedContainerItem = nullptr);
/**
* Adds the NS_FRAME_IN_POPUP state bit to aFrame, and

View File

@ -1129,15 +1129,14 @@ void nsDisplayListBuilder::MarkOutOfFlowFrameForDisplay(nsIFrame* aDirtyFrame,
if (ps->IsScrollPositionClampingScrollPortSizeSet()) {
dirtyRectRelativeToDirtyFrame =
nsRect(nsPoint(0, 0), ps->GetScrollPositionClampingScrollPortSize());
visible = dirtyRectRelativeToDirtyFrame;
#ifdef MOZ_WIDGET_ANDROID
} else {
dirtyRectRelativeToDirtyFrame =
nsRect(nsPoint(0, 0), aDirtyFrame->GetSize());
visible = dirtyRectRelativeToDirtyFrame;
#endif
}
// TODO: We probably don't want visible and dirty to be the same here, figure
// out what to do.
visible = dirtyRectRelativeToDirtyFrame;
}
nsPoint offset = aFrame->GetOffsetTo(aDirtyFrame);
visible -= offset;

View File

@ -196,6 +196,7 @@ protected:
static void DetachAGR(AnimatedGeometryRoot* aAGR) {
aAGR->mFrame = nullptr;
aAGR->mParentAGR = nullptr;
NS_RELEASE(aAGR);
}
NS_DECLARE_FRAME_PROPERTY_WITH_DTOR(AnimatedGeometryRootCache, AnimatedGeometryRoot, DetachAGR)
@ -207,6 +208,7 @@ protected:
{
MOZ_ASSERT(mParentAGR || mIsAsync, "The root AGR should always be treated as an async AGR.");
if (mIsRetained) {
NS_ADDREF(this);
aFrame->SetProperty(AnimatedGeometryRootCache(), this);
}
}
@ -254,7 +256,8 @@ struct ActiveScrolledRoot {
asr = new ActiveScrolledRoot();
if (aIsRetained) {
f->SetProperty(ActiveScrolledRootCache(), asr);
RefPtr<ActiveScrolledRoot> ref = asr;
f->SetProperty(ActiveScrolledRootCache(), ref.forget().take());
}
}
asr->mParent = aParent;
@ -308,6 +311,7 @@ private:
static void DetachASR(ActiveScrolledRoot* aASR) {
aASR->mParent = nullptr;
aASR->mScrollableFrame = nullptr;
NS_RELEASE(aASR);
}
NS_DECLARE_FRAME_PROPERTY_WITH_DTOR(ActiveScrolledRootCache, ActiveScrolledRoot, DetachASR)

View File

@ -7,3 +7,4 @@ skip-if(!retainedDisplayList) == retained-dl-remove-for-ancestor-change-1.html r
skip-if(!retainedDisplayList) == retained-dl-scroll-out-of-view-1.html retained-dl-scroll-out-of-view-1-ref.html
skip-if(!retainedDisplayList) == retained-dl-displayport-1.html retained-dl-displayport-1-ref.html
skip-if(!retainedDisplayList) == retained-dl-prerender-transform-1.html retained-dl-prerender-transform-1-ref.html
== retained-dl-wrap-list.html retained-dl-wrap-list-ref.html

View File

@ -0,0 +1,14 @@
<html>
<head>
<style>
#hover {
background-color:blue;
}
</style>
</head>
<body>
<div style="float:left; width:200px; height:200px; background-color: red">
<div style="width:100px; height:100px; " id="hover"></div>
</div>
</body>
</html>

View File

@ -0,0 +1,15 @@
<html class="reftest-wait">
<body>
<div style="float:left; width:200px; height:200px; background-color: red">
<div style="width:100px; height:100px;" id="hover"></div>
</div>
</body>
<script>
function doTest() {
document.getElementById("hover").style.backgroundColor = "blue";
document.documentElement.removeAttribute("class");
}
window.addEventListener("MozReftestInvalidate", doTest);
</script>
</html>

View File

@ -136,9 +136,12 @@ class ReftestRunner(MozbuildObject):
args.ignoreWindowSize = True
args.printDeviceInfo = False
from mozrunner.devices.android_device import grant_runtime_permissions
from mozrunner.devices.android_device import grant_runtime_permissions, get_adb_path
grant_runtime_permissions(self)
if not args.adb_path:
args.adb_path = get_adb_path(self)
# A symlink and some path manipulations are required so that test
# manifests can be found both locally and remotely (via a url)
# using the same relative path.

View File

@ -418,7 +418,7 @@ class RemoteArgumentsParser(ReftestArgumentsParser):
action="store",
type=str,
dest="adb_path",
default="adb",
default=None,
help="path to adb")
self.add_argument("--deviceIP",

View File

@ -98,7 +98,8 @@ using namespace mozilla;
if (MOZ_UNLIKELY(!XRE_IsParentProcess())) { \
nsPrintfCString msg( \
"ENSURE_MAIN_PROCESS: called %s on %s in a non-main process", \
func, pref); \
func, \
pref); \
NS_ERROR(msg.get()); \
return NS_ERROR_NOT_AVAILABLE; \
} \
@ -109,7 +110,8 @@ using namespace mozilla;
if (MOZ_UNLIKELY(!XRE_IsParentProcess())) { \
nsPrintfCString msg( \
"ENSURE_MAIN_PROCESS: called %s on %s in a non-main process", \
func, pref); \
func, \
pref); \
NS_WARNING(msg.get()); \
return NS_ERROR_NOT_AVAILABLE; \
} \
@ -243,11 +245,8 @@ private:
{
PREF_FLAG_LOCKED = 4,
PREF_FLAG_USERSET = 8,
PREF_FLAG_CONFIG = 16,
PREF_FLAG_REMOTE = 32,
PREF_FLAG_LILOCAL = 64,
PREF_FLAG_HAS_DEFAULT = 128,
PREF_FLAG_STICKY_DEFAULT = 256,
PREF_FLAG_HAS_DEFAULT = 16,
PREF_FLAG_STICKY_DEFAULT = 32,
};
uint16_t mValue;
};
@ -2176,8 +2175,6 @@ public:
int32_t GetRootLength() const { return mPrefRoot.Length(); }
nsresult RemoveObserverFromMap(const char* aDomain, nsISupports* aObserver);
static void NotifyObserver(const char* aNewpref, void* aData);
size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf);
@ -2261,8 +2258,7 @@ private:
nsClassHashtable<PrefCallback, PrefCallback> mObservers;
};
class nsPrefLocalizedString final
: public nsIPrefLocalizedString
class nsPrefLocalizedString final : public nsIPrefLocalizedString
{
public:
nsPrefLocalizedString();

View File

@ -50,16 +50,16 @@ with Files('**/Makefile.in'):
FINAL = True
with Files("**/*.js"):
SCHEDULES.inclusive += ['test-verification']
SCHEDULES.inclusive += ['test-verify']
with Files("**/*.html"):
SCHEDULES.inclusive += ['test-verification']
SCHEDULES.inclusive += ['test-verify']
with Files("**/*.xhtml"):
SCHEDULES.inclusive += ['test-verification']
SCHEDULES.inclusive += ['test-verify']
with Files("**/*.xul"):
SCHEDULES.inclusive += ['test-verification']
SCHEDULES.inclusive += ['test-verify']
FILES_PER_UNIFIED_FILE = 1

View File

@ -17,7 +17,7 @@ INCLUSIVE_COMPONENTS = [
'yaml-lint',
# test suites that only run when certain files have changed
'jittest',
'test-verification',
'test-verify',
# test flavors (narrower than suites)
'jsreftest',
]

View File

@ -50,7 +50,7 @@ telemetry-tests-client:
test-verify:
description: "Extra verification of tests modified on this push"
suite: test-verification
suite: test-verify
treeherder-symbol: tc(TV)
loopback-video: true
max-run-time: 5400

View File

@ -640,7 +640,7 @@ def handle_suite_category(config, tests):
script = test['mozharness']['script']
category_arg = None
if suite == 'test-verification':
if suite == 'test-verify':
pass
elif script == 'android_emulator_unittest.py':
category_arg = '--test-suite'

View File

@ -388,6 +388,9 @@ class MachCommands(MachCommandBase):
commandline.add_logging_group(parser)
options, args = parser.parse_args()
if not options.adb_path:
from mozrunner.devices.android_device import get_adb_path
options.adb_path = get_adb_path(self)
options.symbols_path = symbols_path
options.manifest_path = manifest_path
options.xre_path = self.bindir

View File

@ -172,6 +172,10 @@ class MochitestRunner(MozbuildObject):
('.py', 'r', imp.PY_SOURCE))
import runtestsremote
from mozrunner.devices.android_device import get_adb_path
if not kwargs['adbPath']:
kwargs['adbPath'] = get_adb_path(self)
options = Namespace(**kwargs)
from manifestparser import TestManifest
@ -455,9 +459,12 @@ class RobocopCommands(MachCommandBase):
sorted(list(test_paths)))))
return 1
from mozrunner.devices.android_device import grant_runtime_permissions
from mozrunner.devices.android_device import grant_runtime_permissions, get_adb_path
grant_runtime_permissions(self)
if not kwargs['adbPath']:
kwargs['adbPath'] = get_adb_path(self)
mochitest = self._spawn(MochitestRunner)
return mochitest.run_robocop_test(self._mach_context, tests, 'robocop', **kwargs)

View File

@ -248,6 +248,10 @@ def verify_android_device(build_obj, install=False, xre=False, debugger=False, v
return device_verified
def get_adb_path(build_obj):
return _find_sdk_exe(build_obj.substs, 'adb', False)
def run_firefox_for_android(build_obj, params):
"""
Launch Firefox for Android on the connected device.

View File

@ -178,6 +178,11 @@ class RemoteCPPUnittestOptions(cppunittests.CPPUnittestOptions):
help="port of remote device to test")
defaults["device_port"] = 20701
self.add_option("--adbPath", action="store",
type="string", dest="adb_path",
help="Path to adb")
defaults["adb_path"] = None
self.add_option("--noSetup", action="store_false",
dest="setup",
help="do not copy any files to device (to be used only if "
@ -238,6 +243,8 @@ def run_test_harness(options, args):
if options.device_ip:
dm_args['host'] = options.device_ip
dm_args['port'] = options.device_port
if options.adb_path:
dm_args['adbPath'] = options.adb_path
if options.log_tbpl_level == 'debug' or options.log_mach_level == 'debug':
dm_args['logLevel'] = logging.DEBUG # noqa python 2 / 3
dm = devicemanagerADB.DeviceManagerADB(**dm_args)

View File

@ -248,7 +248,7 @@ RunnerManagerState = _RunnerManagerState()
class TestRunnerManager(threading.Thread):
def __init__(self, suite_name, test_queue, test_source_cls, browser_cls, browser_kwargs,
executor_cls, executor_kwargs, stop_flag, pause_after_test=False,
executor_cls, executor_kwargs, stop_flag, rerun=1, pause_after_test=False,
pause_on_unexpected=False, restart_on_unexpected=True, debug_info=None):
"""Thread that owns a single TestRunner process and any processes required
by the TestRunner (e.g. the Firefox binary).
@ -279,6 +279,8 @@ class TestRunnerManager(threading.Thread):
self.parent_stop_flag = stop_flag
self.child_stop_flag = multiprocessing.Event()
self.rerun = rerun
self.run_count = 0
self.pause_after_test = pause_after_test
self.pause_on_unexpected = pause_on_unexpected
self.restart_on_unexpected = restart_on_unexpected
@ -502,9 +504,9 @@ class TestRunnerManager(threading.Thread):
self.logger.info("No more tests")
return None, None, None
test = test_group.popleft()
self.run_count = 0
return test, test_group, group_metadata
def run_test(self):
assert isinstance(self.state, RunnerManagerState.running)
assert self.state.test is not None
@ -516,6 +518,9 @@ class TestRunnerManager(threading.Thread):
self.state.group_metadata)
self.logger.test_start(self.state.test.id)
if self.rerun > 1:
self.logger.info("Run %d/%d" % (self.run_count, self.rerun))
self.run_count += 1
self.send_message("run_test", self.state.test)
def test_ended(self, test, results):
@ -579,7 +584,7 @@ class TestRunnerManager(threading.Thread):
self.logger.info("Pausing until the browser exits")
self.send_message("wait")
else:
return self.after_test_end(restart_before_next)
return self.after_test_end(test, restart_before_next)
def wait_finished(self):
assert isinstance(self.state, RunnerManagerState.running)
@ -589,14 +594,19 @@ class TestRunnerManager(threading.Thread):
return self.after_test_end(True)
def after_test_end(self, restart):
def after_test_end(self, test, restart):
assert isinstance(self.state, RunnerManagerState.running)
test, test_group, group_metadata = self.get_next_test()
if test is None:
return RunnerManagerState.stop()
if test_group != self.state.test_group:
# We are starting a new group of tests, so force a restart
restart = True
if self.run_count == self.rerun:
test, test_group, group_metadata = self.get_next_test()
if test is None:
return RunnerManagerState.stop()
if test_group != self.state.test_group:
# We are starting a new group of tests, so force a restart
restart = True
else:
test = test
test_group = self.state.test_group
group_metadata = self.state.group_metadata
if restart:
return RunnerManagerState.restarting(test, test_group, group_metadata)
else:
@ -685,6 +695,7 @@ class ManagerGroup(object):
def __init__(self, suite_name, size, test_source_cls, test_source_kwargs,
browser_cls, browser_kwargs,
executor_cls, executor_kwargs,
rerun=1,
pause_after_test=False,
pause_on_unexpected=False,
restart_on_unexpected=True,
@ -702,6 +713,7 @@ class ManagerGroup(object):
self.pause_on_unexpected = pause_on_unexpected
self.restart_on_unexpected = restart_on_unexpected
self.debug_info = debug_info
self.rerun = rerun
self.pool = set()
# Event that is polled by threads so that they can gracefully exit in the face
@ -734,6 +746,7 @@ class ManagerGroup(object):
self.executor_cls,
self.executor_kwargs,
self.stop_flag,
self.rerun,
self.pause_after_test,
self.pause_on_unexpected,
self.restart_on_unexpected,

View File

@ -74,6 +74,9 @@ scheme host and port.""")
mode_group.add_argument("--list-tests", action="store_true",
default=False,
help="List all tests that will run")
mode_group.add_argument("--verify", action="store_true",
default=False,
help="Run a stability check on the selected tests")
test_selection_group = parser.add_argument_group("Test Selection")
test_selection_group.add_argument("--test-types", action="store",
@ -93,8 +96,10 @@ scheme host and port.""")
debugging_group.add_argument('--debugger', const="__default__", nargs="?",
help="run under a debugger, e.g. gdb or valgrind")
debugging_group.add_argument('--debugger-args', help="arguments to the debugger")
debugging_group.add_argument("--rerun", action="store", type=int, default=1,
help="Number of times to re run each test without restarts")
debugging_group.add_argument("--repeat", action="store", type=int, default=1,
help="Number of times to run the tests")
help="Number of times to run the tests, restarting between each run")
debugging_group.add_argument("--repeat-until-unexpected", action="store_true", default=None,
help="Run tests in a loop until one returns an unexpected result")
debugging_group.add_argument('--pause-after-test', action="store_true", default=None,

View File

@ -122,7 +122,7 @@ def get_pause_after_test(test_loader, **kwargs):
if kwargs["pause_after_test"] is None:
if kwargs["repeat_until_unexpected"]:
return False
if kwargs["repeat"] == 1 and total_tests == 1:
if kwargs["repeat"] == 1 and kwargs["rerun"] == 1 and total_tests == 1:
return True
return False
return kwargs["pause_after_test"]
@ -241,6 +241,7 @@ def run_tests(config, test_paths, product, **kwargs):
browser_kwargs,
executor_cls,
executor_kwargs,
kwargs["rerun"],
kwargs["pause_after_test"],
kwargs["pause_on_unexpected"],
kwargs["restart_on_unexpected"],
@ -260,6 +261,12 @@ def run_tests(config, test_paths, product, **kwargs):
logger.suite_end()
return unexpected_total == 0
def check_stability(**kwargs):
import stability
return stability.check_stability(logger, **kwargs)
def start(**kwargs):
if kwargs["list_test_groups"]:
list_test_groups(**kwargs)
@ -267,9 +274,12 @@ def start(**kwargs):
list_disabled(**kwargs)
elif kwargs["list_tests"]:
list_tests(**kwargs)
elif kwargs["verify"]:
check_stability(**kwargs)
else:
return not run_tests(**kwargs)
def main():
"""Main entry point when calling from the command line"""
kwargs = wptcommandline.parse_args()

View File

@ -145,13 +145,15 @@ class XPCShellRunner(MozbuildObject):
class AndroidXPCShellRunner(MozbuildObject):
"""Get specified DeviceManager"""
def get_devicemanager(self, ip, port, remote_test_root):
def get_devicemanager(self, ip, port, remote_test_root, adb_path):
import mozdevice
dm = None
if ip:
dm = mozdevice.DroidADB(ip, port, packageName=None, deviceRoot=remote_test_root)
dm = mozdevice.DroidADB(ip, port, packageName=None, deviceRoot=remote_test_root,
adbPath=adb_path)
else:
dm = mozdevice.DroidADB(packageName=None, deviceRoot=remote_test_root)
dm = mozdevice.DroidADB(packageName=None, deviceRoot=remote_test_root,
adbPath=adb_path)
return dm
"""Run Android xpcshell tests."""
@ -164,7 +166,7 @@ class AndroidXPCShellRunner(MozbuildObject):
import remotexpcshelltests
dm = self.get_devicemanager(kwargs["deviceIP"], kwargs["devicePort"],
kwargs["remoteTestRoot"])
kwargs["remoteTestRoot"], kwargs["adbPath"])
log = kwargs.pop("log")
self.log_manager.enable_unstructured()
@ -255,8 +257,10 @@ class MachCommands(MachCommandBase):
params['threadCount'] = int((cpu_count() * 3) / 2)
if conditions.is_android(self):
from mozrunner.devices.android_device import verify_android_device
from mozrunner.devices.android_device import verify_android_device, get_adb_path
verify_android_device(self)
if not params['adbPath']:
params['adbPath'] = get_adb_path(self)
xpcshell = self._spawn(AndroidXPCShellRunner)
else:
xpcshell = self._spawn(XPCShellRunner)

View File

@ -601,6 +601,8 @@ def main():
dm_args['port'] = options['devicePort']
if options['log_tbpl_level'] == 'debug' or options['log_mach_level'] == 'debug':
dm_args['logLevel'] = logging.DEBUG
if options['adbPath']:
dm_args['adbPath'] = options['adbPath']
dm = mozdevice.DroidADB(**dm_args)
if options['interactive'] and not options['testPath']:

View File

@ -149,6 +149,9 @@ def add_remote_arguments(parser):
parser.add_argument("--apk", action="store", type=str, dest="localAPK",
help="local path to Fennec APK")
parser.add_argument("--adbPath", action="store", type=str, dest="adbPath",
help="Path to adb")
parser.add_argument("--noSetup", action="store_false", dest="setup", default=True,
help="do not copy any files to device (to be used only if "
"device is already setup)")

View File

@ -212,7 +212,7 @@ var Settings = {
getStatusStringForSetting(setting) {
let enabled = Preferences.get(setting.pref, setting.defaultPrefValue);
let status = bundle.GetStringFromName(enabled ? "telemetryEnabled" : "telemetryDisabled");
let status = bundle.GetStringFromName(enabled ? "telemetryUploadEnabled" : "telemetryUploadDisabled");
return status;
},
@ -220,17 +220,19 @@ var Settings = {
* Updates the button & text at the top of the page to reflect Telemetry state.
*/
render() {
let homeExplanation = document.getElementById("home-explanation");
let fhrEnabled = Preferences.get(this.SETTINGS[0].pref, this.SETTINGS[0].defaultPrefValue);
fhrEnabled = bundle.GetStringFromName(fhrEnabled ? "telemetryEnabled" : "telemetryDisabled");
let extendedEnabled = Preferences.get(this.SETTINGS[1].pref, this.SETTINGS[1].defaultPrefValue);
extendedEnabled = bundle.GetStringFromName(extendedEnabled ? "extendedTelemetryEnabled" : "extendedTelemetryDisabled");
let parameters = [fhrEnabled, extendedEnabled].map(this.convertStringToLink);
let settingsExplanation = document.getElementById("settings-explanation");
let uploadEnabled = this.getStatusStringForSetting(this.SETTINGS[0]);
let extendedEnabled = Services.telemetry.canRecordExtended;
let collectedData = bundle.GetStringFromName(extendedEnabled ? "prereleaseData" : "releaseData");
let explanation = bundle.formatStringFromName("homeExplanation", parameters, 2);
let parameters = [
collectedData,
this.convertStringToLink(uploadEnabled),
];
let explanation = bundle.formatStringFromName("settingsExplanation", parameters, 2);
// eslint-disable-next-line no-unsanitized/property
homeExplanation.innerHTML = explanation;
settingsExplanation.innerHTML = explanation;
this.attachObservers();
},

View File

@ -145,7 +145,7 @@
<section id="home-section" class="active">
<p id="page-subtitle"></p>
<p id="home-explanation"></p>
<p id="settings-explanation"></p>
<p id="ping-explanation"></p>
<p>&aboutTelemetry.moreInformations;</p>
<ul>

View File

@ -7,14 +7,14 @@
# - %2$S is replaced by brandFullName
pageSubtitle = This page shows the information about performance, hardware, usage and customizations collected by Telemetry. This information is submitted to %1$S to help improve %2$S.
# LOCALIZATION NOTE(homeExplanation):
# - %1$S is either telemetryEnabled or telemetryDisabled
# - %2$S is either extendedTelemetryEnabled or extendedTelemetryDisabled
homeExplanation = Telemetry is %1$S and extended telemetry is %2$S.
telemetryEnabled = enabled
telemetryDisabled = disabled
extendedTelemetryEnabled = enabled
extendedTelemetryDisabled = disabled
# LOCALIZATION NOTE(settingsExplanation):
# - %1$S is either releaseData or prereleaseData
# - %2$S is either telemetryUploadEnabled or telemetryUploadDisabled
settingsExplanation = Telemetry is collecting %1$S and upload is %2$S.
releaseData = release data
prereleaseData = pre-release data
telemetryUploadEnabled = enabled
telemetryUploadDisabled = disabled
# LOCALIZATION NOTE(pingDetails):
# - %1$S is replaced by a link with pingExplanationLink as text