--- a/gfx/2d/DrawTargetCG.cpp
+++ b/gfx/2d/DrawTargetCG.cpp
@@ -8,16 +8,17 @@
#include "Rect.h"
#include "ScaledFontMac.h"
#include "Tools.h"
#include <vector>
#include <algorithm>
#include "MacIOSurface.h"
#include "FilterNodeSoftware.h"
#include "mozilla/Assertions.h"
+#include "mozilla/FloatingPoint.h"
using namespace std;
//CG_EXTERN void CGContextSetCompositeOperation (CGContextRef, PrivateCGCompositeMode);
// A private API that Cairo has been using for a long time
CG_EXTERN void CGContextSetCTM(CGContextRef, CGAffineTransform);
@@ -408,16 +409,18 @@ DrawTargetCG::CreateGradientStops(Gradie
}
static void
UpdateLinearParametersToIncludePoint(double *min_t, double *max_t,
CGPoint *start,
double dx, double dy,
double x, double y)
{
+ MOZ_ASSERT(IsFinite(x) && IsFinite(y));
+
/**
* Compute a parameter t such that a line perpendicular to the (dx,dy)
* vector, passing through (start->x + dx*t, start->y + dy*t), also
* passes through (x,y).
*
* Let px = x - start->x, py = y - start->y.
* t is given by
* (px - dx*t)*dx + (py - dy*t)*dy = 0
@@ -604,16 +607,20 @@ DrawRadialRepeatingGradient(CGContextRef
CGContextDrawRadialGradient(cg, gradient, startCenter, startRadius, endCenter, endRadius,
kCGGradientDrawsBeforeStartLocation | kCGGradientDrawsAfterEndLocation);
CGGradientRelease(gradient);
}
static void
DrawGradient(CGContextRef cg, const Pattern &aPattern, const CGRect &aExtents)
{
+ if (CGRectIsEmpty(aExtents)) {
+ return;
+ }
+
if (aPattern.GetType() == PatternType::LINEAR_GRADIENT) {
const LinearGradientPattern& pat = static_cast<const LinearGradientPattern&>(aPattern);
GradientStopsCG *stops = static_cast<GradientStopsCG*>(pat.mStops.get());
CGContextConcatCTM(cg, GfxMatrixToCGAffineTransform(pat.mMatrix));
if (stops->mExtend == ExtendMode::CLAMP) {
// XXX: we should take the m out of the properties of LinearGradientPatterns
CGPoint startPoint = { pat.mBegin.x, pat.mBegin.y };
--- a/gfx/layers/Layers.cpp
+++ b/gfx/layers/Layers.cpp
@@ -808,19 +808,23 @@ ContainerLayer::RepositionChild(Layer* a
Layer* prev = aChild->GetPrevSibling();
Layer* next = aChild->GetNextSibling();
if (prev == aAfter) {
// aChild is already in the correct position, nothing to do.
return;
}
if (prev) {
prev->SetNextSibling(next);
+ } else {
+ mFirstChild = next;
}
if (next) {
next->SetPrevSibling(prev);
+ } else {
+ mLastChild = prev;
}
if (!aAfter) {
aChild->SetPrevSibling(nullptr);
aChild->SetNextSibling(mFirstChild);
if (mFirstChild) {
mFirstChild->SetPrevSibling(aChild);
}
mFirstChild = aChild;
--- a/gfx/tests/gtest/TestLayers.cpp
+++ b/gfx/tests/gtest/TestLayers.cpp
@@ -46,43 +46,16 @@ public:
virtual LayerType GetType() const {
return TYPE_CONTAINER;
}
virtual void ComputeEffectiveTransforms(const Matrix4x4& aTransformToSurface) {
DefaultComputeEffectiveTransforms(aTransformToSurface);
}
-
- virtual void RepositionChild(Layer* aChild, Layer* aAfter) {
- MOZ_CRASH();
- }
-
- virtual void InsertAfter(Layer* aChild, Layer* aAfter) {
- // Bad implementation but it should be fine for testing
- if (this == aChild) {
- MOZ_CRASH();
- }
- if (aAfter != nullptr && aAfter != mLastChild) {
- // Fix the implementation to support this if you need it
- MOZ_CRASH();
- }
- if (!mFirstChild) {
- mFirstChild = aChild;
- }
- if (mLastChild) {
- mLastChild->SetNextSibling(aChild);
- }
- aChild->SetPrevSibling(mLastChild);
- mLastChild = aChild;
- }
-
- virtual void RemoveChild(Layer* aChild) {
- MOZ_CRASH();
- }
};
class TestThebesLayer: public ThebesLayer {
public:
TestThebesLayer(LayerManager* aManager)
: ThebesLayer(aManager, nullptr)
{}
@@ -212,30 +185,34 @@ already_AddRefed<Layer> CreateLayerTree(
printf("Layer before '(' must be a container.\n");
MOZ_CRASH();
}
} else if (aLayerTreeDescription[i] == ')') {
parentContainerLayer = parentContainerLayer->GetParent();
lastLayer = nullptr;
} else {
nsRefPtr<Layer> layer = CreateLayer(aLayerTreeDescription[i], manager.get());
- layer->SetVisibleRegion(aVisibleRegions[layerNumber]);
- Matrix4x4 transform;
- ToMatrix4x4(aTransforms[layerNumber], transform);
- layer->SetBaseTransform(transform);
+ if (aVisibleRegions) {
+ layer->SetVisibleRegion(aVisibleRegions[layerNumber]);
+ }
+ if (aTransforms) {
+ Matrix4x4 transform;
+ ToMatrix4x4(aTransforms[layerNumber], transform);
+ layer->SetBaseTransform(transform);
+ }
aLayersOut.AppendElement(layer);
layerNumber++;
if (rootLayer && !parentContainerLayer) {
MOZ_CRASH();
}
if (!rootLayer) {
rootLayer = layer;
}
if (parentContainerLayer) {
- parentContainerLayer->InsertAfter(layer, nullptr);
+ parentContainerLayer->InsertAfter(layer, parentContainerLayer->GetLastChild());
layer->SetParent(parentContainerLayer);
}
lastLayer = layer;
}
}
if (rootLayer) {
rootLayer->ComputeEffectiveTransforms(Matrix4x4());
}
@@ -265,8 +242,85 @@ TEST(Layers, LayerTree) {
// an int.
Layer* nullLayer = nullptr;
ASSERT_NE(nullLayer, layers[0]->AsContainerLayer());
ASSERT_NE(nullLayer, layers[1]->AsContainerLayer());
ASSERT_NE(nullLayer, layers[2]->AsThebesLayer());
ASSERT_NE(nullLayer, layers[3]->AsThebesLayer());
}
+static void ValidateTreePointers(Layer* aLayer) {
+ if (aLayer->GetNextSibling()) {
+ ASSERT_EQ(aLayer, aLayer->GetNextSibling()->GetPrevSibling());
+ } else if (aLayer->GetParent()) {
+ ASSERT_EQ(aLayer, aLayer->GetParent()->GetLastChild());
+ }
+ if (aLayer->GetPrevSibling()) {
+ ASSERT_EQ(aLayer, aLayer->GetPrevSibling()->GetNextSibling());
+ } else if (aLayer->GetParent()) {
+ ASSERT_EQ(aLayer, aLayer->GetParent()->GetFirstChild());
+ }
+ if (aLayer->GetFirstChild()) {
+ ASSERT_EQ(aLayer, aLayer->GetFirstChild()->GetParent());
+ }
+ if (aLayer->GetLastChild()) {
+ ASSERT_EQ(aLayer, aLayer->GetLastChild()->GetParent());
+ }
+}
+
+static void ValidateTreePointers(nsTArray<nsRefPtr<Layer> >& aLayers) {
+ for (uint32_t i = 0; i < aLayers.Length(); i++) {
+ ValidateTreePointers(aLayers[i]);
+ }
+}
+
+TEST(Layers, RepositionChild) {
+ const char* layerTreeSyntax = "c(ttt)";
+
+ nsTArray<nsRefPtr<Layer> > layers;
+ nsRefPtr<LayerManager> lm;
+ nsRefPtr<Layer> root = CreateLayerTree(layerTreeSyntax, nullptr, nullptr, lm, layers);
+ ContainerLayer* parent = root->AsContainerLayer();
+ ValidateTreePointers(layers);
+
+ // tree is currently like this (using indexes into layers):
+ // 0
+ // 1 2 3
+ ASSERT_EQ(layers[2], layers[1]->GetNextSibling());
+ ASSERT_EQ(layers[3], layers[2]->GetNextSibling());
+ ASSERT_EQ(nullptr, layers[3]->GetNextSibling());
+
+ parent->RepositionChild(layers[1], layers[3]);
+ ValidateTreePointers(layers);
+
+ // now the tree is like this:
+ // 0
+ // 2 3 1
+ ASSERT_EQ(layers[3], layers[2]->GetNextSibling());
+ ASSERT_EQ(layers[1], layers[3]->GetNextSibling());
+ ASSERT_EQ(nullptr, layers[1]->GetNextSibling());
+
+ parent->RepositionChild(layers[3], layers[2]);
+ ValidateTreePointers(layers);
+
+ // no change
+ ASSERT_EQ(layers[3], layers[2]->GetNextSibling());
+ ASSERT_EQ(layers[1], layers[3]->GetNextSibling());
+ ASSERT_EQ(nullptr, layers[1]->GetNextSibling());
+
+ parent->RepositionChild(layers[3], layers[1]);
+ ValidateTreePointers(layers);
+
+ // 0
+ // 2 1 3
+ ASSERT_EQ(layers[1], layers[2]->GetNextSibling());
+ ASSERT_EQ(layers[3], layers[1]->GetNextSibling());
+ ASSERT_EQ(nullptr, layers[3]->GetNextSibling());
+
+ parent->RepositionChild(layers[3], nullptr);
+ ValidateTreePointers(layers);
+
+ // 0
+ // 3 2 1
+ ASSERT_EQ(layers[2], layers[3]->GetNextSibling());
+ ASSERT_EQ(layers[1], layers[2]->GetNextSibling());
+ ASSERT_EQ(nullptr, layers[1]->GetNextSibling());
+}
--- a/layout/style/forms.css
+++ b/layout/style/forms.css
@@ -886,26 +886,24 @@ input[type=range]::-moz-range-thumb {
input[type="number"] {
-moz-appearance: number-input;
/* Has to revert some properties applied by the generic input rule. */
-moz-binding: none;
width: 149px; /* to match type=text */
}
-input[type=number] > div, /* work around bug 946184 */
input[type=number]::-moz-number-wrapper {
/* Prevent styling that would change the type of frame we construct. */
display: flex;
float: none !important;
position: static !important;
height: 100%;
}
-input[type=number] > div > input, /* work around bug 946184 */
input[type=number]::-moz-number-text {
-moz-appearance: none;
/* work around autofocus bug 939248 on initial load */
-moz-user-modify: read-write;
/* This pseudo-element is also an 'input' element (nested inside and
* distinct from the <input type=number> element) so we need to prevent the
* explicit setting of 'text-align' by the general CSS rule for 'input'
* above. We want to inherit its value from its <input type=number>
@@ -913,48 +911,45 @@ input[type=number]::-moz-number-text {
*/
text-align: inherit;
flex: 1;
padding: 0;
border: 0;
margin: 0;
}
-input[type=number] > div > div, /* work around bug 946184 */
input[type=number]::-moz-number-spin-box {
display: flex;
flex-direction: column;
%ifdef XP_WIN
/* The Window's Theme's spin buttons have a very narrow minimum width, so
* make it something reasonable:
*/
width: 16px;
%endif
height: 0;
align-self: center;
justify-content: center;
}
-input[type=number] > div > div > div:first-child, /* work around bug 946184 */
input[type=number]::-moz-number-spin-up {
-moz-appearance: spinner-upbutton;
display: block; /* bug 926670 */
flex: none;
cursor: default;
/* Style for when native theming is off: */
background-image: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="6" height="5"><path d="M1,4 L3,0 5,4" fill="dimgrey"/></svg>');
background-repeat: no-repeat;
background-position: center bottom;
border: 1px solid darkgray;
border-bottom: none;
border-top-left-radius: 4px;
border-top-right-radius: 4px;
}
-input[type=number] > div > div > div:not(:first-child), /* work around bug 946184 */
input[type=number]::-moz-number-spin-down {
-moz-appearance: spinner-downbutton;
display: block; /* bug 926670 */
flex: none;
cursor: default;
/* Style for when native theming is off: */
background-image: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="6" height="5"><path d="M1,1 L3,5 5,1" fill="dimgrey"/></svg>');
background-repeat: no-repeat;
--- a/testing/marionette/client/marionette/emulator.py
+++ b/testing/marionette/client/marionette/emulator.py
@@ -18,26 +18,32 @@ import tempfile
import time
import traceback
from emulator_battery import EmulatorBattery
from emulator_geo import EmulatorGeo
from emulator_screen import EmulatorScreen
-class LogcatProc(ProcessHandlerMixin):
- """Process handler for logcat which saves all output to a logfile.
+class LogOutputProc(ProcessHandlerMixin):
+ """
+ Process handler for processes which save all output to a logfile.
+ If no logfile is specified, output will still be consumed to prevent
+ the output pipe's from overflowing.
"""
- def __init__(self, logfile, cmd, **kwargs):
+ def __init__(self, cmd, logfile=None, **kwargs):
self.logfile = logfile
kwargs.setdefault('processOutputLine', []).append(self.log_output)
ProcessHandlerMixin.__init__(self, cmd, **kwargs)
def log_output(self, line):
+ if not self.logfile:
+ return
+
f = open(self.logfile, 'a')
f.write(line + "\n")
f.flush()
class Emulator(object):
deviceRe = re.compile(r"^emulator-(\d+)(\s*)(.*)$")
@@ -312,19 +318,24 @@ waitFor(
if self.copy_userdata:
# Make a copy of the userdata.img for this instance of the emulator to use.
self._tmp_userdata = tempfile.mktemp(prefix='marionette')
shutil.copyfile(self.dataImg, self._tmp_userdata)
qemu_args[qemu_args.index('-data') + 1] = self._tmp_userdata
original_online, original_offline = self._get_adb_devices()
- self.proc = subprocess.Popen(qemu_args,
- stdout=subprocess.PIPE,
- stderr=subprocess.PIPE)
+ filename = None
+ if self.logcat_dir:
+ filename = os.path.join(self.logcat_dir, 'qemu.log')
+ if os.path.isfile(filename):
+ self.rotate_log(filename)
+
+ self.proc = LogOutputProc(qemu_args, filename)
+ self.proc.run()
online, offline = self._get_adb_devices()
now = datetime.datetime.now()
while online - original_online == set([]):
time.sleep(1)
if datetime.datetime.now() - now > datetime.timedelta(seconds=60):
raise Exception('timed out waiting for emulator to start')
online, offline = self._get_adb_devices()
@@ -458,33 +469,39 @@ window.addEventListener('mozbrowserloade
self.dm.pushFile(busybox, remote_file, retryLimit=10)
self._run_adb(['shell', 'cd /system/bin; chmod 555 busybox; for x in `./busybox --list`; do ln -s ./busybox $x; done'])
self.dm._verifyZip()
def rotate_log(self, srclog, index=1):
""" Rotate a logfile, by recursively rotating logs further in the sequence,
deleting the last file if necessary.
"""
- destlog = os.path.join(self.logcat_dir, 'emulator-%d.%d.log' % (self.port, index))
- if os.access(destlog, os.F_OK):
+ basename = os.path.basename(srclog)
+ basename = basename[:-len('.log')]
+ if index > 1:
+ basename = basename[:-len('.1')]
+ basename = '%s.%d.log' % (basename, index)
+
+ destlog = os.path.join(self.logcat_dir, basename)
+ if os.path.isfile(destlog):
if index == 3:
os.remove(destlog)
else:
self.rotate_log(destlog, index+1)
shutil.move(srclog, destlog)
def save_logcat(self):
""" Save the output of logcat to a file.
"""
filename = os.path.join(self.logcat_dir, "emulator-%d.log" % self.port)
- if os.access(filename, os.F_OK):
+ if os.path.isfile(filename):
self.rotate_log(filename)
cmd = [self.adb, '-s', 'emulator-%d' % self.port, 'logcat', '-v', 'threadtime']
- self.logcat_proc = LogcatProc(filename, cmd)
+ self.logcat_proc = LogOutputProc(cmd, filename)
self.logcat_proc.run()
def setup_port_forwarding(self, remote_port):
""" Set up TCP port forwarding to the specified port on the device,
using any availble local port, and return the local port.
"""
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(("",0))
--- a/xpcom/reflect/xptcall/src/md/unix/Makefile.in
+++ b/xpcom/reflect/xptcall/src/md/unix/Makefile.in
@@ -10,19 +10,16 @@
# Linux/ARM
#
ifeq ($(OS_ARCH),Linux)
ifneq (,$(filter arm% sa110,$(OS_TEST)))
CXXFLAGS += -O2
endif
endif
-ifeq ($(OS_TEST),aarch64)
-ASFILES := xptcinvoke_asm_aarch64.s xptcstubs_asm_aarch64.s
-endif
######################################################################
# HPPA
######################################################################
#
# HP-UX/PA32
#
# for gas and gcc, check comment in xptcinvoke_asm_pa32.s
ifeq ($(OS_ARCH),HP-UX)
--- a/xpcom/reflect/xptcall/src/md/unix/moz.build
+++ b/xpcom/reflect/xptcall/src/md/unix/moz.build
@@ -144,21 +144,16 @@ if CONFIG['OS_ARCH'] == 'NetBSD':
if CONFIG['OS_TEST'] in ('amiga', 'atari', 'hp300', 'mac68k', 'mvme68k',
'next68k', 'sun3', 'sun3x', 'x68k'):
SOURCES += [
'xptcinvoke_netbsd_m68k.cpp',
'xptcstubs_netbsd_m68k.cpp'
]
if CONFIG['OS_ARCH'] == 'Linux':
- if CONFIG['OS_TEST'] == 'aarch64':
- SOURCES += [
- 'xptcinvoke_aarch64.cpp',
- 'xptcstubs_aarch64.cpp',
- ]
if CONFIG['OS_TEST'] == 'm68k':
SOURCES += [
'xptcinvoke_linux_m68k.cpp',
'xptcstubs_linux_m68k.cpp',
]
if CONFIG['OS_TEST'].find('mips') != -1:
if CONFIG['OS_TEST'].find('mips64') != -1:
SOURCES += [