Merge mozilla-central to b2g-inbound

This commit is contained in:
Carsten "Tomcat" Book 2014-02-17 13:36:51 +01:00
commit e5c5b4e184
47 changed files with 851 additions and 155 deletions

View File

@ -85,7 +85,7 @@ public:
virtual ~MediaDocumentStreamListener();
void SetStreamListener(nsIStreamListener *aListener);
NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_ISUPPORTS
NS_DECL_NSIREQUESTOBSERVER

View File

@ -60,9 +60,7 @@ void
AudioNodeStream::SetStreamTimeParameterImpl(uint32_t aIndex, MediaStream* aRelativeToStream,
double aStreamTime)
{
TrackTicks ticks =
WebAudioUtils::ConvertDestinationStreamTimeToSourceStreamTime(
aStreamTime, this, aRelativeToStream);
TrackTicks ticks = TicksFromDestinationTime(aRelativeToStream, aStreamTime);
mEngine->SetStreamTimeParameter(aIndex, ticks);
}
@ -517,4 +515,36 @@ AudioNodeStream::FinishOutput()
}
}
TrackTicks
AudioNodeStream::TicksFromDestinationTime(MediaStream* aDestination,
double aSeconds)
{
MOZ_ASSERT(aDestination->AsAudioNodeStream() &&
aDestination->AsAudioNodeStream()->SampleRate() == SampleRate());
double destinationSeconds = std::max(0.0, aSeconds);
StreamTime streamTime = SecondsToMediaTime(destinationSeconds);
// MediaTime does not have the resolution of double
double offset = destinationSeconds - MediaTimeToSeconds(streamTime);
GraphTime graphTime = aDestination->StreamTimeToGraphTime(streamTime);
StreamTime thisStreamTime = GraphTimeToStreamTimeOptimistic(graphTime);
double thisSeconds = MediaTimeToSeconds(thisStreamTime) + offset;
MOZ_ASSERT(thisSeconds >= 0.0);
// Round to nearest
TrackTicks ticks = thisSeconds * SampleRate() + 0.5;
return ticks;
}
double
AudioNodeStream::DestinationTimeFromTicks(AudioNodeStream* aDestination,
TrackTicks aPosition)
{
MOZ_ASSERT(SampleRate() == aDestination->SampleRate());
StreamTime sourceTime = TicksToTimeRoundDown(SampleRate(), aPosition);
GraphTime graphTime = StreamTimeToGraphTime(sourceTime);
StreamTime destinationTime = aDestination->GraphTimeToStreamTimeOptimistic(graphTime);
return MediaTimeToSeconds(destinationTime);
}
}

View File

@ -128,6 +128,19 @@ public:
AudioNodeEngine* Engine() { return mEngine; }
TrackRate SampleRate() const { return mSampleRate; }
/**
* Convert a time in seconds on the destination stream to TrackTicks
* on this stream.
*/
TrackTicks TicksFromDestinationTime(MediaStream* aDestination,
double aSeconds);
/**
* Get the destination stream time in seconds corresponding to a position on
* this stream.
*/
double DestinationTimeFromTicks(AudioNodeStream* aDestination,
TrackTicks aPosition);
protected:
void AdvanceOutputSegment();
void FinishOutput();

View File

@ -314,10 +314,9 @@ private:
// Add the delay caused by the main thread
playbackTick += mSharedBuffers->DelaySoFar();
// Compute the playback time in the coordinate system of the destination
// FIXME: bug 970773
double playbackTime =
WebAudioUtils::StreamPositionToDestinationTime(playbackTick,
mSource,
mDestination);
mSource->DestinationTimeFromTicks(mDestination, playbackTick);
class Command : public nsRunnable
{

View File

@ -23,35 +23,11 @@ struct ConvertTimeToTickHelper
{
ConvertTimeToTickHelper* This = static_cast<ConvertTimeToTickHelper*> (aClosure);
MOZ_ASSERT(This->mSourceStream->SampleRate() == This->mDestinationStream->SampleRate());
return WebAudioUtils::ConvertDestinationStreamTimeToSourceStreamTime(
aTime, This->mSourceStream, This->mDestinationStream);
return This->mSourceStream->
TicksFromDestinationTime(This->mDestinationStream, aTime);
}
};
TrackTicks
WebAudioUtils::ConvertDestinationStreamTimeToSourceStreamTime(double aTime,
AudioNodeStream* aSource,
MediaStream* aDestination)
{
StreamTime streamTime = std::max<MediaTime>(0, SecondsToMediaTime(aTime));
GraphTime graphTime = aDestination->StreamTimeToGraphTime(streamTime);
StreamTime thisStreamTime = aSource->GraphTimeToStreamTimeOptimistic(graphTime);
TrackTicks ticks = TimeToTicksRoundUp(aSource->SampleRate(), thisStreamTime);
return ticks;
}
double
WebAudioUtils::StreamPositionToDestinationTime(TrackTicks aSourcePosition,
AudioNodeStream* aSource,
AudioNodeStream* aDestination)
{
MOZ_ASSERT(aSource->SampleRate() == aDestination->SampleRate());
StreamTime sourceTime = TicksToTimeRoundDown(aSource->SampleRate(), aSourcePosition);
GraphTime graphTime = aSource->StreamTimeToGraphTime(sourceTime);
StreamTime destinationTime = aDestination->GraphTimeToStreamTimeOptimistic(graphTime);
return MediaTimeToSeconds(destinationTime);
}
void
WebAudioUtils::ConvertAudioParamToTicks(AudioParamTimeline& aParam,
AudioNodeStream* aSource,

View File

@ -50,15 +50,6 @@ struct WebAudioUtils {
return 1.0 - std::exp(-1.0 / (aDuration * aSampleRate));
}
/**
* Convert a time in second relative to the destination stream to
* TrackTicks relative to the source stream.
*/
static TrackTicks
ConvertDestinationStreamTimeToSourceStreamTime(double aTime,
AudioNodeStream* aSource,
MediaStream* aDestination);
/**
* Converts AudioParamTimeline floating point time values to tick values
* with respect to a source and a destination AudioNodeStream.
@ -114,14 +105,6 @@ struct WebAudioUtils {
return aTime >= 0 && aTime <= (MEDIA_TIME_MAX >> MEDIA_TIME_FRAC_BITS);
}
/**
* Convert a stream position into the time coordinate of the destination
* stream.
*/
static double StreamPositionToDestinationTime(TrackTicks aSourcePosition,
AudioNodeStream* aSource,
AudioNodeStream* aDestination);
/**
* Converts a floating point value to an integral type in a safe and
* platform agnostic way. The following program demonstrates the kinds

View File

@ -63,6 +63,8 @@ support-files =
[test_bug875221.html]
[test_bug875402.html]
[test_bug894150.html]
[test_bug956489.html]
[test_bug964376.html]
[test_channelMergerNode.html]
[test_channelMergerNodeWithVolume.html]
[test_channelSplitterNode.html]

View File

@ -0,0 +1,55 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Test when and currentTime are in the same coordinate system</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<pre id="test">
<script class="testbody" type="text/javascript">
SimpleTest.waitForExplicitFinish();
addLoadEvent(function() {
var freq = 330;
var context = new AudioContext();
var buffer = context.createBuffer(1, context.sampleRate / freq, context.sampleRate);
for (var i = 0; i < buffer.length; ++i) {
buffer.getChannelData(0)[i] = Math.sin(2 * Math.PI * i / buffer.length);
}
var source = context.createBufferSource();
source.loop = true;
source.buffer = buffer;
setTimeout(function () {
var finished = false;
source.start(context.currentTime);
var processor = context.createScriptProcessor(256, 1, 1);
processor.onaudioprocess = function (e) {
if (finished) return;
var c = e.inputBuffer.getChannelData(0);
var result = true;
for (var i = 0; i < buffer.length; ++i) {
if (Math.abs(c[i] - buffer.getChannelData(0)[i]) > 1e-9) {
result = false;
break;
}
}
finished = true;
ok(result, "when and currentTime are in same time coordinate system");
SimpleTest.finish();
}
processor.connect(context.destination);
source.connect(processor);
}, 500);
});
</script>
</pre>
</body>
</html>

View File

@ -0,0 +1,64 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Test repeating audio is not distorted</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="webaudio.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<pre id="test">
<script class="testbody" type="text/javascript">
function gcd(a, b) {
if (b === 0) {
return a;
}
return gcd(b, a % b);
}
var SAMPLE_PLACEMENT = 128;
var gTest = {
length: 2048,
numberOfChannels: 1,
createGraph: function(context) {
var freq = Math.round(context.sampleRate / SAMPLE_PLACEMENT);
var dur = context.sampleRate / gcd(freq, context.sampleRate);
var buffer = context.createBuffer(1, dur, context.sampleRate);
for (var i = 0; i < context.sampleRate; ++i) {
buffer.getChannelData(0)[i] = Math.sin(freq * 2 * Math.PI * i / context.sampleRate);
}
var source = context.createBufferSource();
source.buffer = buffer;
source.loop = true;
source.playbackRate.setValueAtTime(0.5, SAMPLE_PLACEMENT / context.sampleRate);
source.start(0);
return source;
},
createExpectedBuffers: function(context) {
var freq = Math.round(context.sampleRate / SAMPLE_PLACEMENT);
var expectedBuffer = context.createBuffer(1, 2048, context.sampleRate);
var c = expectedBuffer.getChannelData(0);
for (var i = 0; i < c.length; ++i) {
if (i < SAMPLE_PLACEMENT) {
c[i] = Math.sin(freq * 2 * Math.PI * i / context.sampleRate);
} else {
c[i] = Math.sin(freq / 2 * 2 * Math.PI * (i + SAMPLE_PLACEMENT) / context.sampleRate);
}
}
return expectedBuffer;
},
};
runTest();
</script>
</pre>
</body>
</html>

View File

@ -57,11 +57,11 @@ private:
nsRefPtr<Promise> mPromise;
};
class WorkerPromiseTask MOZ_FINAL : public WorkerRunnable
class WorkerPromiseTask MOZ_FINAL : public WorkerSameThreadRunnable
{
public:
WorkerPromiseTask(WorkerPrivate* aWorkerPrivate, Promise* aPromise)
: WorkerRunnable(aWorkerPrivate, WorkerThreadUnchangedBusyCount)
: WorkerSameThreadRunnable(aWorkerPrivate)
, mPromise(aPromise)
{
MOZ_ASSERT(aPromise);
@ -161,7 +161,7 @@ public:
}
};
class WorkerPromiseResolverTask MOZ_FINAL : public WorkerRunnable,
class WorkerPromiseResolverTask MOZ_FINAL : public WorkerSameThreadRunnable,
public PromiseResolverMixin
{
public:
@ -169,7 +169,7 @@ public:
Promise* aPromise,
JS::Handle<JS::Value> aValue,
Promise::PromiseState aState)
: WorkerRunnable(aWorkerPrivate, WorkerThreadUnchangedBusyCount),
: WorkerSameThreadRunnable(aWorkerPrivate),
PromiseResolverMixin(aPromise, aValue, aState)
{}
@ -832,7 +832,7 @@ Promise::AppendCallbacks(PromiseCallback* aResolveCallback,
WorkerPrivate* worker = GetCurrentThreadWorkerPrivate();
MOZ_ASSERT(worker);
nsRefPtr<WorkerPromiseTask> task = new WorkerPromiseTask(worker, this);
worker->Dispatch(task);
task->Dispatch(worker->GetJSContext());
}
mTaskPending = true;
}
@ -1045,7 +1045,7 @@ Promise::RunResolveTask(JS::Handle<JS::Value> aValue,
MOZ_ASSERT(worker);
nsRefPtr<WorkerPromiseResolverTask> task =
new WorkerPromiseResolverTask(worker, this, aValue, aState);
worker->Dispatch(task);
task->Dispatch(worker->GetJSContext());
}
return;
}

View File

@ -7,10 +7,12 @@
#include "nsIEventTarget.h"
#include "nsIRunnable.h"
#include "nsThreadUtils.h"
#include "mozilla/DebugOnly.h"
#include "js/RootingAPI.h"
#include "js/Value.h"
#include "nsThreadUtils.h"
#include "WorkerPrivate.h"
@ -478,3 +480,43 @@ MainThreadWorkerControlRunnable::PostDispatch(JSContext* aCx,
}
NS_IMPL_ISUPPORTS_INHERITED0(WorkerControlRunnable, WorkerRunnable)
bool
WorkerSameThreadRunnable::PreDispatch(JSContext* aCx,
WorkerPrivate* aWorkerPrivate)
{
aWorkerPrivate->AssertIsOnWorkerThread();
return true;
}
void
WorkerSameThreadRunnable::PostDispatch(JSContext* aCx,
WorkerPrivate* aWorkerPrivate,
bool aDispatchResult)
{
aWorkerPrivate->AssertIsOnWorkerThread();
if (aDispatchResult) {
DebugOnly<bool> willIncrement = aWorkerPrivate->ModifyBusyCountFromWorker(aCx, true);
// Should never fail since if this thread is still running, so should the
// parent and it should be able to process a control runnable.
MOZ_ASSERT(willIncrement);
}
}
void
WorkerSameThreadRunnable::PostRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
bool aRunResult)
{
MOZ_ASSERT(aCx);
MOZ_ASSERT(aWorkerPrivate);
aWorkerPrivate->AssertIsOnWorkerThread();
DebugOnly<bool> willDecrement = aWorkerPrivate->ModifyBusyCountFromWorker(aCx, false);
MOZ_ASSERT(willDecrement);
if (!aRunResult) {
JS_ReportPendingException(aCx);
}
}

View File

@ -314,6 +314,34 @@ protected:
bool aDispatchResult) MOZ_OVERRIDE;
};
// A WorkerRunnable that should be dispatched from the worker to itself for
// async tasks. This will increment the busy count PostDispatch() (only if
// dispatch was successful) and decrement it in PostRun().
//
// Async tasks will almost always want to use this since
// a WorkerSameThreadRunnable keeps the Worker from being GCed.
class WorkerSameThreadRunnable : public WorkerRunnable
{
protected:
WorkerSameThreadRunnable(WorkerPrivate* aWorkerPrivate)
: WorkerRunnable(aWorkerPrivate, WorkerThreadModifyBusyCount)
{ }
virtual ~WorkerSameThreadRunnable()
{ }
virtual bool
PreDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate) MOZ_OVERRIDE;
virtual void
PostDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
bool aDispatchResult) MOZ_OVERRIDE;
virtual void
PostRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
bool aRunResult) MOZ_OVERRIDE;
};
END_WORKERS_NAMESPACE
#endif // mozilla_dom_workers_workerrunnable_h__

View File

@ -1038,6 +1038,12 @@ nsEditorEventListener::ShouldHandleNativeKeyBindings(nsIDOMEvent* aKeyEvent)
return false;
}
nsCOMPtr<nsIDocument> doc = mEditor->GetDocument();
if (doc->HasFlag(NODE_IS_EDITABLE)) {
// Don't need to perform any checks in designMode documents.
return true;
}
nsIContent* editingHost = htmlEditor->GetActiveEditingHost();
if (!editingHost) {
return false;

View File

@ -145,6 +145,8 @@ skip-if = toolkit == 'android'
[test_bug796839.html]
[test_bug832025.html]
[test_bug857487.html]
[test_bug966155.html]
skip-if = os != "win"
[test_bug966552.html]
skip-if = os != "win"
[test_contenteditable_focus.html]

View File

@ -0,0 +1,57 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=966155
-->
<head>
<title>Test for Bug 966155</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=966155">Mozilla Bug 966155</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script class="testbody" type="text/javascript">
SimpleTest.waitForExplicitFinish();
addLoadEvent(function() {
var win = window.open("data:text/html,<input><iframe onload=\"contentDocument.designMode = 'on';\">", "", "test-966155");
win.addEventListener("load", function onLoad() {
win.removeEventListener("load", onLoad);
runTest(win);
}, false);
});
function runTest(win) {
SimpleTest.waitForFocus(function() {
var doc = win.document;
var iframe = doc.querySelector("iframe");
var iframeDoc = iframe.contentDocument;
var input = doc.querySelector("input");
iframe.focus();
iframeDoc.body.focus();
// Type some text
"test".split("").forEach(function(letter) {
synthesizeKey(letter, {}, win);
});
is(iframeDoc.body.textContent, "test", "entered the text");
// focus the input box
input.focus();
// press tab
synthesizeKey("VK_TAB", {}, win);
// Now press Ctrl+Backspace
synthesizeKey("VK_BACK_SPACE", {ctrlKey: true}, win);
is(iframeDoc.body.textContent, "", "deleted the text");
win.close();
SimpleTest.finish();
}, win);
}
</script>
</pre>
</body>
</html>

View File

@ -10,7 +10,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=966552
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=966552">Mozilla Bug 289384</a>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=966552">Mozilla Bug 966552</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>

View File

@ -380,7 +380,7 @@ GrallocImage::GetAsSourceSurface()
TextureClient*
GrallocImage::GetTextureClient()
GrallocImage::GetTextureClient(CompositableClient* aClient)
{
if (!mTextureClient) {
const SurfaceDescriptor& sd = GetSurfaceDescriptor();

View File

@ -149,7 +149,7 @@ public:
virtual ISharedImage* AsSharedImage() MOZ_OVERRIDE { return this; }
virtual TextureClient* GetTextureClient() MOZ_OVERRIDE;
virtual TextureClient* GetTextureClient(CompositableClient* aClient) MOZ_OVERRIDE;
virtual uint8_t* GetBuffer()
{

View File

@ -22,6 +22,7 @@
#include "GrallocImages.h"
#endif
#include "gfx2DGlue.h"
#include "mozilla/gfx/2D.h"
#ifdef XP_MACOSX
#include "mozilla/gfx/QuartzSupport.h"
@ -38,15 +39,12 @@
using namespace mozilla::ipc;
using namespace android;
using mozilla::gfx::DataSourceSurface;
using mozilla::gfx::SourceSurface;
using namespace mozilla::gfx;
namespace mozilla {
namespace layers {
class DataSourceSurface;
class SourceSurface;
Atomic<int32_t> Image::sSerialCounter(0);
@ -711,5 +709,45 @@ RemoteBitmapImage::GetAsSourceSurface()
return newSurf;
}
CairoImage::CairoImage()
: Image(nullptr, ImageFormat::CAIRO_SURFACE)
{}
CairoImage::~CairoImage()
{
}
TextureClient*
CairoImage::GetTextureClient(CompositableClient *aClient)
{
CompositableForwarder* forwarder = aClient->GetForwarder();
RefPtr<TextureClient> textureClient = mTextureClients.Get(forwarder->GetSerial());
if (textureClient) {
return textureClient;
}
RefPtr<SourceSurface> surface = GetAsSourceSurface();
MOZ_ASSERT(surface);
textureClient = aClient->CreateTextureClientForDrawing(surface->GetFormat(),
TEXTURE_FLAGS_DEFAULT);
MOZ_ASSERT(textureClient->AsTextureClientDrawTarget());
if (!textureClient->AsTextureClientDrawTarget()->AllocateForSurface(surface->GetSize()) ||
!textureClient->Lock(OPEN_WRITE_ONLY)) {
return nullptr;
}
{
// We must not keep a reference to the DrawTarget after it has been unlocked.
RefPtr<DrawTarget> dt = textureClient->AsTextureClientDrawTarget()->GetAsDrawTarget();
dt->CopySurface(surface, IntRect(IntPoint(), surface->GetSize()), IntPoint());
}
textureClient->Unlock();
mTextureClients.Put(forwarder->GetSerial(), textureClient);
return textureClient;
}
} // namespace
} // namespace

View File

@ -28,6 +28,7 @@
#include "mozilla/Atomics.h"
#include "nsThreadUtils.h"
#include "mozilla/gfx/2D.h"
#include "nsDataHashtable.h"
#ifndef XPCOM_GLUE_AVOID_NSPR
/**
@ -146,6 +147,8 @@ class ImageClient;
class SharedPlanarYCbCrImage;
class DeprecatedSharedPlanarYCbCrImage;
class TextureClient;
class CompositableClient;
class CompositableForwarder;
class SurfaceDescriptor;
struct ImageBackendData
@ -165,7 +168,7 @@ public:
* For use with the CompositableClient only (so that the later can
* synchronize the TextureClient with the TextureHost).
*/
virtual TextureClient* GetTextureClient() = 0;
virtual TextureClient* GetTextureClient(CompositableClient* aClient) = 0;
};
/**
@ -905,7 +908,8 @@ protected:
* device output color space. This class is very simple as all backends
* have to know about how to deal with drawing a cairo image.
*/
class CairoImage : public Image {
class CairoImage : public Image,
public ISharedImage {
public:
struct Data {
gfxASurface* mDeprecatedSurface;
@ -939,9 +943,14 @@ public:
return surface.forget();
}
virtual ISharedImage* AsSharedImage() { return this; }
virtual uint8_t* GetBuffer() { return nullptr; }
virtual TextureClient* GetTextureClient(CompositableClient* aClient);
gfx::IntSize GetSize() { return mSize; }
CairoImage() : Image(nullptr, ImageFormat::CAIRO_SURFACE) {}
CairoImage();
~CairoImage();
nsCountedRef<nsMainThreadSurfaceRef> mDeprecatedSurface;
gfx::IntSize mSize;
@ -949,6 +958,7 @@ public:
// mSourceSurface wraps mDeprrecatedSurface's data, therefore it should not
// outlive mDeprecatedSurface
nsCountedRef<nsMainThreadSourceSurfaceRef> mSourceSurface;
nsDataHashtable<nsUint32HashKey, RefPtr<TextureClient> > mTextureClients;
};
class RemoteBitmapImage : public Image {

View File

@ -10,7 +10,7 @@ using namespace mozilla;
using namespace mozilla::layers;
TextureClient*
MacIOSurfaceImage::GetTextureClient()
MacIOSurfaceImage::GetTextureClient(CompositableClient* aClient)
{
if (!mTextureClient) {
RefPtr<MacIOSurfaceTextureClientOGL> buffer =

View File

@ -51,7 +51,7 @@ public:
virtual TemporaryRef<gfx::SourceSurface> GetAsSourceSurface();
virtual TextureClient* GetTextureClient() MOZ_OVERRIDE;
virtual TextureClient* GetTextureClient(CompositableClient* aClient) MOZ_OVERRIDE;
virtual uint8_t* GetBuffer() MOZ_OVERRIDE { return nullptr; }
MacIOSurfaceImage() : Image(nullptr, ImageFormat::MAC_IOSURFACE) {}

View File

@ -145,9 +145,9 @@ ImageClientSingle::UpdateImageInternal(ImageContainer* aContainer,
return true;
}
if (image->AsSharedImage() && image->AsSharedImage()->GetTextureClient()) {
if (image->AsSharedImage() && image->AsSharedImage()->GetTextureClient(this)) {
// fast path: no need to allocate and/or copy image data
RefPtr<TextureClient> texture = image->AsSharedImage()->GetTextureClient();
RefPtr<TextureClient> texture = image->AsSharedImage()->GetTextureClient(this);
if (mFrontBuffer) {

View File

@ -265,7 +265,6 @@ public:
aLayer == mLayer ||
aFlags & FORCE_DETACH) {
SetLayer(nullptr);
SetCompositor(nullptr);
mAttached = false;
mKeepAttached = false;
if (mBackendData) {

View File

@ -48,7 +48,8 @@ class CompositableForwarder : public ISurfaceAllocator
public:
CompositableForwarder()
: mMultiProcess(false)
: mSerial(++sSerialCounter)
, mMultiProcess(false)
{}
/**
@ -246,10 +247,14 @@ public:
return mTextureFactoryIdentifier;
}
int32_t GetSerial() { return mSerial; }
protected:
TextureFactoryIdentifier mTextureFactoryIdentifier;
bool mMultiProcess;
nsTArray<RefPtr<TextureClient> > mTexturesToRemove;
const int32_t mSerial;
static mozilla::Atomic<int32_t> sSerialCounter;
bool mMultiProcess;
};
} // namespace

View File

@ -28,6 +28,8 @@ namespace layers {
/*static*/ CompositorChild* CompositorChild::sCompositor;
Atomic<int32_t> CompositableForwarder::sSerialCounter(0);
CompositorChild::CompositorChild(ClientLayerManager *aLayerManager)
: mLayerManager(aLayerManager)
{

View File

@ -63,7 +63,7 @@ DeprecatedSharedPlanarYCbCrImage::~DeprecatedSharedPlanarYCbCrImage() {
}
TextureClient*
SharedPlanarYCbCrImage::GetTextureClient()
SharedPlanarYCbCrImage::GetTextureClient(CompositableClient* aClient)
{
return mTextureClient.get();
}

View File

@ -97,7 +97,7 @@ public:
~SharedPlanarYCbCrImage();
virtual ISharedImage* AsSharedImage() MOZ_OVERRIDE { return this; }
virtual TextureClient* GetTextureClient() MOZ_OVERRIDE;
virtual TextureClient* GetTextureClient(CompositableClient* aClient) MOZ_OVERRIDE;
virtual uint8_t* GetBuffer() MOZ_OVERRIDE;
virtual already_AddRefed<gfxASurface> DeprecatedGetAsSurface() MOZ_OVERRIDE;

View File

@ -234,7 +234,7 @@ SharedRGBImage::GetBufferSize()
}
TextureClient*
SharedRGBImage::GetTextureClient()
SharedRGBImage::GetTextureClient(CompositableClient* aClient)
{
return mTextureClient.get();
}

View File

@ -86,7 +86,7 @@ public:
bool AllocateBuffer(nsIntSize aSize, gfxImageFormat aImageFormat);
TextureClient* GetTextureClient() MOZ_OVERRIDE { return nullptr; }
TextureClient* GetTextureClient(CompositableClient* aClient) MOZ_OVERRIDE { return nullptr; }
protected:
gfx::IntSize mSize;
@ -110,7 +110,7 @@ public:
virtual ISharedImage* AsSharedImage() MOZ_OVERRIDE { return this; }
virtual TextureClient* GetTextureClient() MOZ_OVERRIDE;
virtual TextureClient* GetTextureClient(CompositableClient* aClient) MOZ_OVERRIDE;
virtual uint8_t* GetBuffer() MOZ_OVERRIDE;

View File

@ -81,7 +81,8 @@ gfxFT2LockedFace::GetMetrics(gfxFont::Metrics* aMetrics,
gfxFloat emHeight;
// Scale for vertical design metric conversion: pixels per design unit.
gfxFloat yScale;
// If this remains at 0.0, we can't use metrics from OS/2 etc.
gfxFloat yScale = 0.0;
if (FT_IS_SCALABLE(mFace)) {
// Prefer FT_Size_Metrics::x_scale to x_ppem as x_ppem does not
// have subpixel accuracy.
@ -93,11 +94,17 @@ gfxFT2LockedFace::GetMetrics(gfxFont::Metrics* aMetrics,
yScale = FLOAT_FROM_26_6(FLOAT_FROM_16_16(ftMetrics.y_scale));
emHeight = mFace->units_per_EM * yScale;
} else { // Not scalable.
// FT_Size_Metrics doc says x_scale is "only relevant for scalable
// font formats".
gfxFloat emUnit = mFace->units_per_EM;
emHeight = ftMetrics.y_ppem;
yScale = emHeight / emUnit;
// FT_Face doc says units_per_EM and a bunch of following fields
// are "only relevant to scalable outlines". If it's an sfnt,
// we can get units_per_EM from the 'head' table instead; otherwise,
// we don't have a unitsPerEm value so we can't compute/use yScale.
const TT_Header* head =
static_cast<TT_Header*>(FT_Get_Sfnt_Table(mFace, ft_sfnt_head));
if (head) {
gfxFloat emUnit = head->Units_Per_EM;
emHeight = ftMetrics.y_ppem;
yScale = emHeight / emUnit;
}
}
TT_OS2 *os2 =
@ -108,7 +115,7 @@ gfxFT2LockedFace::GetMetrics(gfxFont::Metrics* aMetrics,
aMetrics->maxAdvance = FLOAT_FROM_26_6(ftMetrics.max_advance);
gfxFloat lineHeight;
if (os2 && os2->sTypoAscender) {
if (os2 && os2->sTypoAscender && yScale > 0.0) {
aMetrics->emAscent = os2->sTypoAscender * yScale;
aMetrics->emDescent = -os2->sTypoDescender * yScale;
FT_Short typoHeight =
@ -150,7 +157,7 @@ gfxFT2LockedFace::GetMetrics(gfxFont::Metrics* aMetrics,
aMetrics->xHeight = -extents.y_bearing;
aMetrics->aveCharWidth = extents.x_advance;
} else {
if (os2 && os2->sxHeight) {
if (os2 && os2->sxHeight && yScale > 0.0) {
aMetrics->xHeight = os2->sxHeight * yScale;
} else {
// CSS 2.1, section 4.3.2 Lengths: "In the cases where it is
@ -195,7 +202,7 @@ gfxFT2LockedFace::GetMetrics(gfxFont::Metrics* aMetrics,
// Therefore get the underline position directly from the table
// ourselves when this table exists. Use FreeType's metrics for
// other (including older PostScript) fonts.
if (mFace->underline_position && mFace->underline_thickness) {
if (mFace->underline_position && mFace->underline_thickness && yScale > 0.0) {
aMetrics->underlineSize = mFace->underline_thickness * yScale;
TT_Postscript *post = static_cast<TT_Postscript*>
(FT_Get_Sfnt_Table(mFace, ft_sfnt_post));
@ -211,7 +218,7 @@ gfxFT2LockedFace::GetMetrics(gfxFont::Metrics* aMetrics,
aMetrics->underlineOffset = -aMetrics->underlineSize;
}
if (os2 && os2->yStrikeoutSize && os2->yStrikeoutPosition) {
if (os2 && os2->yStrikeoutSize && os2->yStrikeoutPosition && yScale > 0.0) {
aMetrics->strikeoutSize = os2->yStrikeoutSize * yScale;
aMetrics->strikeoutOffset = os2->yStrikeoutPosition * yScale;
} else { // No strikeout info.

View File

@ -575,10 +575,8 @@ GetOutlineInnerRect(nsIFrame* aFrame)
(aFrame->Properties().Get(nsIFrame::OutlineInnerRectProperty()));
if (savedOutlineInnerRect)
return *savedOutlineInnerRect;
// FIXME (bug 599652): We probably want something narrower than either
// overflow rect here, but for now use the visual overflow in order to
// be consistent with ComputeEffectsRect in nsFrame.cpp.
return aFrame->GetVisualOverflowRect();
NS_NOTREACHED("we should have saved a frame property");
return nsRect(nsPoint(0, 0), aFrame->GetSize());
}
void
@ -608,37 +606,22 @@ nsCSSRendering::PaintOutline(nsPresContext* aPresContext,
nscolor bgColor =
bgContext->GetVisitedDependentColor(eCSSProperty_background_color);
// When the outline property is set on :-moz-anonymous-block or
// :-moz-anonyomus-positioned-block pseudo-elements, it inherited that
// outline from the inline that was broken because it contained a
// block. In that case, we don't want a really wide outline if the
// block inside the inline is narrow, so union the actual contents of
// the anonymous blocks.
nsIFrame *frameForArea = aForFrame;
do {
nsIAtom *pseudoType = frameForArea->StyleContext()->GetPseudo();
if (pseudoType != nsCSSAnonBoxes::mozAnonymousBlock &&
pseudoType != nsCSSAnonBoxes::mozAnonymousPositionedBlock)
break;
// If we're done, we really want it and all its later siblings.
frameForArea = frameForArea->GetFirstPrincipalChild();
NS_ASSERTION(frameForArea, "anonymous block with no children?");
} while (frameForArea);
nsRect innerRect; // relative to aBorderArea.TopLeft()
if (frameForArea == aForFrame) {
innerRect = GetOutlineInnerRect(aForFrame);
nsRect innerRect;
if (
#ifdef MOZ_XUL
aStyleContext->GetPseudoType() == nsCSSPseudoElements::ePseudo_XULTree
#else
false
#endif
) {
// FIXME: This behavior doesn't make sense; we should switch back to
// using aBorderArea. But since this has been broken since bug
// 133165 in August of 2004, that switch should be made in its own
// patch changing only that behavior.
innerRect = aForFrame->GetVisualOverflowRect();
} else {
for (; frameForArea; frameForArea = frameForArea->GetNextSibling()) {
// The outline has already been included in aForFrame's overflow
// area, but not in those of its descendants, so we have to
// include it. Otherwise we'll end up drawing the outline inside
// the border.
nsRect r(GetOutlineInnerRect(frameForArea) +
frameForArea->GetOffsetTo(aForFrame));
innerRect.UnionRect(innerRect, r);
}
innerRect = GetOutlineInnerRect(aForFrame);
}
innerRect += aBorderArea.TopLeft();
nscoord offset = ourOutline->mOutlineOffset;
innerRect.Inflate(offset, offset);

View File

@ -1639,7 +1639,7 @@ nsLayoutUtils::ChangeMatrixBasis(const gfxPoint3D &aOrigin,
*
* @param aVal The value to constrain (in/out)
*/
static void ConstrainToCoordValues(gfxFloat &aVal)
static void ConstrainToCoordValues(gfxFloat& aVal)
{
if (aVal <= nscoord_MIN)
aVal = nscoord_MIN;
@ -1647,6 +1647,32 @@ static void ConstrainToCoordValues(gfxFloat &aVal)
aVal = nscoord_MAX;
}
static void ConstrainToCoordValues(gfxFloat& aStart, gfxFloat& aSize)
{
gfxFloat max = aStart + aSize;
// Clamp the end points to within nscoord range
ConstrainToCoordValues(aStart);
ConstrainToCoordValues(max);
aSize = max - aStart;
// If the width if still greater than the max nscoord, then bring both
// endpoints in by the same amount until it fits.
if (aSize > nscoord_MAX) {
gfxFloat excess = aSize - nscoord_MAX;
excess /= 2;
aStart += excess;
aSize = nscoord_MAX;
} else if (aSize < nscoord_MIN) {
gfxFloat excess = aSize - nscoord_MIN;
excess /= 2;
aStart -= excess;
aSize = nscoord_MIN;
}
}
nsRect
nsLayoutUtils::RoundGfxRectToAppRect(const gfxRect &aRect, float aFactor)
{
@ -1655,10 +1681,8 @@ nsLayoutUtils::RoundGfxRectToAppRect(const gfxRect &aRect, float aFactor)
scaledRect.ScaleRoundOut(aFactor);
/* We now need to constrain our results to the max and min values for coords. */
ConstrainToCoordValues(scaledRect.x);
ConstrainToCoordValues(scaledRect.y);
ConstrainToCoordValues(scaledRect.width);
ConstrainToCoordValues(scaledRect.height);
ConstrainToCoordValues(scaledRect.x, scaledRect.width);
ConstrainToCoordValues(scaledRect.y, scaledRect.height);
/* Now typecast everything back. This is guaranteed to be safe. */
return nsRect(nscoord(scaledRect.X()), nscoord(scaledRect.Y()),

View File

@ -4976,27 +4976,6 @@ ComputeEffectsRect(nsIFrame* aFrame, const nsRect& aOverflowRect,
// box-shadow
r.UnionRect(r, nsLayoutUtils::GetBoxShadowRectForFrame(aFrame, aNewSize));
const nsStyleOutline* outline = aFrame->StyleOutline();
uint8_t outlineStyle = outline->GetOutlineStyle();
if (outlineStyle != NS_STYLE_BORDER_STYLE_NONE) {
nscoord width;
DebugOnly<bool> result = outline->GetOutlineWidth(width);
NS_ASSERTION(result, "GetOutlineWidth had no cached outline width");
if (width > 0) {
aFrame->Properties().
Set(nsIFrame::OutlineInnerRectProperty(), new nsRect(r));
nscoord offset = outline->mOutlineOffset;
nscoord inflateBy = std::max(width + offset, 0);
// FIXME (bug 599652): We probably want outline to be drawn around
// something smaller than the visual overflow rect (perhaps the
// scrollable overflow rect is correct). When we change that, we
// need to keep this code (and the storing of properties just
// above) in sync with GetOutlineInnerRect in nsCSSRendering.cpp.
r.Inflate(inflateBy, inflateBy);
}
}
// border-image-outset.
// We need to include border-image-outset because it can cause the
// border image to be drawn beyond the border box.
@ -6854,6 +6833,185 @@ IsInlineFrame(nsIFrame *aFrame)
return type == nsGkAtoms::inlineFrame;
}
/**
* Compute the union of the border boxes of aFrame and its descendants,
* in aFrame's coordinate space (if aApplyTransform is false) or its
* post-transform coordinate space (if aApplyTransform is true).
*/
static nsRect
UnionBorderBoxes(nsIFrame* aFrame, bool aApplyTransform,
const nsSize* aSizeOverride = nullptr,
const nsOverflowAreas* aOverflowOverride = nullptr)
{
const nsRect bounds(nsPoint(0, 0),
aSizeOverride ? *aSizeOverride : aFrame->GetSize());
// Start from our border-box, transformed. See comment below about
// transform of children.
nsRect u;
bool doTransform = aApplyTransform && aFrame->IsTransformed();
if (doTransform) {
u = nsDisplayTransform::TransformRect(bounds, aFrame,
nsPoint(0, 0), &bounds);
} else {
u = bounds;
}
// Only iterate through the children if the overflow areas suggest
// that we might need to, and if the frame doesn't clip its overflow
// anyway.
if (aOverflowOverride) {
if (!doTransform &&
bounds.IsEqualEdges(aOverflowOverride->VisualOverflow()) &&
bounds.IsEqualEdges(aOverflowOverride->ScrollableOverflow())) {
return u;
}
} else {
if (!doTransform &&
bounds.IsEqualEdges(aFrame->GetVisualOverflowRect()) &&
bounds.IsEqualEdges(aFrame->GetScrollableOverflowRect())) {
return u;
}
}
const nsStyleDisplay* disp = aFrame->StyleDisplay();
nsIAtom* fType = aFrame->GetType();
if (nsFrame::ShouldApplyOverflowClipping(aFrame, disp) ||
fType == nsGkAtoms::scrollFrame ||
fType == nsGkAtoms::svgOuterSVGFrame) {
return u;
}
nsRect clipPropClipRect;
bool hasClipPropClip =
aFrame->GetClipPropClipRect(disp, &clipPropClipRect, bounds.Size());
// Iterate over all children except pop-ups.
const nsIFrame::ChildListIDs skip(nsIFrame::kPopupList |
nsIFrame::kSelectPopupList);
for (nsIFrame::ChildListIterator childLists(aFrame);
!childLists.IsDone(); childLists.Next()) {
if (skip.Contains(childLists.CurrentID())) {
continue;
}
nsFrameList children = childLists.CurrentList();
for (nsFrameList::Enumerator e(children); !e.AtEnd(); e.Next()) {
nsIFrame* child = e.get();
// Note that passing |true| for aApplyTransform when
// child->Preserves3D() is incorrect if our aApplyTransform is
// false... but the opposite would be as well. This is because
// elements within a preserve-3d scene are always transformed up
// to the top of the scene. This means we don't have a
// mechanism for getting a transform up to an intermediate point
// within the scene. We choose to over-transform rather than
// under-transform because this is consistent with other
// overflow areas.
nsRect childRect = UnionBorderBoxes(child, true) +
child->GetPosition();
if (hasClipPropClip) {
// Intersect with the clip before transforming.
childRect.IntersectRect(childRect, clipPropClipRect);
}
// Note that we transform each child separately according to
// aFrame's transform, and then union, which gives a different
// (smaller) result from unioning and then transforming the
// union. This doesn't match the way we handle overflow areas
// with 2-D transforms, though it does match the way we handle
// overflow areas in preserve-3d 3-D scenes.
if (doTransform && !child->Preserves3D()) {
childRect = nsDisplayTransform::TransformRect(childRect, aFrame,
nsPoint(0, 0), &bounds);
}
u.UnionRectEdges(u, childRect);
}
}
return u;
}
static void
ComputeAndIncludeOutlineArea(nsIFrame* aFrame, nsOverflowAreas& aOverflowAreas,
const nsSize& aNewSize)
{
const nsStyleOutline* outline = aFrame->StyleOutline();
if (outline->GetOutlineStyle() == NS_STYLE_BORDER_STYLE_NONE) {
return;
}
nscoord width;
DebugOnly<bool> result = outline->GetOutlineWidth(width);
NS_ASSERTION(result, "GetOutlineWidth had no cached outline width");
if (width <= 0) {
return;
}
// When the outline property is set on :-moz-anonymous-block or
// :-moz-anonymous-positioned-block pseudo-elements, it inherited
// that outline from the inline that was broken because it
// contained a block. In that case, we don't want a really wide
// outline if the block inside the inline is narrow, so union the
// actual contents of the anonymous blocks.
nsIFrame *frameForArea = aFrame;
do {
nsIAtom *pseudoType = frameForArea->StyleContext()->GetPseudo();
if (pseudoType != nsCSSAnonBoxes::mozAnonymousBlock &&
pseudoType != nsCSSAnonBoxes::mozAnonymousPositionedBlock)
break;
// If we're done, we really want it and all its later siblings.
frameForArea = frameForArea->GetFirstPrincipalChild();
NS_ASSERTION(frameForArea, "anonymous block with no children?");
} while (frameForArea);
// Find the union of the border boxes of all descendants, or in
// the block-in-inline case, all descendants we care about.
//
// Note that the interesting perspective-related cases are taken
// care of by the code that handles those issues for overflow
// calling FinishAndStoreOverflow again, which in turn calls this
// function again. We still need to deal with preserve-3d a bit.
nsRect innerRect;
if (frameForArea == aFrame) {
innerRect = UnionBorderBoxes(aFrame, false, &aNewSize, &aOverflowAreas);
} else {
for (; frameForArea; frameForArea = frameForArea->GetNextSibling()) {
nsRect r(UnionBorderBoxes(frameForArea, true));
// Adjust for offsets transforms up to aFrame's pre-transform
// (i.e., normal) coordinate space; see comments in
// UnionBorderBoxes for some of the subtlety here.
for (nsIFrame *f = frameForArea, *parent = f->GetParent();
/* see middle of loop */;
f = parent, parent = f->GetParent()) {
r += f->GetPosition();
if (parent == aFrame) {
break;
}
if (parent->IsTransformed() && !f->Preserves3D()) {
r = nsDisplayTransform::TransformRect(r, parent, nsPoint(0, 0));
}
}
innerRect.UnionRect(innerRect, r);
}
}
aFrame->Properties().Set(nsIFrame::OutlineInnerRectProperty(),
new nsRect(innerRect));
nscoord offset = outline->mOutlineOffset;
nscoord inflateBy = std::max(width + offset, 0);
// Keep this code (and the storing of properties just above) in
// sync with GetOutlineInnerRect in nsCSSRendering.cpp.
nsRect outerRect(innerRect);
outerRect.Inflate(inflateBy, inflateBy);
nsRect& vo = aOverflowAreas.VisualOverflow();
vo.UnionRectEdges(vo, outerRect);
}
bool
nsIFrame::FinishAndStoreOverflow(nsOverflowAreas& aOverflowAreas,
nsSize aNewSize, nsSize* aOldSize)
@ -6933,6 +7091,8 @@ nsIFrame::FinishAndStoreOverflow(nsOverflowAreas& aOverflowAreas,
}
}
ComputeAndIncludeOutlineArea(this, aOverflowAreas, aNewSize);
// Nothing in here should affect scrollable overflow.
aOverflowAreas.VisualOverflow() =
ComputeEffectsRect(this, aOverflowAreas.VisualOverflow(), aNewSize);

View File

@ -0,0 +1,28 @@
<!DOCTYPE HTML>
<title>Testcase for outline around 3-D transform</title>
<style>
html, body { margin: 0; padding: 0; border: none }
div {
width: 100px;
height: 100px;
}
body > div {
margin-top: 200px;
margin-left: 200px;
transform-style: flat;
position: relative;
}
body > div > div {
position: absolute; top: 0; left: 0;
height: 150px; width: 150px; top: -25px; left: -25px;
background: rgba(255, 255, 0, 0.4);
outline: 2px dashed blue;
}
</style>
<div><div></div></div>

View File

@ -0,0 +1,40 @@
<!DOCTYPE HTML>
<title>Testcase for outline around 3-D transform</title>
<style>
html, body { margin: 0; padding: 0; border: none }
div {
width: 100px;
height: 100px;
}
body > div {
margin-top: 200px;
margin-left: 200px;
transform-style: flat;
outline: 2px dashed blue;
}
body > div > div {
transform: rotateX(30deg);
transform-origin: 50% 50%;
transform-style: preserve-3d;
}
body > div > div > div {
transform: rotateX(30deg);
transform-origin: 50% 50%;
transform-style: preserve-3d;
}
body > div > div > div > div {
transform: scale(1.5, 3);
transform-origin: 50% 50%;
background: rgba(255, 255, 0, 0.4);
}
</style>
<div><div><div><div></div></div></div></div>

View File

@ -0,0 +1,40 @@
<!DOCTYPE HTML>
<title>Testcase for outline around 3-D transform</title>
<style>
html, body { margin: 0; padding: 0; border: none }
div {
width: 100px;
height: 100px;
}
body > div {
margin-top: 200px;
margin-left: 200px;
transform-style: flat;
outline: 2px dashed blue;
}
body > div > div {
transform: rotateX(90deg);
transform-origin: 50% 50%;
transform-style: preserve-3d;
}
body > div > div > div {
transform: rotateX(-30deg);
transform-origin: 50% 50%;
transform-style: preserve-3d;
}
body > div > div > div > div {
transform: scale(1.5, 3);
transform-origin: 50% 50%;
background: rgba(255, 255, 0, 0.4);
}
</style>
<div><div><div><div></div></div></div></div>

View File

@ -0,0 +1,36 @@
<!DOCTYPE HTML>
<title>Testcase for outline around 3-D transform</title>
<style>
html, body { margin: 0; padding: 0; border: none }
div {
width: 100px;
height: 100px;
}
body > div {
margin-top: 200px;
margin-left: 200px;
transform-style: flat;
}
body > div > div {
transform: rotateX(30deg);
transform-origin: 50% 50%;
transform-style: preserve-3d;
border: 5px solid green;
margin: -5px;
}
body > div > div > div {
transform: rotateX(30deg);
width: 50px; margin-left: 20px; margin-top: -5px;
transform-origin: 50% 50%;
transform-style: preserve-3d;
border: 5px solid blue;
}
</style>
<div><div><div></div></div></div>

View File

@ -0,0 +1,35 @@
<!DOCTYPE HTML>
<title>Testcase for outline around 3-D transform</title>
<style>
html, body { margin: 0; padding: 0; border: none }
div {
width: 100px;
height: 100px;
}
body > div {
margin-top: 200px;
margin-left: 200px;
transform-style: flat;
}
body > div > div {
transform: rotateX(30deg);
transform-origin: 50% 50%;
transform-style: preserve-3d;
outline: 5px solid green;
}
body > div > div > div {
transform: rotateX(30deg);
width: 50px; margin-left: 25px;
transform-origin: 50% 50%;
transform-style: preserve-3d;
outline: 5px solid blue;
}
</style>
<div><div><div></div></div></div>

View File

@ -0,0 +1,13 @@
<!DOCTYPE HTML>
<title>outline and box-shadow</title>
<style>
html, body { margin: 0; padding: 0 }
p {
margin: 48px;
border: 2px solid blue;
padding: 5px; /* ensure no font overhang */
background: yellow; color: black;
box-shadow: 10px 10px 10px 0px black;
}
</style>
<p>The outline should be adjacent to the background.</p>

View File

@ -0,0 +1,13 @@
<!DOCTYPE HTML>
<title>outline and box-shadow</title>
<style>
html, body { margin: 0; padding: 0 }
p {
margin: 50px;
outline: 2px solid blue;
padding: 5px; /* ensure no font overhang */
background: yellow; color: black;
box-shadow: 10px 10px 10px 2px black;
}
</style>
<p>The outline should be adjacent to the background.</p>

View File

@ -0,0 +1,4 @@
== outline-and-box-shadow.html outline-and-box-shadow-ref.html
== outline-and-3d-transform-1a.html outline-and-3d-transform-1-ref.html
== outline-and-3d-transform-1b.html outline-and-3d-transform-1-ref.html
== outline-and-3d-transform-2.html outline-and-3d-transform-2-ref.html

View File

@ -219,6 +219,8 @@ skip-if(Android||B2G) include native-theme/reftest.list
# netwerk/
skip-if(B2G) include ../../netwerk/test/reftest/reftest.list
include outline/reftest.list
# object/
skip-if(B2G) include object/reftest.list

View File

@ -1543,7 +1543,7 @@ nsStyleGradient::HasCalc()
return true;
}
return mBgPosX.IsCalcUnit() || mBgPosY.IsCalcUnit() || mAngle.IsCalcUnit() ||
mRadiusX.IsCalcUnit() || mRadiusX.IsCalcUnit();
mRadiusX.IsCalcUnit() || mRadiusY.IsCalcUnit();
}
// --------------------

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- -*- Mode: HTML; tab-width: 4; indent-tabs-mode: nil; -*- -->
<!-- vim: set shiftwidth=4 tabstop=4 autoindent noexpandtab: -->
<!-- -*- Mode: HTML; tab-width: 2; indent-tabs-mode: nil; -*- -->
<!-- vim: set shiftwidth=2 tabstop=2 autoindent expandtab: -->
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
@ -179,7 +179,7 @@ function fileentry_changed() {
var log = null;
log = e.target.result;
if (log)
process_log(log);
else
@ -217,7 +217,7 @@ function process_log(contents) {
var state = match[1];
var random = match[2];
var url = match[3];
var extra = match[4];
var extra = match[4];
gTestItems.push(
{
pass: !state.match(/DEBUG-INFO$|FAIL$/),

View File

@ -1655,7 +1655,7 @@ function RecordResult(testRunTime, errorMsg, scriptResults)
result += "REFTEST IMAGE 2 (REFERENCE): " + gCanvas2.toDataURL() + "\n";
} else {
result += "\n";
gDumpLog("REFTEST IMAGE: " + gCanvas1.toDataURL() + "\n");
result += "REFTEST IMAGE: " + gCanvas1.toDataURL() + "\n";
}
} else {
result += "\n";

View File

@ -19,7 +19,7 @@ def format_char(c):
return "\\"
elif c == 0x22:
return "\\\""
elif c == 0x39:
elif c == 0x27:
return "\\'"
elif c < 0x20 or c >= 0x80 and c <= 0xff:
return "\\x%02x" % c