Merge mozilla-central to build-system.

This commit is contained in:
Siddharth Agarwal 2012-09-04 21:16:02 +05:30
commit 08bf89ab6c
126 changed files with 1730 additions and 829 deletions

View File

@ -65,19 +65,19 @@ MozKeyboard.prototype = {
},
setSelectedOption: function mozKeyboardSetSelectedOption(index) {
this._messageManager.broadcastAsyncMessage("Forms:Select:Choice", {
this._messageManager.sendAsyncMessage("Forms:Select:Choice", {
"index": index
});
},
setValue: function mozKeyboardSetValue(value) {
this._messageManager.broadcastAsyncMessage("Forms:Input:Value", {
this._messageManager.sendAsyncMessage("Forms:Input:Value", {
"value": value
});
},
setSelectedOptions: function mozKeyboardSetSelectedOptions(indexes) {
this._messageManager.broadcastAsyncMessage("Forms:Select:Choice", {
this._messageManager.sendAsyncMessage("Forms:Select:Choice", {
"indexes": indexes || []
});
},

View File

@ -3228,25 +3228,16 @@
</method>
<method name="_finishAnimateTabMove">
<parameter name="event"/>
<body><![CDATA[
if (this.getAttribute("movingtab") != "true")
return;
if (event) {
let draggedTab = event.dataTransfer.mozGetDataAt(TAB_DROP_TYPE, 0);
if ("animDropIndex" in draggedTab._dragData) {
let newIndex = draggedTab._dragData.animDropIndex;
if (newIndex > draggedTab._tPos)
newIndex--;
this.tabbrowser.moveTabTo(draggedTab, newIndex);
}
}
for (let tab of this.tabbrowser.visibleTabs)
tab.style.transform = "";
this.removeAttribute("movingtab");
this._handleTabSelect();
]]></body>
</method>
@ -3623,7 +3614,7 @@
return;
}
this._finishAnimateTabMove(event);
this._finishAnimateTabMove();
if (effects == "link") {
let tab = this._getDragTargetTab(event);
@ -3639,7 +3630,7 @@
var newIndex = this._getDropIndex(event);
var scrollRect = tabStrip.scrollClientRect;
var rect = this.getBoundingClientRect();
var rect = tabStrip.getBoundingClientRect();
var minMargin = scrollRect.left - rect.left;
var maxMargin = Math.min(minMargin + scrollRect.width,
scrollRect.right);
@ -3700,7 +3691,14 @@
if (draggedTab.parentNode != this || event.shiftKey)
this.selectedItem = newTab;
} else if (draggedTab && draggedTab.parentNode == this) {
this._finishAnimateTabMove(event);
// actually move the dragged tab
if ("animDropIndex" in draggedTab._dragData) {
let newIndex = draggedTab._dragData.animDropIndex;
if (newIndex > draggedTab._tPos)
newIndex--;
this.tabbrowser.moveTabTo(draggedTab, newIndex);
}
this._finishAnimateTabMove();
} else if (draggedTab) {
// swap the dropped tab with a new one we create and then close
// it in the other window (making it seem to have moved between
@ -3769,7 +3767,7 @@
// isn't dispatched when the tab is moved within the tabstrip,
// see bug 460801.
this._finishAnimateTabMove(event);
this._finishAnimateTabMove();
var dt = event.dataTransfer;
var draggedTab = dt.mozGetDataAt(TAB_DROP_TYPE, 0);

View File

@ -274,7 +274,6 @@ _BROWSER_FILES = \
social_flyout.html \
social_window.html \
social_worker.js \
browser_bug784142.js \
$(NULL)
ifneq (cocoa,$(MOZ_WIDGET_TOOLKIT))

View File

@ -1,61 +0,0 @@
const windowMediator = Cc["@mozilla.org/appshell/window-mediator;1"].getService(Ci.nsIWindowMediator);
function test()
{
waitForExplicitFinish();
// Need to enable modal dialogs for this test.
Services.prefs.setBoolPref("prompts.tab_modal.enabled", false);
windowMediator.addListener(promptListener);
// Open a new tab and have that tab open a new window. This is done to
// ensure that the new window is a normal browser window.
var script = "window.open('data:text/html,<button id=\"button\" onclick=\"window.close(); alert(5);\">Close</button>', null, 'width=200,height=200');";
gBrowser.selectedTab =
gBrowser.addTab("data:text/html,<body onload='setTimeout(dotest, 0)'><script>function dotest() { " + script + "}</script></body>");
}
function windowOpened(win)
{
// Wait for the page in the window to load.
waitForFocus(clickButton, win.content);
}
function clickButton(win)
{
// Set the window in the prompt listener to indicate that the alert window
// is now expected to open.
promptListener.window = win;
// Click the Close button in the window.
EventUtils.synthesizeMouseAtCenter(win.content.document.getElementById("button"), { }, win);
windowMediator.removeListener(promptListener);
gBrowser.removeTab(gBrowser.selectedTab);
is(promptListener.message, "window appeared", "modal prompt closer didn't crash");
Services.prefs.clearUserPref("prompts.tab_modal.enabled", false);
finish();
}
var promptListener = {
onWindowTitleChange: function () {},
onOpenWindow: function (win) {
let domWin = win.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindow);
if (!promptListener.window) {
// The first window that is open is the one opened by the new tab.
waitForFocus(windowOpened, domWin);
}
else {
// The second window is the alert opened when clicking the Close button in the window
ok(promptListener.window.closed, "window has closed");
// Assign a message so that it can be checked just before the test
// finishes to ensure that the alert opened properly.
promptListener.message = "window appeared";
executeSoon(function () { domWin.close() });
}
},
onCloseWindow: function () {}
};

View File

@ -3818,7 +3818,7 @@ MOZ_ARG_WITH_BOOL(system-nspr,
_USE_SYSTEM_NSPR=1 )
if test -n "$_USE_SYSTEM_NSPR"; then
AM_PATH_NSPR(4.9.0, [MOZ_NATIVE_NSPR=1], [AC_MSG_ERROR([your don't have NSPR installed or your version is too old])])
AM_PATH_NSPR(4.9.2, [MOZ_NATIVE_NSPR=1], [AC_MSG_ERROR([your don't have NSPR installed or your version is too old])])
fi
if test -n "$MOZ_NATIVE_NSPR"; then

View File

@ -5136,7 +5136,7 @@ nsContentUtils::GetViewportInfo(nsIDocument *aDocument)
nsresult errorCode;
float scaleMinFloat = minScaleStr.ToFloat(&errorCode);
if (errorCode) {
if (NS_FAILED(errorCode)) {
scaleMinFloat = kViewportMinScale;
}
@ -5151,7 +5151,7 @@ nsContentUtils::GetViewportInfo(nsIDocument *aDocument)
nsresult scaleMaxErrorCode;
float scaleMaxFloat = maxScaleStr.ToFloat(&scaleMaxErrorCode);
if (scaleMaxErrorCode) {
if (NS_FAILED(scaleMaxErrorCode)) {
scaleMaxFloat = kViewportMaxScale;
}
@ -5210,7 +5210,7 @@ nsContentUtils::GetViewportInfo(nsIDocument *aDocument)
screen->GetRect(&screenLeft, &screenTop, &screenWidth, &screenHeight);
uint32_t width = widthStr.ToInteger(&errorCode);
if (errorCode) {
if (NS_FAILED(errorCode)) {
if (autoSize) {
width = screenWidth;
} else {
@ -5229,7 +5229,7 @@ nsContentUtils::GetViewportInfo(nsIDocument *aDocument)
uint32_t height = heightStr.ToInteger(&errorCode);
if (errorCode) {
if (NS_FAILED(errorCode)) {
height = width * ((float)screenHeight / screenWidth);
}
@ -5244,10 +5244,10 @@ nsContentUtils::GetViewportInfo(nsIDocument *aDocument)
// We need to perform a conversion, but only if the initial or maximum
// scale were set explicitly by the user.
if (!scaleStr.IsEmpty() && !scaleErrorCode) {
if (!scaleStr.IsEmpty() && NS_SUCCEEDED(scaleErrorCode)) {
width = NS_MAX(width, (uint32_t)(screenWidth / scaleFloat));
height = NS_MAX(height, (uint32_t)(screenHeight / scaleFloat));
} else if (!maxScaleStr.IsEmpty() && !scaleMaxErrorCode) {
} else if (!maxScaleStr.IsEmpty() && NS_SUCCEEDED(scaleMaxErrorCode)) {
width = NS_MAX(width, (uint32_t)(screenWidth / scaleMaxFloat));
height = NS_MAX(height, (uint32_t)(screenHeight / scaleMaxFloat));
}

View File

@ -614,6 +614,7 @@ GK_ATOM(OFF, "OFF")
GK_ATOM(ol, "ol")
GK_ATOM(omitXmlDeclaration, "omit-xml-declaration")
GK_ATOM(onabort, "onabort")
GK_ATOM(onadapteradded, "onadapteradded")
GK_ATOM(onafterprint, "onafterprint")
GK_ATOM(onafterscriptexecute, "onafterscriptexecute")
GK_ATOM(onalerting, "onalerting")
@ -692,6 +693,7 @@ GK_ATOM(onget, "onget")
GK_ATOM(onhashchange, "onhashchange")
GK_ATOM(onheld, "onheld")
GK_ATOM(onholding, "onholding")
GK_ATOM(oniccinfochange, "oniccinfochange")
GK_ATOM(onincoming, "onincoming")
GK_ATOM(oninput, "oninput")
GK_ATOM(oninvalid, "oninvalid")

View File

@ -287,7 +287,8 @@ public:
mTempRect = mgfx::Rect(0, 0, ctx->mWidth, ctx->mHeight);
Float blurRadius = mSigma * 3;
static const gfxFloat GAUSSIAN_SCALE_FACTOR = (3 * sqrt(2 * M_PI) / 4) * 1.5;
int32_t blurRadius = (int32_t) floor(mSigma * GAUSSIAN_SCALE_FACTOR + 0.5);
// We need to enlarge and possibly offset our temporary surface
// so that things outside of the canvas may cast shadows.
@ -311,8 +312,8 @@ public:
transform._32 -= mTempRect.y;
mTarget =
mCtx->mTarget->CreateSimilarDrawTarget(IntSize(int32_t(mTempRect.width), int32_t(mTempRect.height)),
FORMAT_B8G8R8A8);
mCtx->mTarget->CreateShadowDrawTarget(IntSize(int32_t(mTempRect.width), int32_t(mTempRect.height)),
FORMAT_B8G8R8A8, mSigma);
if (!mTarget) {
// XXX - Deal with the situation where our temp size is too big to
@ -3102,8 +3103,9 @@ struct NS_STACK_CLASS nsCanvasBidiProcessorAzure : public nsBidiPresUtils::BidiP
buffer.mGlyphs = &glyphBuf.front();
buffer.mNumGlyphs = glyphBuf.size();
Rect bounds(mBoundingBox.x, mBoundingBox.y, mBoundingBox.width, mBoundingBox.height);
if (mOp == nsCanvasRenderingContext2DAzure::TEXT_DRAW_OPERATION_FILL) {
AdjustedTarget(mCtx)->
AdjustedTarget(mCtx, &bounds)->
FillGlyphs(scaledFont, buffer,
CanvasGeneralPattern().
ForStyle(mCtx, nsCanvasRenderingContext2DAzure::STYLE_FILL, mCtx->mTarget),
@ -3112,7 +3114,7 @@ struct NS_STACK_CLASS nsCanvasBidiProcessorAzure : public nsBidiPresUtils::BidiP
RefPtr<Path> path = scaledFont->GetPathForGlyphs(buffer, mCtx->mTarget);
const ContextState& state = *mState;
AdjustedTarget(mCtx)->
AdjustedTarget(mCtx, &bounds)->
Stroke(path, CanvasGeneralPattern().
ForStyle(mCtx, nsCanvasRenderingContext2DAzure::STYLE_STROKE, mCtx->mTarget),
StrokeOptions(state.lineWidth, state.lineJoin,

View File

@ -14740,14 +14740,8 @@ isPixel(ctx, 0,25, 0,255,0,255, 0);
isPixel(ctx, 50,25, 0,255,0,255, 0);
isPixel(ctx, 99,25, 0,255,0,255, 0);
isPixel(ctx, 0,49, 0,255,0,255, 0);
if (IsAzureEnabled() && IsAzureCairo()) {
// Bug 764108
todo_isPixel(ctx, 50,49, 0,255,0,255, 0);
todo_isPixel(ctx, 99,49, 0,255,0,255, 0);
} else {
isPixel(ctx, 50,49, 0,255,0,255, 0);
isPixel(ctx, 99,49, 0,255,0,255, 0);
}
isPixel(ctx, 50,49, 0,255,0,255, 0);
isPixel(ctx, 99,49, 0,255,0,255, 0);
}
</script>

View File

@ -1005,11 +1005,22 @@ bool
nsEventListenerManager::HasListenersFor(const nsAString& aEventName)
{
nsCOMPtr<nsIAtom> atom = do_GetAtom(NS_LITERAL_STRING("on") + aEventName);
return HasListenersFor(atom);
}
bool
nsEventListenerManager::HasListenersFor(nsIAtom* aEventNameWithOn)
{
#ifdef DEBUG
nsAutoString name;
aEventNameWithOn->ToString(name);
#endif
NS_ASSERTION(StringBeginsWith(name, NS_LITERAL_STRING("on")),
"Event name does not start with 'on'");
uint32_t count = mListeners.Length();
for (uint32_t i = 0; i < count; ++i) {
nsListenerStruct* ls = &mListeners.ElementAt(i);
if (ls->mTypeAtom == atom) {
if (ls->mTypeAtom == aEventNameWithOn) {
return true;
}
}

View File

@ -44,8 +44,8 @@ struct nsListenerStruct
nsCOMPtr<nsIAtom> mTypeAtom;
uint16_t mFlags;
uint8_t mListenerType;
bool mListenerIsHandler;
bool mHandlerIsString;
bool mListenerIsHandler : 1;
bool mHandlerIsString : 1;
nsIJSEventListener* GetJSListener() const {
return (mListenerType == eJSEventListener) ?
@ -183,6 +183,12 @@ public:
*/
bool HasListenersFor(const nsAString& aEventName);
/**
* Returns true if there is at least one event listener for aEventNameWithOn.
* Note that aEventNameWithOn must start with "on"!
*/
bool HasListenersFor(nsIAtom* aEventNameWithOn);
/**
* Returns true if there is at least one event listener.
*/

View File

@ -4874,7 +4874,8 @@ nsEventStateManager::UnregisterAccessKey(nsIContent* aContent, uint32_t aKey)
uint32_t
nsEventStateManager::GetRegisteredAccessKey(nsIContent* aContent)
{
NS_ENSURE_ARG(aContent);
NS_ASSERTION(aContent, "Null pointer passed to GetRegisteredAccessKey");
NS_ENSURE_TRUE(aContent, 0);
if (mAccessKeys.IndexOf(aContent) == -1)
return 0;

View File

@ -1688,7 +1688,8 @@ nsHTMLFormElement::CheckValidFormSubmission()
nsCOMPtr<nsISimpleEnumerator> theEnum;
nsresult rv = service->EnumerateObservers(NS_INVALIDFORMSUBMIT_SUBJECT,
getter_AddRefs(theEnum));
NS_ENSURE_SUCCESS(rv, rv);
// Return true on error here because that's what we always did
NS_ENSURE_SUCCESS(rv, true);
bool hasObserver = false;
rv = theEnum->HasMoreElements(&hasObserver);
@ -1698,7 +1699,8 @@ nsHTMLFormElement::CheckValidFormSubmission()
if (NS_SUCCEEDED(rv) && hasObserver) {
nsCOMPtr<nsIMutableArray> invalidElements =
do_CreateInstance(NS_ARRAY_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
// Return true on error here because that's what we always did
NS_ENSURE_SUCCESS(rv, true);
if (!CheckFormValidity(invalidElements.get())) {
// For the first invalid submission, we should update element states.

View File

@ -277,7 +277,7 @@ nsHTMLFrameSetElement::ParseRowCol(const nsAString & aValue,
// Otherwise just convert to integer.
nsresult err;
specs[i].mValue = token.ToInteger(&err);
if (err) {
if (NS_FAILED(err)) {
specs[i].mValue = 0;
}
}

View File

@ -917,7 +917,8 @@ class FileMediaResource : public MediaResource
{
public:
FileMediaResource(nsMediaDecoder* aDecoder, nsIChannel* aChannel, nsIURI* aURI) :
MediaResource(aDecoder, aChannel, aURI), mSize(-1),
MediaResource(aDecoder, aChannel, aURI),
mSize(-1),
mLock("FileMediaResource.mLock"),
mSizeInitialized(false)
{
@ -958,14 +959,28 @@ public:
}
virtual int64_t GetLength() {
MutexAutoLock lock(mLock);
EnsureLengthInitialized();
return mSize;
if (mInput) {
EnsureSizeInitialized();
}
return mSizeInitialized ? mSize : 0;
}
virtual int64_t GetNextCachedData(int64_t aOffset)
{
MutexAutoLock lock(mLock);
if (!mInput) {
return -1;
}
EnsureSizeInitialized();
return (aOffset < mSize) ? aOffset : -1;
}
virtual int64_t GetCachedDataEnd(int64_t aOffset) { return NS_MAX(aOffset, mSize); }
virtual int64_t GetCachedDataEnd(int64_t aOffset) {
MutexAutoLock lock(mLock);
if (!mInput) {
return aOffset;
}
EnsureSizeInitialized();
return NS_MAX(aOffset, mSize);
}
virtual bool IsDataCachedToEndOfResource(int64_t aOffset) { return true; }
virtual bool IsSuspendedByCache(MediaResource** aActiveResource)
{
@ -980,16 +995,18 @@ public:
private:
// Ensures mSize is initialized, if it can be.
void EnsureLengthInitialized();
// mLock must be held when this is called, and mInput must be non-null.
void EnsureSizeInitialized();
// The file size, or -1 if not known. Immutable after Open().
// Can be used from any thread.
int64_t mSize;
// This lock handles synchronisation between calls to Close() and
// the Read, Seek, etc calls. Close must not be called while a
// Read or Seek is in progress since it resets various internal
// values to null.
// This lock protects mSeekable and mInput.
// This lock protects mSeekable, mInput, mSize, and mSizeInitialized.
Mutex mLock;
// Seekable stream interface to file. This can be used from any
@ -997,7 +1014,9 @@ private:
nsCOMPtr<nsISeekableStream> mSeekable;
// Input stream for the media data. This can be used from any
// thread.
// thread. This is annulled when the decoder is being shutdown.
// The decoder can be shut down while we're calculating buffered
// ranges or seeking, so this must be null-checked before it's used.
nsCOMPtr<nsIInputStream> mInput;
// Whether we've attempted to initialize mSize. Note that mSize can be -1
@ -1028,9 +1047,10 @@ private:
nsRefPtr<nsMediaDecoder> mDecoder;
};
void FileMediaResource::EnsureLengthInitialized()
void FileMediaResource::EnsureSizeInitialized()
{
mLock.AssertCurrentThreadOwns();
NS_ASSERTION(mInput, "Must have file input stream");
if (mSizeInitialized) {
return;
}
@ -1048,7 +1068,10 @@ void FileMediaResource::EnsureLengthInitialized()
nsresult FileMediaResource::GetCachedRanges(nsTArray<MediaByteRange>& aRanges)
{
MutexAutoLock lock(mLock);
EnsureLengthInitialized();
if (!mInput) {
return NS_ERROR_FAILURE;
}
EnsureSizeInitialized();
if (mSize == -1) {
return NS_ERROR_FAILURE;
}
@ -1162,9 +1185,9 @@ MediaResource* FileMediaResource::CloneData(nsMediaDecoder* aDecoder)
nsresult FileMediaResource::ReadFromCache(char* aBuffer, int64_t aOffset, uint32_t aCount)
{
MutexAutoLock lock(mLock);
EnsureLengthInitialized();
if (!mInput || !mSeekable)
return NS_ERROR_FAILURE;
EnsureSizeInitialized();
int64_t offset = 0;
nsresult res = mSeekable->Tell(&offset);
NS_ENSURE_SUCCESS(res,res);
@ -1192,9 +1215,9 @@ nsresult FileMediaResource::ReadFromCache(char* aBuffer, int64_t aOffset, uint32
nsresult FileMediaResource::Read(char* aBuffer, uint32_t aCount, uint32_t* aBytes)
{
MutexAutoLock lock(mLock);
EnsureLengthInitialized();
if (!mInput)
return NS_ERROR_FAILURE;
EnsureSizeInitialized();
return mInput->Read(aBuffer, aCount, aBytes);
}
@ -1205,7 +1228,7 @@ nsresult FileMediaResource::Seek(int32_t aWhence, int64_t aOffset)
MutexAutoLock lock(mLock);
if (!mSeekable)
return NS_ERROR_FAILURE;
EnsureLengthInitialized();
EnsureSizeInitialized();
return mSeekable->Seek(aWhence, aOffset);
}
@ -1216,7 +1239,7 @@ int64_t FileMediaResource::Tell()
MutexAutoLock lock(mLock);
if (!mSeekable)
return 0;
EnsureLengthInitialized();
EnsureSizeInitialized();
int64_t offset = 0;
mSeekable->Tell(&offset);

View File

@ -3,6 +3,8 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "VideoUtils.h"
#include "MediaResource.h"
#include "nsTimeRanges.h"
#include "nsMathUtils.h"
#include "prtypes.h"
@ -38,3 +40,52 @@ void ScaleDisplayByAspectRatio(nsIntSize& aDisplay, float aAspectRatio)
aDisplay.height = ConditionDimension(aDisplay.height / aAspectRatio);
}
}
static int64_t BytesToTime(int64_t offset, int64_t length, int64_t durationUs) {
NS_ASSERTION(length > 0, "Must have positive length");
double r = double(offset) / double(length);
if (r > 1.0)
r = 1.0;
return int64_t(double(durationUs) * r);
}
void GetEstimatedBufferedTimeRanges(mozilla::MediaResource* aStream,
int64_t aDurationUsecs,
nsTimeRanges* aOutBuffered)
{
// Nothing to cache if the media takes 0us to play.
if (aDurationUsecs <= 0 || !aStream || !aOutBuffered)
return;
// Special case completely cached files. This also handles local files.
if (aStream->IsDataCachedToEndOfResource(0)) {
aOutBuffered->Add(0, double(aDurationUsecs) / USECS_PER_S);
return;
}
int64_t totalBytes = aStream->GetLength();
// If we can't determine the total size, pretend that we have nothing
// buffered. This will put us in a state of eternally-low-on-undecoded-data
// which is not great, but about the best we can do.
if (totalBytes <= 0)
return;
int64_t startOffset = aStream->GetNextCachedData(0);
while (startOffset >= 0) {
int64_t endOffset = aStream->GetCachedDataEnd(startOffset);
// Bytes [startOffset..endOffset] are cached.
NS_ASSERTION(startOffset >= 0, "Integer underflow in GetBuffered");
NS_ASSERTION(endOffset >= 0, "Integer underflow in GetBuffered");
int64_t startUs = BytesToTime(startOffset, totalBytes, aDurationUsecs);
int64_t endUs = BytesToTime(endOffset, totalBytes, aDurationUsecs);
if (startUs != endUs) {
aOutBuffered->Add(double(startUs) / USECS_PER_S,
double(endUs) / USECS_PER_S);
}
startOffset = aStream->GetNextCachedData(endOffset);
}
return;
}

View File

@ -85,8 +85,21 @@ private:
nsCOMPtr<nsIThread> mThread;
};
class MediaResource;
} // namespace mozilla
class nsTimeRanges;
// Estimates the buffered ranges of a MediaResource using a simple
// (byteOffset/length)*duration method. Probably inaccurate, but won't
// do file I/O, and can be used when we don't have detailed knowledge
// of the byte->time mapping of a resource. aDurationUsecs is the duration
// of the media in microseconds. Estimated buffered ranges are stored in
// aOutBuffered. Ranges are 0-normalized, i.e. in the range of (0,duration].
void GetEstimatedBufferedTimeRanges(mozilla::MediaResource* aStream,
int64_t aDurationUsecs,
nsTimeRanges* aOutBuffered);
// Converts from number of audio frames (aFrames) to microseconds, given
// the specified audio rate (aRate). Stores result in aOutUsecs. Returns true
// if the operation succeeded, or false if there was an integer overflow

View File

@ -233,6 +233,7 @@ VideoData* VideoData::Create(nsVideoInfo& aInfo,
data.mPicSize = gfxIntSize(aPicture.width, aPicture.height);
data.mStereoMode = aInfo.mStereoMode;
videoImage->SetDelayedConversion(true);
videoImage->SetData(data);
return v.forget();
}

View File

@ -20,6 +20,12 @@ extern "C" {
using namespace mozilla;
// On B2G estimate the buffered ranges rather than calculating them explicitly.
// This prevents us doing I/O on the main thread, which is prohibited in B2G.
#ifdef MOZ_WIDGET_GONK
#define OGG_ESTIMATE_BUFFERED 1
#endif
// Un-comment to enable logging of seek bisections.
//#define SEEK_LOGGING
@ -532,7 +538,7 @@ nsresult nsOggReader::DecodeOpus(ogg_packet* aPacket) {
/*4*/{ {0.4226f,0}, {0,0.4226f}, {0.366f,0.2114f}, {0.2114f,0.366f}},
/*5*/{ {0.651f,0}, {0.46f,0.46f}, {0,0.651f}, {0.5636f,0.3254f}, {0.3254f,0.5636f}},
/*6*/{ {0.529f,0}, {0.3741f,0.3741f}, {0,0.529f}, {0.4582f,0.2645f}, {0.2645f,0.4582f}, {0.3741f,0.3741f}},
/*7*/{ {0.4553f,0}, {0.322f,0.322f}, {0,4553}, {0.3943f,0.2277f}, {0.2277f,0.3943f}, {0.2788f,0.2788f}, {0.322f,0.322f}},
/*7*/{ {0.4553f,0}, {0.322f,0.322f}, {0,0.4553f}, {0.3943f,0.2277f}, {0.2277f,0.3943f}, {0.2788f,0.2788f}, {0.322f,0.322f}},
/*8*/{ {0.3886f,0}, {0.2748f,0.2748f}, {0,0.3886f}, {0.3366f,0.1943f}, {0.1943f,0.3366f}, {0.3366f,0.1943f}, {0.1943f,0.3366f}, {0.2748f,0.2748f}},
};
for (int32_t i = 0; i < frames; i++) {
@ -1620,6 +1626,17 @@ nsresult nsOggReader::SeekBisection(int64_t aTarget,
nsresult nsOggReader::GetBuffered(nsTimeRanges* aBuffered, int64_t aStartTime)
{
#ifdef OGG_ESTIMATE_BUFFERED
MediaResource* stream = mDecoder->GetResource();
int64_t durationUs = 0;
{
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
durationUs = mDecoder->GetStateMachine()->GetDuration();
}
GetEstimatedBufferedTimeRanges(stream, durationUs, aBuffered);
return NS_OK;
#else
// HasAudio and HasVideo are not used here as they take a lock and cause
// a deadlock. Accessing mInfo doesn't require a lock - it doesn't change
// after metadata is read.
@ -1720,6 +1737,7 @@ nsresult nsOggReader::GetBuffered(nsTimeRanges* aBuffered, int64_t aStartTime)
}
return NS_OK;
#endif
}
bool nsOggReader::IsKnownStream(uint32_t aSerial)

View File

@ -290,13 +290,6 @@ nsresult nsMediaPluginReader::Seek(int64_t aTarget, int64_t aStartTime, int64_t
return DecodeToTarget(aTarget);
}
static uint64_t BytesToTime(int64_t offset, uint64_t length, uint64_t durationUs) {
double perc = double(offset) / double(length);
if (perc > 1.0)
perc = 1.0;
return uint64_t(double(durationUs) * perc);
}
nsresult nsMediaPluginReader::GetBuffered(nsTimeRanges* aBuffered, int64_t aStartTime)
{
if (!mPlugin)
@ -307,37 +300,7 @@ nsresult nsMediaPluginReader::GetBuffered(nsTimeRanges* aBuffered, int64_t aStar
int64_t durationUs = 0;
mPlugin->GetDuration(mPlugin, &durationUs);
// Nothing to cache if the media takes 0us to play.
if (!durationUs)
return NS_OK;
// Special case completely cached files. This also handles local files.
if (stream->IsDataCachedToEndOfResource(0)) {
aBuffered->Add(0, durationUs);
return NS_OK;
}
int64_t totalBytes = stream->GetLength();
// If we can't determine the total size, pretend that we have nothing
// buffered. This will put us in a state of eternally-low-on-undecoded-data
// which is not get, but about the best we can do.
if (totalBytes == -1)
return NS_OK;
int64_t startOffset = stream->GetNextCachedData(0);
while (startOffset >= 0) {
int64_t endOffset = stream->GetCachedDataEnd(startOffset);
// Bytes [startOffset..endOffset] are cached.
NS_ASSERTION(startOffset >= 0, "Integer underflow in GetBuffered");
NS_ASSERTION(endOffset >= 0, "Integer underflow in GetBuffered");
uint64_t startUs = BytesToTime(startOffset, totalBytes, durationUs);
uint64_t endUs = BytesToTime(endOffset, totalBytes, durationUs);
if (startUs != endUs) {
aBuffered->Add(startUs, endUs);
}
startOffset = stream->GetNextCachedData(endOffset);
}
GetEstimatedBufferedTimeRanges(stream, durationUs, aBuffered);
return NS_OK;
}

View File

@ -1891,7 +1891,7 @@ nsXULContentBuilder::InsertSortedNode(nsIContent* aContainer,
// found "static" XUL element count hint
nsresult strErr = NS_OK;
staticCount = staticValue.ToInteger(&strErr);
if (strErr)
if (NS_FAILED(strErr))
staticCount = 0;
} else {
// compute the "static" XUL element count

View File

@ -1850,7 +1850,7 @@ nsXULTreeBuilder::CompareResults(nsIXULTemplateResult* aLeft, nsIXULTemplateResu
nsCOMPtr<nsISupports> ref;
nsresult rv = aLeft->GetBindingObjectFor(mRefVariable, getter_AddRefs(ref));
if (NS_FAILED(rv))
return rv;
return 0;
nsCOMPtr<nsIRDFResource> container = do_QueryInterface(ref);
if (container) {

View File

@ -78,9 +78,15 @@ let DOMApplicationRegistry = {
#endif
let currentId = 1;
dirList.forEach((function(dir) {
let curFile = FileUtils.getFile(dir, ["webapps", "webapps.json"], true);
if (curFile.exists()) {
let appDir = FileUtils.getDir(dir, ["webapps"]);
let curFile;
try {
// getFile calls getDir with |shouldCreate = true|, so we have
// to wrap in a try..catch in case the file does not exist on a
// read-only partition.
curFile = FileUtils.getFile(dir, ["webapps", "webapps.json"], false);
} catch(e) { }
if (curFile && curFile.exists()) {
let appDir = FileUtils.getDir(dir, ["webapps"], false);
this._loadJSONAsync(curFile, (function(aData) {
if (!aData) {
return;

View File

@ -2518,7 +2518,7 @@ nsGlobalWindow::DialogsAreBlocked(bool *aBeingAbused)
nsGlobalWindow *topWindow = GetScriptableTop();
if (!topWindow) {
NS_ASSERTION(!mDocShell, "DialogsAreBlocked() called without a top window?");
NS_ERROR("DialogsAreBlocked() called without a top window?");
return true;
}
@ -7652,11 +7652,9 @@ nsGlobalWindow::ActivateOrDeactivate(bool aActivate)
// widgetListener should be a nsXULWindow
nsIWidgetListener* listener = topLevelWidget->GetWidgetListener();
if (listener) {
nsCOMPtr<nsIXULWindow> window = listener->GetXULWindow();
nsCOMPtr<nsIInterfaceRequestor> req(do_QueryInterface(window));
topLevelWindow = do_GetInterface(req);
}
nsCOMPtr<nsIXULWindow> window = listener->GetXULWindow();
nsCOMPtr<nsIInterfaceRequestor> req(do_QueryInterface(window));
topLevelWindow = do_GetInterface(req);
}
if (topLevelWindow) {
nsCOMPtr<nsPIDOMWindow> piWin(do_QueryInterface(topLevelWindow));

View File

@ -83,7 +83,7 @@ public:
sc->GetNativeGlobal(),
adapter,
aValue);
bool result = NS_SUCCEEDED(rv) ? true : false;
bool result = NS_SUCCEEDED(rv);
if (!result) {
NS_WARNING("Cannot create native object!");
SetError(NS_LITERAL_STRING("BluetoothNativeObjectError"));
@ -247,6 +247,20 @@ BluetoothManager::HandleMozsettingChanged(const PRUnichar* aData)
}
bool enabled = value.toBoolean();
bool isEnabled = (bs->IsEnabledInternal() > 0);
if (!isEnabled && enabled) {
if (NS_FAILED(bs->RegisterBluetoothSignalHandler(NS_LITERAL_STRING("/"), this))) {
NS_ERROR("Failed to register object with observer!");
return NS_ERROR_FAILURE;
}
} else if (isEnabled && !enabled){
if (NS_FAILED(bs->UnregisterBluetoothSignalHandler(NS_LITERAL_STRING("/"), this))) {
NS_WARNING("Failed to unregister object with observer!");
}
} else {
return NS_OK;
}
nsCOMPtr<nsIRunnable> resultTask = new ToggleBtResultTask(this, enabled);
if (enabled) {
@ -330,17 +344,19 @@ BluetoothManager::GetDefaultAdapter(nsIDOMDOMRequest** aAdapter)
// static
already_AddRefed<BluetoothManager>
BluetoothManager::Create(nsPIDOMWindow* aWindow) {
nsRefPtr<BluetoothManager> manager = new BluetoothManager(aWindow);
BluetoothService* bs = BluetoothService::Get();
if (!bs) {
NS_WARNING("BluetoothService not available!");
return nullptr;
}
if (NS_FAILED(bs->RegisterBluetoothSignalHandler(NS_LITERAL_STRING("/"), manager))) {
NS_ERROR("Failed to register object with observer!");
return nullptr;
bool isEnabled = (bs->IsEnabledInternal() > 0);
if (isEnabled) {
if (NS_FAILED(bs->RegisterBluetoothSignalHandler(NS_LITERAL_STRING("/"), manager))) {
NS_ERROR("Failed to register object with observer!");
return nullptr;
}
}
return manager.forget();
@ -390,13 +406,28 @@ NS_NewBluetoothManager(nsPIDOMWindow* aWindow,
void
BluetoothManager::Notify(const BluetoothSignal& aData)
{
if (aData.name().EqualsLiteral("AdapterAdded")) {
nsRefPtr<nsDOMEvent> event = new nsDOMEvent(nullptr, nullptr);
nsresult rv = event->InitEvent(NS_LITERAL_STRING("adapteradded"), false, false);
if (NS_FAILED(rv)) {
NS_WARNING("Failed to init the adapteradded event!!!");
return;
}
event->SetTrusted(true);
bool dummy;
DispatchEvent(event, &dummy);
} else {
#ifdef DEBUG
nsCString warningMsg;
warningMsg.AssignLiteral("Not handling manager signal: ");
warningMsg.Append(NS_ConvertUTF16toUTF8(aData.name()));
NS_WARNING(warningMsg.get());
nsCString warningMsg;
warningMsg.AssignLiteral("Not handling manager signal: ");
warningMsg.Append(NS_ConvertUTF16toUTF8(aData.name()));
NS_WARNING(warningMsg.get());
#endif
}
}
NS_IMPL_EVENT_HANDLER(BluetoothManager, enabled)
NS_IMPL_EVENT_HANDLER(BluetoothManager, disabled)
NS_IMPL_EVENT_HANDLER(BluetoothManager, adapteradded)

View File

@ -225,6 +225,7 @@ public:
virtual bool SetPasskeyInternal(const nsAString& aDeviceAddress, uint32_t aPasskey) = 0;
virtual bool SetPairingConfirmationInternal(const nsAString& aDeviceAddress, bool aConfirm) = 0;
virtual bool SetAuthorizationInternal(const nsAString& aDeviceAddress, bool aAllow) = 0;
virtual int IsEnabledInternal() = 0;
/**
* Due to the fact that some operations require multiple calls, a

View File

@ -128,6 +128,16 @@ StartStopGonkBluetooth(bool aShouldEnable)
return NS_OK;
}
int
BluetoothGonkService::IsEnabledInternal()
{
if (!EnsureBluetoothInit()) {
NS_ERROR("Failed to load bluedroid library.\n");
return false;
}
return IsBluetoothEnabled();
}
nsresult
BluetoothGonkService::StartInternal()
{

View File

@ -52,6 +52,11 @@ public:
* otherwise
*/
virtual nsresult StopInternal();
/**
* @return true if bluetooth daemon is enabled, false otherwise
*/
virtual int IsEnabledInternal();
};
END_BLUETOOTH_NAMESPACE

View File

@ -831,7 +831,6 @@ EventFilter(DBusConnection* aConn, DBusMessage* aMsg, void* aData)
BluetoothValue v;
if (dbus_message_is_signal(aMsg, DBUS_ADAPTER_IFACE, "DeviceFound")) {
DBusMessageIter iter;
if (!dbus_message_iter_init(aMsg, &iter)) {
@ -892,6 +891,16 @@ EventFilter(DBusConnection* aConn, DBusMessage* aMsg, void* aData)
errorStr,
sDeviceProperties,
ArrayLength(sDeviceProperties));
} else if (dbus_message_is_signal(aMsg, DBUS_MANAGER_IFACE, "AdapterAdded")) {
const char* str;
if (!dbus_message_get_args(aMsg, &err,
DBUS_TYPE_OBJECT_PATH, &str,
DBUS_TYPE_INVALID)) {
LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, aMsg);
errorStr.AssignLiteral("Cannot parse manager path!");
} else {
v = NS_ConvertUTF8toUTF16(str);
}
} else if (dbus_message_is_signal(aMsg, DBUS_MANAGER_IFACE, "PropertyChanged")) {
ParsePropertyChange(aMsg,
v,
@ -1028,6 +1037,14 @@ BluetoothDBusService::StopInternal()
return NS_OK;
}
int
BluetoothDBusService::IsEnabledInternal()
{
// assume bluetooth is always enabled on desktop
return true;
}
class DefaultAdapterPropertiesRunnable : public nsRunnable
{
public:

View File

@ -82,6 +82,8 @@ public:
virtual bool
SetAuthorizationInternal(const nsAString& aDeviceAddress, bool aAllow);
virtual int IsEnabledInternal();
private:
nsresult SendGetPropertyMessage(const nsAString& aPath,
const char* aInterface,

View File

@ -9,7 +9,7 @@
interface nsIDOMDOMRequest;
interface nsIDOMBluetoothAdapter;
[scriptable, builtinclass, uuid(b9e0a4a2-fa84-402d-8830-d0f3625f120a)]
[scriptable, builtinclass, uuid(d27ec867-949f-4585-b718-d2352e420ec6)]
interface nsIDOMBluetoothManager : nsIDOMEventTarget
{
readonly attribute bool enabled;
@ -18,4 +18,5 @@ interface nsIDOMBluetoothManager : nsIDOMEventTarget
[implicit_jscontext] attribute jsval onenabled;
[implicit_jscontext] attribute jsval ondisabled;
[implicit_jscontext] attribute jsval onadapteradded;
};

View File

@ -6,12 +6,13 @@
interface nsIDOMEventListener;
interface nsIDOMDOMRequest;
interface nsIDOMMozMobileICCInfo;
interface nsIDOMMozMobileConnectionInfo;
interface nsIDOMMozMobileNetworkInfo;
interface nsIDOMMozMobileCellInfo;
interface nsIDOMMozIccManager;
[scriptable, builtinclass, uuid(fda3bb30-3259-4ba7-8cff-c486c30821a4)]
[scriptable, builtinclass, uuid(d9009d90-a4b3-44fd-a592-42b09f330fe5)]
interface nsIDOMMozMobileConnection : nsIDOMEventTarget
{
/**
@ -22,6 +23,11 @@ interface nsIDOMMozMobileConnection : nsIDOMEventTarget
*/
readonly attribute DOMString cardState;
/**
* Information stored in the device's ICC card.
*/
readonly attribute nsIDOMMozMobileICCInfo iccInfo;
/**
* Information about the voice connection.
*/
@ -210,6 +216,12 @@ interface nsIDOMMozMobileConnection : nsIDOMEventTarget
*/
[implicit_jscontext] attribute jsval oncardstatechange;
/**
* The 'iccinfochange' event is notified whenever the icc info object
* changes.
*/
[implicit_jscontext] attribute jsval oniccinfochange;
/**
* The 'voicechange' event is notified whenever the voice connection object
* changes.
@ -334,3 +346,17 @@ interface nsIDOMMozMobileCellInfo: nsISupports
*/
readonly attribute unsigned long gsmCellId;
};
[scriptable, uuid(109c1117-1199-47aa-aad2-ea9f456220fa)]
interface nsIDOMMozMobileICCInfo : nsISupports
{
/**
* Mobile Country Code (MCC) of the subscriber's home network.
*/
readonly attribute unsigned short mcc;
/**
* Mobile Network Code (MNC) of the subscriber's home network.
*/
readonly attribute unsigned short mnc;
};

View File

@ -4,6 +4,7 @@
#include "nsISupports.idl"
interface nsIDOMMozMobileICCInfo;
interface nsIDOMMozMobileConnectionInfo;
interface nsIDOMMozMobileNetworkInfo;
interface nsIDOMDOMRequest;
@ -13,10 +14,11 @@ interface nsIDOMWindow;
* XPCOM component (in the content process) that provides the mobile
* network information.
*/
[scriptable, uuid(fb3fac34-c1c2-45a9-ad18-a7af0f7997c9)]
[scriptable, uuid(63787ba1-5091-450b-8810-d321a8b4f77a)]
interface nsIMobileConnectionProvider : nsISupports
{
readonly attribute DOMString cardState;
readonly attribute nsIDOMMozMobileICCInfo iccInfo;
readonly attribute nsIDOMMozMobileConnectionInfo voiceConnectionInfo;
readonly attribute nsIDOMMozMobileConnectionInfo dataConnectionInfo;
readonly attribute DOMString networkSelectionMode;

View File

@ -16,6 +16,7 @@
#define VOICECHANGE_EVENTNAME NS_LITERAL_STRING("voicechange")
#define DATACHANGE_EVENTNAME NS_LITERAL_STRING("datachange")
#define CARDSTATECHANGE_EVENTNAME NS_LITERAL_STRING("cardstatechange")
#define ICCINFOCHANGE_EVENTNAME NS_LITERAL_STRING("iccinfochange")
#define USSDRECEIVED_EVENTNAME NS_LITERAL_STRING("ussdreceived")
DOMCI_DATA(MozMobileConnection, mozilla::dom::network::MobileConnection)
@ -27,6 +28,7 @@ namespace network {
const char* kVoiceChangedTopic = "mobile-connection-voice-changed";
const char* kDataChangedTopic = "mobile-connection-data-changed";
const char* kCardStateChangedTopic = "mobile-connection-cardstate-changed";
const char* kIccInfoChangedTopic = "mobile-connection-iccinfo-changed";
const char* kUssdReceivedTopic = "mobile-connection-ussd-received";
NS_IMPL_CYCLE_COLLECTION_CLASS(MobileConnection)
@ -51,6 +53,7 @@ NS_IMPL_ADDREF_INHERITED(MobileConnection, nsDOMEventTargetHelper)
NS_IMPL_RELEASE_INHERITED(MobileConnection, nsDOMEventTargetHelper)
NS_IMPL_EVENT_HANDLER(MobileConnection, cardstatechange)
NS_IMPL_EVENT_HANDLER(MobileConnection, iccinfochange)
NS_IMPL_EVENT_HANDLER(MobileConnection, voicechange)
NS_IMPL_EVENT_HANDLER(MobileConnection, datachange)
NS_IMPL_EVENT_HANDLER(MobileConnection, ussdreceived)
@ -80,6 +83,7 @@ MobileConnection::Init(nsPIDOMWindow* aWindow)
obs->AddObserver(this, kVoiceChangedTopic, false);
obs->AddObserver(this, kDataChangedTopic, false);
obs->AddObserver(this, kCardStateChangedTopic, false);
obs->AddObserver(this, kIccInfoChangedTopic, false);
obs->AddObserver(this, kUssdReceivedTopic, false);
mIccManager = new icc::IccManager();
@ -98,6 +102,7 @@ MobileConnection::Shutdown()
obs->RemoveObserver(this, kVoiceChangedTopic);
obs->RemoveObserver(this, kDataChangedTopic);
obs->RemoveObserver(this, kCardStateChangedTopic);
obs->RemoveObserver(this, kIccInfoChangedTopic);
obs->RemoveObserver(this, kUssdReceivedTopic);
if (mIccManager) {
@ -128,6 +133,11 @@ MobileConnection::Observe(nsISupports* aSubject,
return NS_OK;
}
if (!strcmp(aTopic, kIccInfoChangedTopic)) {
InternalDispatchEvent(ICCINFOCHANGE_EVENTNAME);
return NS_OK;
}
if (!strcmp(aTopic, kUssdReceivedTopic)) {
nsString ussd;
ussd.Assign(aData);
@ -157,6 +167,16 @@ MobileConnection::GetCardState(nsAString& cardState)
return mProvider->GetCardState(cardState);
}
NS_IMETHODIMP
MobileConnection::GetIccInfo(nsIDOMMozMobileICCInfo** aIccInfo)
{
if (!mProvider) {
*aIccInfo = nullptr;
return NS_OK;
}
return mProvider->GetIccInfo(aIccInfo);
}
NS_IMETHODIMP
MobileConnection::GetVoice(nsIDOMMozMobileConnectionInfo** voice)
{

View File

@ -8,3 +8,8 @@ qemu = true
b2g = true
browser = false
qemu = true
[test_mobile_iccinfo.js]
b2g = true
browser = false
qemu = true

View File

@ -0,0 +1,18 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
MARIONETTE_TIMEOUT = 30000;
SpecialPowers.addPermission("mobileconnection", true, document);
let connection = navigator.mozMobileConnection;
ok(connection instanceof MozMobileConnection,
"connection is instanceof " + connection.constructor);
// The emulator's hard coded mcc and mnc codes.
// See it here {B2G_HOME}/external/qemu/telephony/android_modem.c#L2465.
is(connection.iccInfo.mcc, 310);
is(connection.iccInfo.mnc, 260);
SpecialPowers.removePermission("mobileconnection", document);
finish();

View File

@ -18,8 +18,9 @@
SimpleTest.waitForExplicitFinish();
const isOSXLion = navigator.userAgent.indexOf("Mac OS X 10.7") != -1;
if (isOSXLion) {
todo(false, "Can't test plugin crash notification on OS X 10.7, see bug 705047");
const isOSXMtnLion = navigator.userAgent.indexOf("Mac OS X 10.8") != -1;
if (isOSXLion || isOSXMtnLion) {
todo(false, "Can't test plugin crash notification on OS X 10.7 or 10.8, see bug 705047");
SimpleTest.finish();
}

View File

@ -16,8 +16,9 @@
SimpleTest.waitForExplicitFinish();
const isOSXLion = navigator.userAgent.indexOf("Mac OS X 10.7") != -1;
if (isOSXLion) {
todo(false, "Can't test plugin crash notification on OS X 10.7, see bug 705047");
const isOSXMtnLion = navigator.userAgent.indexOf("Mac OS X 10.8") != -1;
if (isOSXLion || isOSXMtnLion) {
todo(false, "Can't test plugin crash notification on OS X 10.7 or 10.8, see bug 705047");
SimpleTest.finish();
}

View File

@ -16,8 +16,9 @@
SimpleTest.waitForExplicitFinish();
const isOSXLion = navigator.userAgent.indexOf("Mac OS X 10.7") != -1;
if (isOSXLion) {
todo(false, "Can't test plugin crash notification on OS X 10.7, see bug 705047");
const isOSXMtnLion = navigator.userAgent.indexOf("Mac OS X 10.8") != -1;
if (isOSXLion || isOSXMtnLion) {
todo(false, "Can't test plugin crash notification on OS X 10.7 or 10.8, see bug 705047");
SimpleTest.finish();
}

View File

@ -19,8 +19,9 @@ SimpleTest.waitForExplicitFinish();
SimpleTest.ignoreAllUncaughtExceptions();
const isOSXLion = navigator.userAgent.indexOf("Mac OS X 10.7") != -1;
if (isOSXLion) {
todo(false, "Can't test plugin crash notification on OS X 10.7, see bug 705047");
const isOSXMtnLion = navigator.userAgent.indexOf("Mac OS X 10.8") != -1;
if (isOSXLion || isOSXMtnLion) {
todo(false, "Can't test plugin crash notification on OS X 10.7 or 10.8, see bug 705047");
SimpleTest.finish();
}

View File

@ -7,8 +7,9 @@
SimpleTest.waitForExplicitFinish();
const isOSXLion = navigator.userAgent.indexOf("Mac OS X 10.7") != -1;
if (isOSXLion) {
todo(false, "Can't test plugin crash notification on OS X 10.7, see bug 705047");
const isOSXMtnLion = navigator.userAgent.indexOf("Mac OS X 10.8") != -1;
if (isOSXLion || isOSXMtnLion) {
todo(false, "Can't test plugin crash notification on OS X 10.7 or 10.8, see bug 705047");
SimpleTest.finish();
}

View File

@ -7,8 +7,9 @@
SimpleTest.waitForExplicitFinish();
const isOSXLion = navigator.userAgent.indexOf("Mac OS X 10.7") != -1;
if (isOSXLion) {
todo(false, "Can't test plugin crash notification on OS X 10.7, see bug 705047");
const isOSXMtnLion = navigator.userAgent.indexOf("Mac OS X 10.8") != -1;
if (isOSXLion || isOSXMtnLion) {
todo(false, "Can't test plugin crash notification on OS X 10.7 or 10.8, see bug 705047");
SimpleTest.finish();
}

View File

@ -18,8 +18,9 @@
SimpleTest.waitForExplicitFinish();
const isOSXLion = navigator.userAgent.indexOf("Mac OS X 10.7") != -1;
if (isOSXLion) {
todo(false, "Can't test plugin crash notification on OS X 10.7, see bug 705047");
const isOSXMtnLion = navigator.userAgent.indexOf("Mac OS X 10.8") != -1;
if (isOSXLion || isOSXMtnLion) {
todo(false, "Can't test plugin crash notification on OS X 10.7 or 10.8, see bug 705047");
SimpleTest.finish();
}

View File

@ -29,6 +29,8 @@ const DEBUG = RIL.DEBUG_CONTENT_HELPER;
const RILCONTENTHELPER_CID =
Components.ID("{472816e1-1fd6-4405-996c-806f9ea68174}");
const MOBILEICCINFO_CID =
Components.ID("{8649c12f-f8f4-4664-bbdd-7d115c23e2a7}");
const MOBILECONNECTIONINFO_CID =
Components.ID("{a35cfd39-2d93-4489-ac7d-396475dacb27}");
const MOBILENETWORKINFO_CID =
@ -40,6 +42,7 @@ const VOICEMAILSTATUS_CID=
const RIL_IPC_MSG_NAMES = [
"RIL:CardStateChanged",
"RIL:IccInfoChanged",
"RIL:VoiceInfoChanged",
"RIL:DataInfoChanged",
"RIL:EnumerateCalls",
@ -64,6 +67,7 @@ const RIL_IPC_MSG_NAMES = [
const kVoiceChangedTopic = "mobile-connection-voice-changed";
const kDataChangedTopic = "mobile-connection-data-changed";
const kCardStateChangedTopic = "mobile-connection-cardstate-changed";
const kIccInfoChangedTopic = "mobile-connection-iccinfo-changed";
const kUssdReceivedTopic = "mobile-connection-ussd-received";
const kStkCommandTopic = "icc-manager-stk-command";
const kStkSessionEndTopic = "icc-manager-stk-session-end";
@ -76,6 +80,23 @@ XPCOMUtils.defineLazyServiceGetter(this, "gUUIDGenerator",
"@mozilla.org/uuid-generator;1",
"nsIUUIDGenerator");
function MobileICCInfo() {}
MobileICCInfo.prototype = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsIDOMMozMobileICCInfo]),
classID: MOBILEICCINFO_CID,
classInfo: XPCOMUtils.generateCI({
classID: MOBILEICCINFO_CID,
classDescription: "MobileICCInfo",
flags: Ci.nsIClassInfo.DOM_OBJECT,
interfaces: [Ci.nsIDOMMozMobileICCInfo]
}),
// nsIDOMMozMobileICCInfo
mcc: 0,
mnc: 0
};
function MobileConnectionInfo() {}
MobileConnectionInfo.prototype = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsIDOMMozMobileConnectionInfo]),
@ -157,6 +178,7 @@ VoicemailStatus.prototype = {
};
function RILContentHelper() {
this.iccInfo = new MobileICCInfo();
this.voiceConnectionInfo = new MobileConnectionInfo();
this.dataConnectionInfo = new MobileConnectionInfo();
@ -172,6 +194,7 @@ function RILContentHelper() {
return;
}
this.cardState = rilContext.cardState;
this.updateICCInfo(rilContext.icc, this.iccInfo);
this.updateConnectionInfo(rilContext.voice, this.voiceConnectionInfo);
this.updateConnectionInfo(rilContext.data, this.dataConnectionInfo);
}
@ -188,6 +211,11 @@ RILContentHelper.prototype = {
interfaces: [Ci.nsIMobileConnectionProvider,
Ci.nsIRILContentHelper]}),
updateICCInfo: function updateICCInfo(srcInfo, destInfo) {
destInfo.mcc = srcInfo.mcc;
destInfo.mnc = srcInfo.mnc;
},
updateConnectionInfo: function updateConnectionInfo(srcInfo, destInfo) {
for (let key in srcInfo) {
if ((key != "network") && (key != "cell")) {
@ -227,9 +255,10 @@ RILContentHelper.prototype = {
// nsIRILContentHelper
cardState: RIL.GECKO_CARDSTATE_UNAVAILABLE,
voiceConnectionInfo: null,
dataConnectionInfo: null,
cardState: RIL.GECKO_CARDSTATE_UNAVAILABLE,
iccInfo: null,
voiceConnectionInfo: null,
dataConnectionInfo: null,
networkSelectionMode: RIL.GECKO_NETWORK_SELECTION_UNKNOWN,
/**
@ -584,6 +613,10 @@ RILContentHelper.prototype = {
Services.obs.notifyObservers(null, kCardStateChangedTopic, null);
}
break;
case "RIL:IccInfoChanged":
this.updateICCInfo(msg.json, this.iccInfo);
Services.obs.notifyObservers(null, kIccInfoChangedTopic, null);
break;
case "RIL:VoiceInfoChanged":
this.updateConnectionInfo(msg.json, this.voiceConnectionInfo);
Services.obs.notifyObservers(null, kVoiceChangedTopic, null);

View File

@ -422,7 +422,7 @@ RadioInterfaceLayer.prototype = {
" timestamp=" + message.localTimeStampInMS);
break;
case "iccinfochange":
this.rilContext.icc = message;
this.handleICCInfoChange(message);
break;
case "iccGetCardLock":
case "iccSetCardLock":
@ -1017,6 +1017,17 @@ RadioInterfaceLayer.prototype = {
[message.datacalls, message.datacalls.length]);
},
handleICCInfoChange: function handleICCInfoChange(message) {
let oldIcc = this.rilContext.icc;
this.rilContext.icc = message;
if (oldIcc && (oldIcc.mcc == message.mcc || oldIcc.mnc == message.mnc)) {
return;
}
// RIL:IccInfoChanged corresponds to a DOM event that gets fired only
// when the MCC or MNC codes have changed.
ppmm.broadcastAsyncMessage("RIL:IccInfoChanged", message);
},
handleICCCardLockResult: function handleICCCardLockResult(message) {
this._sendRequestResults("RIL:CardLockResult", message);
},

View File

@ -1364,7 +1364,7 @@ let RIL = {
pin2: null,
type: EF_TYPE_LINEAR_FIXED,
callback: callback,
onerror: error
onerror: error,
loadAll: true,
requestId: options.requestId,
});

View File

@ -71,11 +71,10 @@ DOMWifiManager.prototype = {
// Maintain this state for synchronous APIs.
this._currentNetwork = null;
this._connectionStatus = "disconnected";
this._enabled = true;
this._enabled = false;
this._lastConnectionInfo = null;
const messages = ["WifiManager:setEnabled:Return:OK", "WifiManager:setEnabled:Return:NO",
"WifiManager:getNetworks:Return:OK", "WifiManager:getNetworks:Return:NO",
const messages = ["WifiManager:getNetworks:Return:OK", "WifiManager:getNetworks:Return:NO",
"WifiManager:associate:Return:OK", "WifiManager:associate:Return:NO",
"WifiManager:forget:Return:OK", "WifiManager:forget:Return:NO",
"WifiManager:wps:Return:OK", "WifiManager:wps:Return:NO",
@ -125,19 +124,6 @@ DOMWifiManager.prototype = {
let request;
switch (aMessage.name) {
case "WifiManager:setEnabled:Return:OK":
request = this.takeRequest(msg.rid);
this._enabled = msg.data;
if (!this._enabled)
this._currentNetwork = null;
Services.DOMRequest.fireSuccess(request, true);
break;
case "WifiManager:setEnabled:Return:NO":
request = this.takeRequest(msg.rid);
Services.DOMRequest.fireError(request, "Unable to initialize wifi");
break;
case "WifiManager:getNetworks:Return:OK":
request = this.takeRequest(msg.rid);
Services.DOMRequest.fireSuccess(request, exposeReadOnly(msg.data));
@ -284,14 +270,6 @@ DOMWifiManager.prototype = {
},
// nsIDOMWifiManager
setEnabled: function nsIDOMWifiManager_setEnabled(enabled) {
if (!this._hasPrivileges)
throw new Components.Exception("Denied", Cr.NS_ERROR_FAILURE);
var request = this.createRequest();
this._sendMessageForRequest("WifiManager:setEnabled", enabled, request);
return request;
},
getNetworks: function nsIDOMWifiManager_getNetworks() {
if (!this._hasPrivileges)
throw new Components.Exception("Denied", Cr.NS_ERROR_FAILURE);

View File

@ -19,6 +19,7 @@ const WIFIWORKER_CID = Components.ID("{a14e8977-d259-433a-a88d-58dd44657e
const WIFIWORKER_WORKER = "resource://gre/modules/wifi_worker.js";
const kNetworkInterfaceStateChangedTopic = "network-interface-state-changed";
const kMozSettingsChangedObserverTopic = "mozsettings-changed";
const MAX_RETRIES_ON_AUTHENTICATION_FAILURE = 2;
const MAX_SUPPLICANT_LOOP_ITERATIONS = 4;
@ -27,6 +28,10 @@ XPCOMUtils.defineLazyServiceGetter(this, "gNetworkManager",
"@mozilla.org/network/manager;1",
"nsINetworkManager");
XPCOMUtils.defineLazyServiceGetter(this, "gSettingsService",
"@mozilla.org/settingsService;1",
"nsISettingsService");
// A note about errors and error handling in this file:
// The libraries that we use in this file are intended for C code. For
// C code, it is natural to return -1 for errors and 0 for success.
@ -998,8 +1003,8 @@ var WifiManager = (function() {
}
// Get wifi interface and load wifi driver when enable Ap mode.
manager.setWifiApEnabled = function(enable, callback) {
if (enable) {
manager.setWifiApEnabled = function(enabled, callback) {
if (enabled) {
getProperty("wifi.interface", "tiwlan0", function (ifname) {
if (!ifname) {
callback(-1, null);
@ -1362,7 +1367,7 @@ function WifiWorker() {
this._mm = Cc["@mozilla.org/parentprocessmessagemanager;1"]
.getService(Ci.nsIMessageListenerManager);
const messages = ["WifiManager:setEnabled", "WifiManager:getNetworks",
const messages = ["WifiManager:getNetworks",
"WifiManager:associate", "WifiManager:forget",
"WifiManager:wps", "WifiManager:getState",
"WifiManager:managerFinished"];
@ -1371,6 +1376,8 @@ function WifiWorker() {
this._mm.addMessageListener(msgName, this);
}).bind(this));
Services.obs.addObserver(this, kMozSettingsChangedObserverTopic, false);
this.wantScanResults = [];
this._needToEnableNetworks = false;
@ -1464,6 +1471,7 @@ function WifiWorker() {
WifiManager.onsupplicantconnection = function() {
debug("Connected to supplicant");
WifiManager.enabled = true;
self._updateWifiSetting(true);
WifiManager.getMacAddress(function (mac) {
debug("Got mac: " + mac);
});
@ -1475,44 +1483,47 @@ function WifiWorker() {
self.waitForScan(function firstScan() {});
});
// Check if we need to fire request replies first:
if (self._stateRequests.length > 0)
self._notifyAfterStateChange(true, true);
// Check if we need to dequeue requests first.
self._notifyAfterStateChange(true, true);
// Notify everybody, even if they didn't ask us to come up.
self._fireEvent("wifiUp", {});
}
};
WifiManager.onsupplicantlost = function() {
WifiManager.enabled = WifiManager.supplicantStarted = false;
self._updateWifiSetting(false);
WifiManager.state = "UNINITIALIZED";
debug("Supplicant died!");
// Check if we need to fire request replies first:
if (self._stateRequests.length > 0)
self._notifyAfterStateChange(true, false);
// Check if we need to dequeue requests first.
self._notifyAfterStateChange(true, false);
// Notify everybody, even if they didn't ask us to come up.
self._fireEvent("wifiDown", {});
}
};
WifiManager.onsupplicantfailed = function() {
WifiManager.enabled = WifiManager.supplicantStarted = false;
self._updateWifiSetting(false);
WifiManager.state = "UNINITIALIZED";
debug("Couldn't connect to supplicant");
if (self._stateRequests.length > 0)
self._notifyAfterStateChange(false, false);
}
// Check if we need to dequeue requests first.
self._notifyAfterStateChange(false, false);
};
WifiManager.onpasswordmaybeincorrect = function() {
WifiManager.authenticationFailuresCount++;
}
};
WifiManager.ondisconnected = function() {
var currentNetwork = self.currentNetwork;
if (currentNetwork) {
WifiManager.disableNetwork(currentNetwork.netId, function() {});
self._fireEvent("onconnectingfailed", {network: currentNetwork});
}
}
};
WifiManager.onstatechange = function() {
debug("State change: " + this.prevState + " -> " + this.state);
@ -1705,16 +1716,26 @@ function WifiWorker() {
self.wantScanResults.forEach(function(callback) { callback(self.networks) });
self.wantScanResults = [];
});
}
};
WifiManager.setWifiEnabled(true, function (ok) {
if (ok === 0)
WifiManager.start();
else
debug("Couldn't start Wifi");
});
debug("Wifi starting");
// Read the 'wifi.enabled' setting in order to start with a known
// value at boot time. The handle() will be called after reading.
//
// nsISettingsServiceCallback implementation
var initWifiEnabledCb = {
handle: function handle(aName, aResult) {
if (aName !== "wifi.enabled")
return;
if (aResult === null)
aResult = true;
self.setWifiEnabled({enabled: aResult});
},
handleError: function handleError(aErrorMessage) {
debug("Error reading the 'wifi.enabled' setting. Default to wifi on.");
self.setWifiEnabled({enabled: true});
},
};
gSettingsService.getLock().get("wifi.enabled", initWifiEnabledCb);
}
function translateState(state) {
@ -1744,7 +1765,8 @@ WifiWorker.prototype = {
contractID: WIFIWORKER_CONTRACTID,
classDescription: "WifiWorker",
interfaces: [Ci.nsIWorkerHolder,
Ci.nsIWifi]}),
Ci.nsIWifi,
Ci.nsIObserver]}),
QueryInterface: XPCOMUtils.generateQI([Ci.nsIWorkerHolder,
Ci.nsIWifi]),
@ -1941,9 +1963,6 @@ WifiWorker.prototype = {
msg.manager = aMessage.target;
switch (aMessage.name) {
case "WifiManager:setEnabled":
this.setWifiEnabled(msg);
break;
case "WifiManager:getNetworks":
this.getNetworks(msg);
break;
@ -2019,6 +2038,9 @@ WifiWorker.prototype = {
},
_notifyAfterStateChange: function(success, newState) {
if (!this._stateRequests.length)
return;
// First, notify all of the requests that were trying to make this change.
let state = this._stateRequests[0].enabled;
@ -2034,9 +2056,7 @@ WifiWorker.prototype = {
if (!success || state === newState) {
do {
if (!("callback" in this._stateRequests[0])) {
let req = this._stateRequests.shift();
this._sendMessage("WifiManager:setEnabled:Return",
success, state, req);
this._stateRequests.shift();
}
// Don't remove more than one request if the previous one failed.
} while (success &&
@ -2087,7 +2107,6 @@ WifiWorker.prototype = {
// and handle each on/off request in turn.
// - Because we can't pass a callback to WifiManager.start, we need to
// have a way to communicate with our onsupplicantconnection callback.
msg.enabled = msg.data;
this._stateRequests.push(msg);
if (this._stateRequests.length === 1) {
if ("callback" in this._stateRequests[0]) {
@ -2098,12 +2117,12 @@ WifiWorker.prototype = {
}
},
setWifiEnabledInternal: function(enable, callback) {
this.setWifiEnabled({enabled: enable, callback: callback});
setWifiEnabledInternal: function(enabled, callback) {
this.setWifiEnabled({enabled: enabled, callback: callback});
},
setWifiApEnabled: function(enable, callback) {
WifiManager.setWifiApEnabled(enable, callback);
setWifiApEnabled: function(enabled, callback) {
WifiManager.setWifiApEnabled(enabled, callback);
},
associate: function(msg) {
@ -2247,7 +2266,7 @@ WifiWorker.prototype = {
shutdown: function() {
debug("shutting down ...");
this.setWifiEnabled(false);
this.setWifiEnabled({enabled: false});
},
setWifiTethering: function(enabled, callback) {
@ -2289,6 +2308,36 @@ WifiWorker.prototype = {
// This should not be happened. Return error to NetworkManager.
callback.wifiTetheringEnabledChange(1, null);
}
},
_updateWifiSetting: function(enabled) {
// This is used to update the setting value, whenever the
// WifiManager.enabled is re-assigned based on supplicant
// connection/lost/failed.
//
// To avoid WifiWorker setting the wifi again, we mark the
// "fromInternalSetting" so WifiWorker won't deal with such
// an internal "mozsettings-changed" event when receiving it.
gSettingsService.getLock().set(
"wifi.enabled", enabled, null, "fromInternalSetting");
},
// nsIObserver implementation
observe: function observe(subject, topic, data) {
// Note that this function gets called for any and all settings changes,
// so we need to carefully check if we have the one we're interested in.
// The string we're interested in will be a JSON string that looks like:
// {"key":"wifi.enabled","value":"true"}.
if (topic !== kMozSettingsChangedObserverTopic)
return;
let setting = JSON.parse(data);
if (setting.key !== "wifi.enabled")
return;
// To avoid WifiWorker setting the wifi again, don't need to deal with
// the "mozsettings-changed" event fired from internal setting.
if (setting.message && setting.message === "fromInternalSetting")
return;
this.setWifiEnabled({enabled: setting.value});
}
};

View File

@ -36,18 +36,9 @@ interface nsIWifi : nsISupports
void setWifiTethering(in boolean enabled, in nsIWifiTetheringCallback callback);
};
[scriptable, uuid(b1f2e67f-75a8-4781-bf7f-eb21662ae9f3)]
[scriptable, uuid(540674a6-edbe-11e1-87c9-dbcd31c74284)]
interface nsIDOMWifiManager : nsISupports
{
/**
* TODO Remove in favor of a settings API.
* Activates or disactivates wifi.
* onsuccess: Wifi has been successfully activated and can start
* attempting to connect to networks. request.value will be true.
* onerror: Wifi was not successfully activated. (TODO provide details!)
*/
nsIDOMDOMRequest setEnabled(in boolean enabled);
/**
* Returns the list of currently available networks as well as the list of
* currently configured networks.
@ -97,7 +88,6 @@ interface nsIDOMWifiManager : nsISupports
nsIDOMDOMRequest wps(in jsval detail);
/**
* TODO Remove in favor of a settings API.
* Returns whether or not wifi is currently enabled.
*/
readonly attribute boolean enabled;

View File

@ -1470,12 +1470,14 @@ uint32_t nsWindowWatcher::CalculateChromeFlags(nsIDOMWindow *aParent,
nsCOMPtr<nsIScriptSecurityManager>
securityManager(do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID));
NS_ENSURE_TRUE(securityManager, NS_ERROR_FAILURE);
bool isChrome = false;
nsresult rv = securityManager->SubjectPrincipalIsSystem(&isChrome);
if (NS_FAILED(rv)) {
isChrome = false;
nsresult rv;
if (securityManager) {
rv = securityManager->SubjectPrincipalIsSystem(&isChrome);
if (NS_FAILED(rv)) {
isChrome = false;
}
}
nsCOMPtr<nsIPrefBranch> prefBranch;
@ -1578,11 +1580,13 @@ uint32_t nsWindowWatcher::CalculateChromeFlags(nsIDOMWindow *aParent,
*/
// Check security state for use in determing window dimensions
bool enabled;
nsresult res =
securityManager->IsCapabilityEnabled("UniversalXPConnect", &enabled);
bool enabled = false;
if (securityManager) {
rv = securityManager->IsCapabilityEnabled("UniversalXPConnect",
&enabled);
}
if (NS_FAILED(res) || !enabled || (isChrome && !aHasChromeParent)) {
if (NS_FAILED(rv) || !enabled || (isChrome && !aHasChromeParent)) {
// If priv check fails (or if we're called from chrome, but the
// parent is not a chrome window), set all elements to minimum
// reqs., else leave them alone.

View File

@ -727,6 +727,21 @@ public:
virtual TemporaryRef<DrawTarget>
CreateSimilarDrawTarget(const IntSize &aSize, SurfaceFormat aFormat) const = 0;
/*
* Create a draw target optimized for drawing a shadow.
*
* Note that aSigma is the blur radius that must be used when we draw the
* shadow. Also note that this doesn't affect the size of the allocated
* surface, the caller is still responsible for including the shadow area in
* its size.
*/
virtual TemporaryRef<DrawTarget>
CreateShadowDrawTarget(const IntSize &aSize, SurfaceFormat aFormat,
float aSigma) const
{
return CreateSimilarDrawTarget(aSize, aFormat);
}
/*
* Create a path builder with the specified fillmode.
*

View File

@ -330,7 +330,8 @@ AlphaBoxBlur::AlphaBoxBlur(const Rect& aRect,
const Rect* aSkipRect)
: mSpreadRadius(aSpreadRadius),
mBlurRadius(aBlurRadius),
mData(nullptr)
mData(nullptr),
mFreeData(true)
{
Rect rect(aRect);
rect.Inflate(Size(aBlurRadius + aSpreadRadius));
@ -384,9 +385,25 @@ AlphaBoxBlur::AlphaBoxBlur(const Rect& aRect,
}
}
AlphaBoxBlur::AlphaBoxBlur(uint8_t* aData,
const Rect& aRect,
int32_t aStride,
float aSigma)
: mSpreadRadius(),
mBlurRadius(CalculateBlurRadius(Point(aSigma, aSigma))),
mData(aData),
mFreeData(false),
mStride(aStride),
mRect(aRect.x, aRect.y, aRect.width, aRect.height)
{
}
AlphaBoxBlur::~AlphaBoxBlur()
{
free(mData);
if (mFreeData) {
delete mData;
}
}
unsigned char*

View File

@ -57,6 +57,11 @@ public:
const Rect* aDirtyRect,
const Rect* aSkipRect);
AlphaBoxBlur(uint8_t* aData,
const Rect& aRect,
int32_t aStride,
float aSigma);
~AlphaBoxBlur();
/**
@ -135,7 +140,12 @@ private:
/**
* A pointer to the backing 8-bit alpha surface.
*/
unsigned char* mData;
uint8_t* mData;
/**
* True if we need to dispose the data.
*/
bool mFreeData;
/**
* The stride of the data contained in mData.

View File

@ -11,6 +11,7 @@
#include "ScaledFontBase.h"
#include "cairo.h"
#include "cairo-tee.h"
#include <string.h>
#include "Blur.h"
@ -280,6 +281,7 @@ NeedIntermediateSurface(const Pattern& aPattern, const DrawOptions& aOptions)
DrawTargetCairo::DrawTargetCairo()
: mContext(nullptr)
, mPathObserver(nullptr)
{
}
@ -387,49 +389,35 @@ DrawTargetCairo::DrawSurfaceWithShadow(SourceSurface *aSurface,
return;
}
WillChange();
Float width = aSurface->GetSize().width;
Float height = aSurface->GetSize().height;
Rect extents(0, 0, width, height);
SourceSurfaceCairo* source = static_cast<SourceSurfaceCairo*>(aSurface);
cairo_surface_t* sourcesurf = source->GetSurface();
cairo_surface_t* blursurf;
cairo_surface_t* surf;
AlphaBoxBlur blur(extents, IntSize(0, 0),
AlphaBoxBlur::CalculateBlurRadius(Point(aSigma, aSigma)),
nullptr, nullptr);
if (!blur.GetData()) {
return;
// We only use the A8 surface for blurred shadows. Unblurred shadows can just
// use the RGBA surface directly.
if (cairo_surface_get_type(sourcesurf) == CAIRO_SURFACE_TYPE_TEE) {
blursurf = cairo_tee_surface_index(sourcesurf, 0);
surf = cairo_tee_surface_index(sourcesurf, 1);
MOZ_ASSERT(cairo_surface_get_type(blursurf) == CAIRO_SURFACE_TYPE_IMAGE);
Rect extents(0, 0, width, height);
AlphaBoxBlur blur(cairo_image_surface_get_data(blursurf),
extents,
cairo_image_surface_get_stride(blursurf),
aSigma);
blur.Blur();
} else {
blursurf = sourcesurf;
surf = sourcesurf;
}
IntSize blursize = blur.GetSize();
cairo_surface_t* blursurf = cairo_image_surface_create_for_data(blur.GetData(),
CAIRO_FORMAT_A8,
blursize.width,
blursize.height,
blur.GetStride());
WillChange();
ClearSurfaceForUnboundedSource(aOperator);
// Draw the source surface into the surface we're going to blur.
SourceSurfaceCairo* source = static_cast<SourceSurfaceCairo*>(aSurface);
cairo_surface_t* surf = source->GetSurface();
cairo_pattern_t* pat = cairo_pattern_create_for_surface(surf);
cairo_pattern_set_extend(pat, CAIRO_EXTEND_PAD);
cairo_t* ctx = cairo_create(blursurf);
cairo_set_source(ctx, pat);
IntRect blurrect = blur.GetRect();
cairo_new_path(ctx);
cairo_rectangle(ctx, blurrect.x, blurrect.y, blurrect.width, blurrect.height);
cairo_clip(ctx);
cairo_paint(ctx);
cairo_destroy(ctx);
// Blur the result, then use that blurred result as a mask to draw the shadow
// colour to the surface.
blur.Blur();
cairo_save(mContext);
cairo_set_operator(mContext, GfxOpToCairoOp(aOperator));
cairo_identity_matrix(mContext);
@ -440,33 +428,26 @@ DrawTargetCairo::DrawSurfaceWithShadow(SourceSurface *aSurface,
cairo_push_group(mContext);
cairo_set_source_rgba(mContext, aColor.r, aColor.g, aColor.b, aColor.a);
cairo_mask_surface(mContext, blursurf, aOffset.x, aOffset.y);
cairo_pop_group_to_source(mContext);
cairo_paint(mContext);
// Now that the shadow has been drawn, we can draw the surface on top.
cairo_push_group(mContext);
// Now that the shadow has been drawn, we can draw the surface on top.
cairo_set_source_surface(mContext, surf, 0, 0);
cairo_new_path(mContext);
cairo_rectangle(mContext, 0, 0, width, height);
cairo_set_source(mContext, pat);
cairo_fill(mContext);
cairo_pop_group_to_source(mContext);
cairo_paint(mContext);
} else {
cairo_set_source_rgba(mContext, aColor.r, aColor.g, aColor.b, aColor.a);
cairo_mask_surface(mContext, blursurf, aOffset.x, aOffset.y);
// Now that the shadow has been drawn, we can draw the surface on top.
cairo_set_source(mContext, pat);
cairo_set_source_surface(mContext, surf, 0, 0);
cairo_new_path(mContext);
cairo_rectangle(mContext, 0, 0, width, height);
cairo_clip(mContext);
cairo_fill(mContext);
}
cairo_paint(mContext);
cairo_restore(mContext);
cairo_pattern_destroy(pat);
cairo_surface_destroy(blursurf);
}
void
@ -707,11 +688,6 @@ DrawTargetCairo::CreatePathBuilder(FillRule aFillRule /* = FILL_WINDING */) cons
const_cast<DrawTargetCairo*>(this),
aFillRule);
// Creating a PathBuilder implicitly resets our mPathObserver, as it calls
// SetPathObserver() on us. Since this guarantees our old path is saved off,
// it's safe to reset the path here.
cairo_new_path(mContext);
return builder;
}
@ -821,6 +797,49 @@ DrawTargetCairo::InitAlreadyReferenced(cairo_surface_t* aSurface, const IntSize&
return true;
}
TemporaryRef<DrawTarget>
DrawTargetCairo::CreateShadowDrawTarget(const IntSize &aSize, SurfaceFormat aFormat,
float aSigma) const
{
cairo_surface_t* similar = cairo_surface_create_similar(cairo_get_target(mContext),
GfxFormatToCairoContent(aFormat),
aSize.width, aSize.height);
if (cairo_surface_status(similar)) {
return nullptr;
}
// If we don't have a blur then we can use the RGBA mask and keep all the
// operations in graphics memory.
if (aSigma == 0.0F) {
RefPtr<DrawTargetCairo> target = new DrawTargetCairo();
target->InitAlreadyReferenced(similar, aSize);
return target;
}
cairo_surface_t* blursurf = cairo_image_surface_create(CAIRO_FORMAT_A8,
aSize.width,
aSize.height);
if (cairo_surface_status(blursurf)) {
return nullptr;
}
cairo_surface_t* tee = cairo_tee_surface_create(blursurf);
cairo_surface_destroy(blursurf);
if (cairo_surface_status(tee)) {
cairo_surface_destroy(similar);
return nullptr;
}
cairo_tee_surface_add(tee, similar);
cairo_surface_destroy(similar);
RefPtr<DrawTargetCairo> target = new DrawTargetCairo();
target->InitAlreadyReferenced(tee, aSize);
return target;
}
bool
DrawTargetCairo::Init(cairo_surface_t* aSurface, const IntSize& aSize)
{
@ -898,12 +917,6 @@ DrawTargetCairo::SetPathObserver(CairoPathContext* aPathObserver)
void
DrawTargetCairo::SetTransform(const Matrix& aTransform)
{
// We're about to logically change our transformation. Our current path will
// need to change, because Cairo stores paths in device space.
if (mPathObserver) {
mPathObserver->MatrixWillChange(aTransform);
}
mTransform = aTransform;
cairo_matrix_t mat;

View File

@ -115,6 +115,9 @@ public:
CreateSourceSurfaceFromNativeSurface(const NativeSurface &aSurface) const;
virtual TemporaryRef<DrawTarget>
CreateSimilarDrawTarget(const IntSize &aSize, SurfaceFormat aFormat) const;
virtual TemporaryRef<DrawTarget>
CreateShadowDrawTarget(const IntSize &aSize, SurfaceFormat aFormat,
float aSigma) const;
virtual TemporaryRef<GradientStops>
CreateGradientStops(GradientStop *aStops,
@ -166,7 +169,12 @@ private: // data
cairo_surface_t* mSurface;
IntSize mSize;
std::vector<SourceSurfaceCairo*> mSnapshots;
mutable RefPtr<CairoPathContext> mPathObserver;
// It is safe to use a regular pointer here because the CairoPathContext will
// deregister itself on destruction. Using a RefPtr would extend the life-
// span of the CairoPathContext. This causes a problem when
// PathBuilderCairo.Finish()
mutable CairoPathContext* mPathObserver;
};
}

View File

@ -207,6 +207,32 @@ GfxFillRuleToCairoFillRule(FillRule rule)
return CAIRO_FILL_RULE_WINDING;
}
// RAII class for temporarily changing the cairo matrix transform. It will use
// the given matrix transform while it is in scope. When it goes out of scope
// it will put the cairo context back the way it was.
class CairoTempMatrix
{
public:
CairoTempMatrix(cairo_t* aCtx, const Matrix& aMatrix)
: mCtx(aCtx)
{
cairo_get_matrix(aCtx, &mSaveMatrix);
cairo_matrix_t matrix;
GfxMatrixToCairoMatrix(aMatrix, matrix);
cairo_set_matrix(aCtx, &matrix);
}
~CairoTempMatrix()
{
cairo_get_matrix(mCtx, &mSaveMatrix);
}
private:
cairo_t* mCtx;
cairo_matrix_t mSaveMatrix;
};
}
}

View File

@ -13,61 +13,40 @@
namespace mozilla {
namespace gfx {
CairoPathContext::CairoPathContext(cairo_t* aCtx, DrawTargetCairo* aDrawTarget,
FillRule aFillRule,
const Matrix& aTransform /* = Matrix() */)
: mTransform(aTransform)
, mContext(aCtx)
CairoPathContext::CairoPathContext(cairo_t* aCtx, DrawTargetCairo* aDrawTarget)
: mContext(aCtx)
, mDrawTarget(aDrawTarget)
, mFillRule(aFillRule)
{
cairo_reference(mContext);
cairo_set_fill_rule(mContext, GfxFillRuleToCairoFillRule(mFillRule));
// If we don't have an identity transformation, we need to have a separate
// context from the draw target, because we can't set a transformation on its
// context.
if (mDrawTarget && !mTransform.IsIdentity()) {
DuplicateContextAndPath(mTransform);
// A new path in the DrawTarget's context.
aDrawTarget->SetPathObserver(this);
cairo_new_path(mContext);
}
ForgetDrawTarget();
} else if (mDrawTarget) {
mDrawTarget->SetPathObserver(this);
}
CairoPathContext::CairoPathContext(CairoPathContext& aPathContext)
: mContext(aPathContext.mContext)
, mDrawTarget(nullptr)
{
cairo_reference(mContext);
DuplicateContextAndPath();
}
CairoPathContext::~CairoPathContext()
{
if (mDrawTarget) {
mDrawTarget->SetPathObserver(nullptr);
DrawTargetCairo* drawTarget = mDrawTarget;
ForgetDrawTarget();
// We need to set mDrawTarget to nullptr before we tell DrawTarget otherwise
// we will think we need to make a defensive copy of the path.
drawTarget->SetPathObserver(nullptr);
}
cairo_destroy(mContext);
}
void
CairoPathContext::ObserveTarget(DrawTargetCairo* aDrawTarget)
{
if (!aDrawTarget) {
return;
}
if (mDrawTarget) {
mDrawTarget->SetPathObserver(nullptr);
}
mDrawTarget = aDrawTarget;
// If there is a transform on the path, then we must have a separate context
// from the draw target, so we cannot be its observer
if (!mTransform.IsIdentity()) {
ForgetDrawTarget();
return;
}
mDrawTarget->SetPathObserver(this);
}
void
CairoPathContext::DuplicateContextAndPath(const Matrix& aMatrix /* = Matrix() */)
CairoPathContext::DuplicateContextAndPath()
{
// Duplicate the path.
cairo_path_t* path = cairo_copy_path(mContext);
@ -75,20 +54,31 @@ CairoPathContext::DuplicateContextAndPath(const Matrix& aMatrix /* = Matrix() */
// Duplicate the context.
cairo_surface_t* surf = cairo_get_target(mContext);
cairo_matrix_t matrix;
cairo_get_matrix(mContext, &matrix);
cairo_destroy(mContext);
mContext = cairo_create(surf);
// Transform the context.
cairo_matrix_t matrix;
GfxMatrixToCairoMatrix(aMatrix, matrix);
cairo_transform(mContext, &matrix);
// Set the matrix to match the source context so that the path is copied in
// device space. After this point it doesn't matter what the transform is
// set to because it's always swapped out before use.
cairo_set_matrix(mContext, &matrix);
// Add the path, and throw away our duplicate.
cairo_append_path(mContext, path);
cairo_set_fill_rule(mContext, rule);
cairo_path_destroy(path);
}
void
CairoPathContext::ForgetDrawTarget()
{
// We don't need to set the path observer back to nullptr in this case
// because ForgetDrawTarget() is trigged when the target has been
// grabbed by another path observer.
mDrawTarget = nullptr;
}
void
CairoPathContext::PathWillChange()
{
@ -100,68 +90,22 @@ CairoPathContext::PathWillChange()
// The context we point to is going to change from under us. To continue
// using this path, we need to copy it to a new context.
DuplicateContextAndPath();
ForgetDrawTarget();
}
}
void
CairoPathContext::MatrixWillChange(const Matrix& aNewMatrix)
{
// Cairo paths are stored in device space. Since we logically operate in user
// space, we want to make it so our path will be in the same location if and
// when our path is copied out.
// To effect this, we copy out our path (which, in Cairo, implicitly converts
// to user space), then temporarily set the context to have the new
// transform. We then set the path, which ensures that the points are all
// transformed correctly. Finally, we set the matrix back to its original
// value.
cairo_path_t* path = cairo_copy_path(mContext);
cairo_matrix_t origMatrix;
cairo_get_matrix(mContext, &origMatrix);
cairo_matrix_t newMatrix;
GfxMatrixToCairoMatrix(aNewMatrix, newMatrix);
cairo_set_matrix(mContext, &newMatrix);
cairo_new_path(mContext);
cairo_append_path(mContext, path);
cairo_path_destroy(path);
cairo_set_matrix(mContext, &origMatrix);
}
void
CairoPathContext::CopyPathTo(cairo_t* aToContext)
CairoPathContext::CopyPathTo(cairo_t* aToContext, Matrix& aTransform)
{
if (aToContext != mContext) {
cairo_set_fill_rule(aToContext, GfxFillRuleToCairoFillRule(mFillRule));
cairo_matrix_t origMat;
cairo_get_matrix(aToContext, &origMat);
cairo_matrix_t mat;
GfxMatrixToCairoMatrix(mTransform, mat);
cairo_transform(aToContext, &mat);
// cairo_copy_path gives us a user-space copy of the path, so we don't have
// to worry about transformations here.
CairoTempMatrix tempMatrix(mContext, aTransform);
cairo_path_t* path = cairo_copy_path(mContext);
cairo_new_path(aToContext);
cairo_append_path(aToContext, path);
cairo_path_destroy(path);
cairo_set_matrix(aToContext, &origMat);
}
}
void
CairoPathContext::ForgetDrawTarget()
{
mDrawTarget = nullptr;
}
bool
CairoPathContext::ContainsPath(const Path* aPath)
{
@ -175,38 +119,32 @@ CairoPathContext::ContainsPath(const Path* aPath)
}
PathBuilderCairo::PathBuilderCairo(CairoPathContext* aPathContext,
FillRule aFillRule,
const Matrix& aTransform /* = Matrix() */)
: mFillRule(aPathContext->GetFillRule())
{
RefPtr<DrawTargetCairo> drawTarget = aPathContext->GetDrawTarget();
mPathContext = new CairoPathContext(*aPathContext, drawTarget, mFillRule,
aPathContext->GetTransform() * aTransform);
// We need to ensure that we are allowed to modify the path currently set on
// aPathContext. If we don't have a draw target, CairoPathContext's
// constructor has no way to make aPathContext duplicate its path (normally,
// calling drawTarget->SetPathObserver() would do so). In this case, we
// explicitly make aPathContext copy out its context and path, leaving our
// path alone.
if (!drawTarget) {
aPathContext->DuplicateContextAndPath();
}
}
: mPathContext(aPathContext)
, mTransform(aTransform)
, mFillRule(aFillRule)
{}
PathBuilderCairo::PathBuilderCairo(cairo_t* aCtx, DrawTargetCairo* aDrawTarget, FillRule aFillRule)
: mPathContext(new CairoPathContext(aCtx, aDrawTarget, aFillRule))
: mPathContext(new CairoPathContext(aCtx, aDrawTarget))
, mTransform(aDrawTarget->GetTransform())
, mFillRule(aFillRule)
{}
void
PathBuilderCairo::MoveTo(const Point &aPoint)
{
PrepareForWrite();
CairoTempMatrix tempMatrix(*mPathContext, mTransform);
cairo_move_to(*mPathContext, aPoint.x, aPoint.y);
}
void
PathBuilderCairo::LineTo(const Point &aPoint)
{
PrepareForWrite();
CairoTempMatrix tempMatrix(*mPathContext, mTransform);
cairo_line_to(*mPathContext, aPoint.x, aPoint.y);
}
@ -215,6 +153,8 @@ PathBuilderCairo::BezierTo(const Point &aCP1,
const Point &aCP2,
const Point &aCP3)
{
PrepareForWrite();
CairoTempMatrix tempMatrix(*mPathContext, mTransform);
cairo_curve_to(*mPathContext, aCP1.x, aCP1.y, aCP2.x, aCP2.y, aCP3.x, aCP3.y);
}
@ -222,6 +162,9 @@ void
PathBuilderCairo::QuadraticBezierTo(const Point &aCP1,
const Point &aCP2)
{
PrepareForWrite();
CairoTempMatrix tempMatrix(*mPathContext, mTransform);
// We need to elevate the degree of this quadratic Bézier to cubic, so we're
// going to add an intermediate control point, and recompute control point 1.
// The first and last control points remain the same.
@ -237,6 +180,7 @@ PathBuilderCairo::QuadraticBezierTo(const Point &aCP1,
void
PathBuilderCairo::Close()
{
PrepareForWrite();
cairo_close_path(*mPathContext);
}
@ -250,6 +194,7 @@ PathBuilderCairo::Arc(const Point &aOrigin, float aRadius, float aStartAngle,
Point
PathBuilderCairo::CurrentPoint() const
{
CairoTempMatrix tempMatrix(*mPathContext, mTransform);
double x, y;
cairo_get_current_point(*mPathContext, &x, &y);
return Point(x, y);
@ -258,11 +203,7 @@ PathBuilderCairo::CurrentPoint() const
TemporaryRef<Path>
PathBuilderCairo::Finish()
{
RefPtr<PathCairo> path = new PathCairo(*mPathContext,
mPathContext->GetDrawTarget(),
mFillRule,
mPathContext->GetTransform());
return path;
return new PathCairo(mPathContext, mTransform, mFillRule);
}
TemporaryRef<CairoPathContext>
@ -271,43 +212,63 @@ PathBuilderCairo::GetPathContext()
return mPathContext;
}
PathCairo::PathCairo(cairo_t* aCtx, DrawTargetCairo* aDrawTarget, FillRule aFillRule, const Matrix& aTransform)
: mPathContext(new CairoPathContext(aCtx, aDrawTarget, aFillRule, aTransform))
void
PathBuilderCairo::PrepareForWrite()
{
// Only PathBuilder and PathCairo maintain references to CairoPathContext.
// DrawTarget does not. If we're sharing a reference to the context then we
// need to create a copy that we can modify. This provides copy on write
// behaviour.
if (mPathContext->refCount() != 1) {
mPathContext = new CairoPathContext(*mPathContext);
}
}
PathCairo::PathCairo(CairoPathContext* aPathContext, Matrix& aTransform,
FillRule aFillRule)
: mPathContext(aPathContext)
, mTransform(aTransform)
, mFillRule(aFillRule)
{}
TemporaryRef<PathBuilder>
PathCairo::CopyToBuilder(FillRule aFillRule) const
{
// Note: This PathBuilderCairo constructor causes our mPathContext to copy
// out the path, since the path builder is going to change the path on us.
RefPtr<PathBuilderCairo> builder = new PathBuilderCairo(mPathContext);
return builder;
return new PathBuilderCairo(mPathContext, aFillRule, mTransform);
}
TemporaryRef<PathBuilder>
PathCairo::TransformedCopyToBuilder(const Matrix &aTransform, FillRule aFillRule) const
{
// Note: This PathBuilderCairo constructor causes our mPathContext to copy
// out the path, since the path builder is going to change the path on us.
RefPtr<PathBuilderCairo> builder = new PathBuilderCairo(mPathContext,
aTransform);
return builder;
// We are given the transform we would apply from device space to user space.
// However in cairo our path is in device space so we view the transform as
// being the other way round. We therefore need to apply the inverse transform
// to our current cairo transform.
Matrix inverse = aTransform;
inverse.Invert();
return new PathBuilderCairo(mPathContext, aFillRule, mTransform * inverse);
}
bool
PathCairo::ContainsPoint(const Point &aPoint, const Matrix &aTransform) const
{
CairoTempMatrix(*mPathContext, mTransform);
Matrix inverse = aTransform;
inverse.Invert();
Point transformed = inverse * aPoint;
// Needs the correct fill rule set.
cairo_set_fill_rule(*mPathContext, GfxFillRuleToCairoFillRule(mFillRule));
return cairo_in_fill(*mPathContext, transformed.x, transformed.y);
}
Rect
PathCairo::GetBounds(const Matrix &aTransform) const
{
CairoTempMatrix(*mPathContext, mTransform);
double x1, y1, x2, y2;
cairo_path_extents(*mPathContext, &x1, &y1, &x2, &y2);
@ -319,6 +280,8 @@ Rect
PathCairo::GetStrokedBounds(const StrokeOptions &aStrokeOptions,
const Matrix &aTransform) const
{
CairoTempMatrix(*mPathContext, mTransform);
double x1, y1, x2, y2;
SetCairoStrokeOptions(*mPathContext, aStrokeOptions);
@ -337,13 +300,8 @@ PathCairo::GetPathContext()
void
PathCairo::CopyPathTo(cairo_t* aContext, DrawTargetCairo* aDrawTarget)
{
if (mPathContext->GetContext() != aContext) {
mPathContext->CopyPathTo(aContext);
// Since aDrawTarget wants us to be the current path on its context, we
// should also listen to it for updates to that path (as an optimization).
mPathContext->ObserveTarget(aDrawTarget);
}
mPathContext->CopyPathTo(aContext, mTransform);
cairo_set_fill_rule(aContext, GfxFillRuleToCairoFillRule(mFillRule));
}
}

View File

@ -37,74 +37,57 @@ class DrawTargetCairo;
class CairoPathContext : public RefCounted<CairoPathContext>
{
public:
// Construct a CairoPathContext and set it to be the path observer of
// aDrawTarget. Optionally, this path can be transformed by aMatrix.
CairoPathContext(cairo_t* aCtx, DrawTargetCairo* aDrawTarget,
FillRule aFillRule,
const Matrix& aMatrix = Matrix());
// Construct a new empty CairoPathContext that uses the given draw target and
// its cairo context. Using the existing context may save having to copy the
// path later.
CairoPathContext(cairo_t* aCtx, DrawTargetCairo* aDrawTarget);
// Copy the path.
CairoPathContext(CairoPathContext& aPathContext);
~CairoPathContext();
// Copy the path on mContext to be the path on aToContext, if they aren't the
// same.
void CopyPathTo(cairo_t* aToContext);
// same. At this point we set the fill rule for the destination context as
// there is little point in doing this earlier.
void CopyPathTo(cairo_t* aToContext, Matrix& aTransform);
// This method must be called by the draw target before it changes the path
// currently on the cairo context.
void PathWillChange();
// This method must be called by the draw target whenever it is going to
// change the current transformation on mContext.
void MatrixWillChange(const Matrix& aMatrix);
// This method must be called as the draw target is dying. In this case, we
// forget our reference to the draw target, and become the only reference to
// our context.
void ForgetDrawTarget();
// Create a duplicate context, and copy this path to that context. Optionally,
// the new context can be transformed.
void DuplicateContextAndPath(const Matrix& aMatrix = Matrix());
// Create a duplicate context, and copy this path to that context.
void DuplicateContextAndPath();
// Returns true if this CairoPathContext represents path.
bool ContainsPath(const Path* path);
// add ourselves as an observer of aDrawTarget, if possible
// if we succeed, then mDrawTarget is set to aDrawTarget
void ObserveTarget(DrawTargetCairo* aDrawTarget);
cairo_t* GetContext() const { return mContext; }
DrawTargetCairo* GetDrawTarget() const { return mDrawTarget; }
Matrix GetTransform() const { return mTransform; }
FillRule GetFillRule() const { return mFillRule; }
operator cairo_t* () const { return mContext; }
private: // methods
CairoPathContext(const CairoPathContext&) MOZ_DELETE;
private: // data
Matrix mTransform;
cairo_t* mContext;
// Not a RefPtr to avoid cycles.
DrawTargetCairo* mDrawTarget;
FillRule mFillRule;
};
class PathBuilderCairo : public PathBuilder
{
public:
// This constructor implicitly takes ownership of aCtx by calling
// aDrawTarget->SetPathObserver(). Therefore, if the draw target has a path
// observer, this constructor will cause it to copy out its path.
// The path currently set on aCtx is not changed.
// Creates a new empty path. It also implicitly takes ownership of aCtx by
// calling aDrawTarget->SetPathObserver(). Therefore, if the draw target has a
// path observer, this constructor will cause it to copy out its path.
PathBuilderCairo(cairo_t* aCtx, DrawTargetCairo* aDrawTarget, FillRule aFillRule);
// This constructor, called with a CairoPathContext*, implicitly takes
// ownership of the path, and therefore makes aPathContext copy out its path
// regardless of whether it has a pointer to a DrawTargetCairo.
// The path currently set on aPathContext is not changed.
explicit PathBuilderCairo(CairoPathContext* aPathContext,
const Matrix& aTransform = Matrix());
// Creates a path builder out of an existing CairoPathContext with a new fill
// rule and transform.
PathBuilderCairo(CairoPathContext* aContext, FillRule aFillRule, const Matrix& aTransform = Matrix());
virtual void MoveTo(const Point &aPoint);
virtual void LineTo(const Point &aPoint);
@ -121,18 +104,18 @@ public:
TemporaryRef<CairoPathContext> GetPathContext();
private: // methods
void SetFillRule(FillRule aFillRule);
private: // data
void PrepareForWrite();
RefPtr<CairoPathContext> mPathContext;
Matrix mTransform;
FillRule mFillRule;
};
class PathCairo : public Path
{
public:
PathCairo(cairo_t* aCtx, DrawTargetCairo* aDrawTarget, FillRule aFillRule, const Matrix& aTransform);
PathCairo(CairoPathContext* aPathContex, Matrix& aTransform, FillRule aFillRule);
virtual BackendType GetBackendType() const { return BACKEND_CAIRO; }
@ -158,6 +141,7 @@ public:
private:
RefPtr<CairoPathContext> mPathContext;
Matrix mTransform;
FillRule mFillRule;
};

View File

@ -30,6 +30,7 @@ public:
BasicPlanarYCbCrImage(const gfxIntSize& aScaleHint, gfxImageFormat aOffscreenFormat, BufferRecycleBin *aRecycleBin)
: PlanarYCbCrImage(aRecycleBin)
, mScaleHint(aScaleHint)
, mDelayedConversion(false)
{
SetOffscreenFormat(aOffscreenFormat);
}
@ -44,12 +45,15 @@ public:
}
virtual void SetData(const Data& aData);
virtual void SetDelayedConversion(bool aDelayed) { mDelayedConversion = aDelayed; }
already_AddRefed<gfxASurface> GetAsSurface();
private:
nsAutoArrayPtr<uint8_t> mDecodedBuffer;
gfxIntSize mScaleHint;
int mStride;
nsAutoArrayPtr<uint8_t> mDecodedBuffer;
bool mDelayedConversion;
};
class BasicImageFactory : public ImageFactory
@ -81,6 +85,10 @@ BasicPlanarYCbCrImage::SetData(const Data& aData)
{
PlanarYCbCrImage::SetData(aData);
if (mDelayedConversion) {
return;
}
// Do some sanity checks to prevent integer overflow
if (aData.mYSize.width > PlanarYCbCrImage::MAX_DIMENSION ||
aData.mYSize.height > PlanarYCbCrImage::MAX_DIMENSION) {

View File

@ -535,8 +535,23 @@ gfxPlatform::GetSourceSurfaceForSurface(DrawTarget *aTarget, gfxASurface *aSurfa
dt->Flush();
}
srcBuffer = aTarget->CreateSourceSurfaceFromNativeSurface(surf);
}
} else
#endif
if (aSurface->CairoSurface() && aTarget->GetType() == BACKEND_CAIRO) {
// If this is an xlib cairo surface we don't want to fetch it into memory
// because this is a major slow down.
NativeSurface surf;
surf.mFormat = format;
surf.mType = NATIVE_SURFACE_CAIRO_SURFACE;
surf.mSurface = aSurface->CairoSurface();
srcBuffer = aTarget->CreateSourceSurfaceFromNativeSurface(surf);
if (srcBuffer) {
// It's cheap enough to make a new one so we won't keep it around and
// keeping it creates a cycle.
return srcBuffer;
}
}
if (!srcBuffer) {
nsRefPtr<gfxImageSurface> imgSurface = aSurface->GetAsImageSurface();

View File

@ -3219,7 +3219,7 @@ fi
dnl Top-level Mozilla switched to requiring NSPR 4.8.6 (bug 560582), but we don't need it in JS.
if test -n "$_USE_SYSTEM_NSPR"; then
MOZ_NATIVE_NSPR=
AM_PATH_NSPR(4.7.0, [MOZ_NATIVE_NSPR=1], [AC_MSG_ERROR([your don't have NSPR installed or your version is too old])])
AM_PATH_NSPR(4.9.2, [MOZ_NATIVE_NSPR=1], [AC_MSG_ERROR([your don't have NSPR installed or your version is too old])])
fi
if test -n "$MOZ_NATIVE_NSPR"; then

View File

@ -79,7 +79,7 @@ using namespace js::frontend;
JS_END_MACRO
#define MUST_MATCH_TOKEN(tt, errno) MUST_MATCH_TOKEN_WITH_FLAGS(tt, errno, 0)
StrictMode::StrictModeState
StrictMode
StrictModeGetter::get() const
{
return parser->pc->sc->strictModeState;
@ -388,7 +388,7 @@ Parser::newObjectBox(JSObject *obj)
}
FunctionBox::FunctionBox(ObjectBox* traceListHead, JSObject *obj, ParseContext *outerpc,
StrictMode::StrictModeState sms)
StrictMode sms)
: ObjectBox(traceListHead, obj),
siblings(outerpc->functionList),
kids(NULL),
@ -444,7 +444,7 @@ FunctionBox::FunctionBox(ObjectBox* traceListHead, JSObject *obj, ParseContext *
}
FunctionBox *
Parser::newFunctionBox(JSObject *obj, ParseContext *outerpc, StrictMode::StrictModeState sms)
Parser::newFunctionBox(JSObject *obj, ParseContext *outerpc, StrictMode sms)
{
JS_ASSERT(obj && !IsPoisonedPtr(obj));
JS_ASSERT(obj->isFunction());
@ -1612,7 +1612,7 @@ Parser::functionDef(HandlePropertyName funName, FunctionType type, FunctionSynta
return NULL;
// Inherit strictness if neeeded.
StrictMode::StrictModeState sms = (outerpc->sc->strictModeState == StrictMode::STRICT) ?
StrictMode sms = (outerpc->sc->strictModeState == StrictMode::STRICT) ?
StrictMode::STRICT : StrictMode::UNKNOWN;
// Create box for fun->object early to protect against last-ditch GC.
@ -1779,7 +1779,7 @@ Parser::functionExpr()
}
void
FunctionBox::recursivelySetStrictMode(StrictMode::StrictModeState strictness)
FunctionBox::recursivelySetStrictMode(StrictMode strictness)
{
if (strictModeState == StrictMode::UNKNOWN) {
strictModeState = strictness;

View File

@ -303,7 +303,7 @@ struct Parser : private AutoGCRooter
*/
ObjectBox *newObjectBox(JSObject *obj);
FunctionBox *newFunctionBox(JSObject *obj, ParseContext *pc, StrictMode::StrictModeState sms);
FunctionBox *newFunctionBox(JSObject *obj, ParseContext *pc, StrictMode sms);
/*
* Create a new function object given parse context (pc) and a name (which

View File

@ -16,7 +16,7 @@ namespace frontend {
inline
SharedContext::SharedContext(JSContext *cx, JSObject *scopeChain, JSFunction *fun,
FunctionBox *funbox, StrictMode::StrictModeState sms)
FunctionBox *funbox, StrictMode sms)
: context(cx),
fun_(cx, fun),
funbox_(funbox),

View File

@ -156,12 +156,12 @@ struct SharedContext {
// can have any kind of children.
//
// When parsing is done, no context may be in the UNKNOWN strictness state.
StrictMode::StrictModeState strictModeState;
StrictMode strictModeState;
// If it's function code, fun must be non-NULL and scopeChain must be NULL.
// If it's global code, fun and funbox must be NULL.
inline SharedContext(JSContext *cx, JSObject *scopeChain, JSFunction *fun, FunctionBox *funbox,
StrictMode::StrictModeState sms);
StrictMode sms);
// In theory, |fun*| flags are only relevant if |inFunction()| is true.
// However, we get and set in some cases where |inFunction()| is false,
@ -297,7 +297,7 @@ struct FunctionBox : public ObjectBox
size_t bufStart;
size_t bufEnd;
uint16_t ndefaults;
StrictMode::StrictModeState strictModeState;
StrictMode strictModeState;
bool inWith:1; /* some enclosing scope is a with-statement
or E4X filter-expression */
bool inGenexpLambda:1; /* lambda from generator expression */
@ -305,13 +305,13 @@ struct FunctionBox : public ObjectBox
ContextFlags cxFlags;
FunctionBox(ObjectBox* traceListHead, JSObject *obj, ParseContext *pc,
StrictMode::StrictModeState sms);
StrictMode sms);
bool funIsGenerator() const { return cxFlags.funIsGenerator; }
JSFunction *function() const { return (JSFunction *) object; }
void recursivelySetStrictMode(StrictMode::StrictModeState strictness);
void recursivelySetStrictMode(StrictMode strictness);
};
// Push the C-stack-allocated struct at stmt onto the StmtInfoPC stack.

View File

@ -433,16 +433,14 @@ struct CompileError {
void throwError();
};
namespace StrictMode {
/* For an explanation of how these are used, see the comment in the FunctionBox definition. */
enum StrictModeState {
MOZ_BEGIN_ENUM_CLASS(StrictMode, uint8_t)
NOTSTRICT,
UNKNOWN,
STRICT
};
}
MOZ_END_ENUM_CLASS(StrictMode)
inline StrictMode::StrictModeState
inline StrictMode
StrictModeFromContext(JSContext *cx)
{
return cx->hasRunOption(JSOPTION_STRICT_MODE) ? StrictMode::STRICT : StrictMode::UNKNOWN;
@ -463,7 +461,7 @@ class StrictModeGetter {
public:
StrictModeGetter(Parser *p) : parser(p) { }
StrictMode::StrictModeState get() const;
StrictMode get() const;
CompileError *queuedStrictModeError() const;
void setQueuedStrictModeError(CompileError *e);
};
@ -536,9 +534,9 @@ class TokenStream
void setXMLOnlyMode(bool enabled = true) { setFlag(enabled, TSF_XMLONLYMODE); }
void setUnexpectedEOF(bool enabled = true) { setFlag(enabled, TSF_UNEXPECTED_EOF); }
StrictMode::StrictModeState strictModeState() const
StrictMode strictModeState() const
{
return strictModeGetter ? strictModeGetter->get() : StrictMode::NOTSTRICT;
return strictModeGetter ? strictModeGetter->get() : StrictMode(StrictMode::NOTSTRICT);
}
bool isXMLTagMode() const { return !!(flags & TSF_XMLTAGMODE); }
bool isXMLOnlyMode() const { return !!(flags & TSF_XMLONLYMODE); }

View File

@ -551,8 +551,8 @@ XPCWrappedNative::GetNewOrUsed(XPCCallContext& ccx,
JSObject *cached = cache->GetWrapper();
if (cached) {
if (IS_SLIM_WRAPPER_OBJECT(cached)) {
if (!XPCWrappedNative::Morph(ccx, cached, Interface, cache,
getter_AddRefs(wrapper)))
if (NS_FAILED(XPCWrappedNative::Morph(ccx, cached,
Interface, cache, getter_AddRefs(wrapper))))
return NS_ERROR_FAILURE;
} else {
wrapper = static_cast<XPCWrappedNative*>(xpc_GetJSPrivate(cached));

View File

@ -497,11 +497,19 @@ public:
mXScale(1.f), mYScale(1.f),
mActiveScrolledRootPosition(0, 0) {}
/**
* Record the number of clips in the Thebes layer's mask layer.
* Should not be reset when the layer is recycled since it is used to track
* changes in the use of mask layers.
*/
uint32_t mMaskClipCount;
/**
* A color that should be painted over the bounds of the layer's visible
* region before any other content is painted.
*/
nscolor mForcedBackgroundColor;
/**
* The resolution scale used.
*/
@ -1675,6 +1683,10 @@ ContainerState::FindThebesLayerFor(nsDisplayItem* aItem,
layer = thebesLayerData->mLayer;
}
// check to see if the new item has rounded rect clips in common with
// other items in the layer
thebesLayerData->UpdateCommonClipCount(aClip);
thebesLayerData->Accumulate(this, aItem, aVisibleRect, aDrawRect, aClip);
return thebesLayerData;
@ -3202,7 +3214,7 @@ FrameLayerBuilder::Clip::RemoveRoundedCorners()
}
gfxRect
CalculateBounds(nsTArray<FrameLayerBuilder::Clip::RoundedRect> aRects, int32_t A2D)
CalculateBounds(const nsTArray<FrameLayerBuilder::Clip::RoundedRect>& aRects, int32_t A2D)
{
nsRect bounds = aRects[0].mRect;
for (uint32_t i = 1; i < aRects.Length(); ++i) {
@ -3211,16 +3223,36 @@ CalculateBounds(nsTArray<FrameLayerBuilder::Clip::RoundedRect> aRects, int32_t A
return nsLayoutUtils::RectToGfxRect(bounds, A2D);
}
static void
SetClipCount(ThebesDisplayItemLayerUserData* aThebesData,
uint32_t aClipCount)
{
if (aThebesData) {
aThebesData->mMaskClipCount = aClipCount;
}
}
void
ContainerState::SetupMaskLayer(Layer *aLayer, const FrameLayerBuilder::Clip& aClip,
uint32_t aRoundedRectClipCount)
{
// if the number of clips we are going to mask has decreased, then aLayer might have
// cached graphics which assume the existence of a soon-to-be non-existent mask layer
// in that case, invalidate the whole layer.
ThebesDisplayItemLayerUserData* thebesData = GetThebesDisplayItemLayerUserData(aLayer);
if (thebesData &&
aRoundedRectClipCount < thebesData->mMaskClipCount) {
ThebesLayer* thebes = aLayer->AsThebesLayer();
thebes->InvalidateRegion(thebes->GetValidRegion().GetBounds());
}
// don't build an unnecessary mask
nsIntRect layerBounds = aLayer->GetVisibleRegion().GetBounds();
if (aClip.mRoundedClipRects.IsEmpty() ||
aRoundedRectClipCount <= 0 ||
aRoundedRectClipCount == 0 ||
layerBounds.IsEmpty()) {
SetClipCount(thebesData, 0);
return;
}
@ -3238,6 +3270,7 @@ ContainerState::SetupMaskLayer(Layer *aLayer, const FrameLayerBuilder::Clip& aCl
if (*userData == newData) {
aLayer->SetMaskLayer(maskLayer);
SetClipCount(thebesData, aRoundedRectClipCount);
return;
}
@ -3263,28 +3296,24 @@ ContainerState::SetupMaskLayer(Layer *aLayer, const FrameLayerBuilder::Clip& aCl
gfxMatrix imageTransform = maskTransform;
imageTransform.Scale(mParameters.mXScale, mParameters.mYScale);
nsAutoPtr<MaskLayerImageCache::MaskLayerImageKey> newKey(
new MaskLayerImageCache::MaskLayerImageKey(aLayer->Manager()->GetBackendType()));
// copy and transform the rounded rects
nsTArray<MaskLayerImageCache::PixelRoundedRect> roundedRects;
for (uint32_t i = 0; i < newData.mRoundedClipRects.Length(); ++i) {
roundedRects.AppendElement(
newKey->mRoundedClipRects.AppendElement(
MaskLayerImageCache::PixelRoundedRect(newData.mRoundedClipRects[i],
mContainerFrame->PresContext()));
roundedRects[i].ScaleAndTranslate(imageTransform);
newKey->mRoundedClipRects[i].ScaleAndTranslate(imageTransform);
}
// check to see if we can reuse a mask image
const MaskLayerImageCache::MaskLayerImageKey* key =
new MaskLayerImageCache::MaskLayerImageKey(roundedRects, aLayer->Manager()->GetBackendType());
const MaskLayerImageCache::MaskLayerImageKey* lookupKey = key;
const MaskLayerImageCache::MaskLayerImageKey* lookupKey = newKey;
// check to see if we can reuse a mask image
nsRefPtr<ImageContainer> container =
GetMaskLayerImageCache()->FindImageFor(&lookupKey);
if (container) {
// track the returned key for the mask image
delete key;
key = lookupKey;
} else {
if (!container) {
// no existing mask image, so build a new one
nsRefPtr<gfxASurface> surface =
aLayer->Manager()->CreateOptimalMaskSurface(surfaceSize);
@ -3292,6 +3321,7 @@ ContainerState::SetupMaskLayer(Layer *aLayer, const FrameLayerBuilder::Clip& aCl
// fail if we can't get the right surface
if (!surface || surface->CairoStatus()) {
NS_WARNING("Could not create surface for mask layer.");
SetClipCount(thebesData, 0);
return;
}
@ -3314,7 +3344,7 @@ ContainerState::SetupMaskLayer(Layer *aLayer, const FrameLayerBuilder::Clip& aCl
static_cast<CairoImage*>(image.get())->SetData(data);
container->SetCurrentImageInTransaction(image);
GetMaskLayerImageCache()->PutImage(key, container);
GetMaskLayerImageCache()->PutImage(newKey.forget(), container);
}
maskLayer->SetContainer(container);
@ -3324,9 +3354,10 @@ ContainerState::SetupMaskLayer(Layer *aLayer, const FrameLayerBuilder::Clip& aCl
userData->mScaleX = newData.mScaleX;
userData->mScaleY = newData.mScaleY;
userData->mRoundedClipRects.SwapElements(newData.mRoundedClipRects);
userData->mImageKey = key;
userData->mImageKey = lookupKey;
aLayer->SetMaskLayer(maskLayer);
SetClipCount(thebesData, aRoundedRectClipCount);
return;
}

View File

@ -88,6 +88,7 @@ CPPSRCS = \
nsStyleChangeList.cpp \
nsStyleSheetService.cpp \
PaintTracker.cpp \
PositionedEventTargeting.cpp \
StackArena.cpp \
$(NULL)

View File

@ -12,10 +12,13 @@ namespace mozilla {
MaskLayerImageCache::MaskLayerImageCache()
{
MOZ_COUNT_CTOR(MaskLayerImageCache);
mMaskImageContainers.Init();
}
MaskLayerImageCache::~MaskLayerImageCache()
{}
{
MOZ_COUNT_DTOR(MaskLayerImageCache);
}
/* static */ PLDHashOperator

View File

@ -50,10 +50,24 @@ public:
aPresContext->AppUnitsToGfxUnits(aRRect.mRect.width),
aPresContext->AppUnitsToGfxUnits(aRRect.mRect.height))
{
MOZ_COUNT_CTOR(PixelRoundedRect);
NS_FOR_CSS_HALF_CORNERS(corner) {
mRadii[corner] = aPresContext->AppUnitsToGfxUnits(aRRect.mRadii[corner]);
}
}
PixelRoundedRect(const PixelRoundedRect& aPRR)
: mRect(aPRR.mRect)
{
MOZ_COUNT_CTOR(PixelRoundedRect);
NS_FOR_CSS_HALF_CORNERS(corner) {
mRadii[corner] = aPRR.mRadii[corner];
}
}
~PixelRoundedRect()
{
MOZ_COUNT_DTOR(PixelRoundedRect);
}
// Applies the scale and translate components of aTransform.
// It is an error to pass a matrix which does more than just scale
@ -99,6 +113,9 @@ public:
gfxRect mRect;
// Indices into mRadii are the NS_CORNER_* constants in nsStyleConsts.h
gfxFloat mRadii[8];
private:
PixelRoundedRect() MOZ_DELETE;
};
/**
@ -111,14 +128,27 @@ public:
* pointers to a key object (the +1 being from the hashtable entry), but this
* invariant may be temporarily broken.
*/
class MaskLayerImageKey
struct MaskLayerImageKey
{
public:
MaskLayerImageKey(const nsTArray<PixelRoundedRect>& aRoundedClipRects, layers::LayersBackend aBackend)
MaskLayerImageKey(layers::LayersBackend aBackend)
: mBackend(aBackend)
, mLayerCount(0)
, mRoundedClipRects(aRoundedClipRects)
{}
, mRoundedClipRects()
{
MOZ_COUNT_CTOR(MaskLayerImageKey);
}
MaskLayerImageKey(const MaskLayerImageKey& aKey)
: mBackend(aKey.mBackend)
, mLayerCount(aKey.mLayerCount)
, mRoundedClipRects(aKey.mRoundedClipRects)
{
MOZ_COUNT_CTOR(MaskLayerImageKey);
}
~MaskLayerImageKey()
{
MOZ_COUNT_DTOR(MaskLayerImageKey);
}
void AddRef() const { ++mLayerCount; }
void Release() const
@ -172,12 +202,19 @@ protected:
typedef const MaskLayerImageKey& KeyType;
typedef const MaskLayerImageKey* KeyTypePointer;
MaskLayerImageEntry(KeyTypePointer aKey) : mKey(aKey) {}
MaskLayerImageEntry(KeyTypePointer aKey) : mKey(aKey)
{
MOZ_COUNT_CTOR(MaskLayerImageEntry);
}
MaskLayerImageEntry(const MaskLayerImageEntry& aOther)
: mKey(aOther.mKey.get())
{
NS_ERROR("ALLOW_MEMMOVE == true, should never be called");
}
~MaskLayerImageEntry()
{
MOZ_COUNT_DTOR(MaskLayerImageEntry);
}
// KeyEquals(): does this entry match this key?
bool KeyEquals(KeyTypePointer aKey) const

View File

@ -0,0 +1,274 @@
/* 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/. */
#include "PositionedEventTargeting.h"
#include "mozilla/Preferences.h"
#include "nsGUIEvent.h"
#include "nsLayoutUtils.h"
#include "nsGkAtoms.h"
#include "nsEventListenerManager.h"
#include "nsPrintfCString.h"
#include "mozilla/dom/Element.h"
namespace mozilla {
/*
* The basic goal of FindFrameTargetedByInputEvent() is to find a good
* target element that can respond to mouse events. Both mouse events and touch
* events are targeted at this element. Note that even for touch events, we
* check responsiveness to mouse events. We assume Web authors
* designing for touch events will take their own steps to account for
* inaccurate touch events.
*
* IsElementClickable() encapsulates the heuristic that determines whether an
* element is expected to respond to mouse events. An element is deemed
* "clickable" if it has registered listeners for "click", "mousedown" or
* "mouseup", or is on a whitelist of element tags (<a>, <button>, <input>,
* <select>, <textarea>, <label>), or has role="button", or is a link, or
* is a suitable XUL element.
* Any descendant (in the same document) of a clickable element is also
* deemed clickable since events will propagate to the clickable element from its
* descendant.
*
* If the element directly under the event position is clickable (or
* event radii are disabled), we always use that element. Otherwise we collect
* all frames intersecting a rectangle around the event position (taking CSS
* transforms into account) and choose the best candidate in GetClosest().
* Only IsElementClickable() candidates are considered; if none are found,
* then we revert to targeting the element under the event position.
* We ignore candidates outside the document subtree rooted by the
* document of the element directly under the event position. This ensures that
* event listeners in ancestor documents don't make it completely impossible
* to target a non-clickable element in a child document.
*
* When both a frame and its ancestor are in the candidate list, we ignore
* the ancestor. Otherwise a large ancestor element with a mouse event listener
* and some descendant elements that need to be individually targetable would
* disable intelligent targeting of those descendants within its bounds.
*
* GetClosest() computes the transformed axis-aligned bounds of each
* candidate frame, then computes the Manhattan distance from the event point
* to the bounds rect (which can be zero). The frame with the
* shortest distance is chosen. For visited links we multiply the distance
* by a specified constant weight; this can be used to make visited links
* more or less likely to be targeted than non-visited links.
*/
struct EventRadiusPrefs
{
uint32_t mVisitedWeight; // in percent, i.e. default is 100
uint32_t mSideRadii[4]; // TRBL order, in millimetres
bool mEnabled;
bool mRegistered;
};
static EventRadiusPrefs sMouseEventRadiusPrefs;
static EventRadiusPrefs sTouchEventRadiusPrefs;
static const EventRadiusPrefs*
GetPrefsFor(uint8_t aEventStructType)
{
EventRadiusPrefs* prefs = nullptr;
const char* prefBranch = nullptr;
if (aEventStructType == NS_MOZTOUCH_EVENT ||
aEventStructType == NS_TOUCH_EVENT) {
prefBranch = "touch";
prefs = &sTouchEventRadiusPrefs;
} else if (aEventStructType == NS_MOUSE_EVENT) {
// Mostly for testing purposes
prefBranch = "mouse";
prefs = &sMouseEventRadiusPrefs;
} else {
return nullptr;
}
if (!prefs->mRegistered) {
prefs->mRegistered = true;
nsPrintfCString enabledPref("ui.%s.radius.enabled", prefBranch);
Preferences::AddBoolVarCache(&prefs->mEnabled, enabledPref.get(), false);
nsPrintfCString visitedWeightPref("ui.%s.radius.visitedWeight", prefBranch);
Preferences::AddUintVarCache(&prefs->mVisitedWeight, visitedWeightPref.get(), 100);
static const char prefNames[4][9] =
{ "topmm", "rightmm", "bottommm", "leftmm" };
for (int32_t i = 0; i < 4; ++i) {
nsPrintfCString radiusPref("ui.%s.radius.%s", prefBranch, prefNames[i]);
Preferences::AddUintVarCache(&prefs->mSideRadii[i], radiusPref.get(), 0);
}
}
return prefs;
}
static bool
HasMouseListener(nsIContent* aContent)
{
nsEventListenerManager* elm = aContent->GetListenerManager(false);
if (!elm) {
return false;
}
return elm->HasListenersFor(nsGkAtoms::onclick) ||
elm->HasListenersFor(nsGkAtoms::onmousedown) ||
elm->HasListenersFor(nsGkAtoms::onmouseup);
}
static bool
IsElementClickable(nsIFrame* aFrame)
{
// Input events propagate up the content tree so we'll follow the content
// ancestors to look for elements accepting the click.
for (nsIContent* content = aFrame->GetContent(); content;
content = content->GetFlattenedTreeParent()) {
if (HasMouseListener(content)) {
return true;
}
if (content->IsHTML()) {
nsIAtom* tag = content->Tag();
if (tag == nsGkAtoms::button ||
tag == nsGkAtoms::input ||
tag == nsGkAtoms::select ||
tag == nsGkAtoms::textarea ||
tag == nsGkAtoms::label) {
return true;
}
} else if (content->IsXUL()) {
nsIAtom* tag = content->Tag();
// See nsCSSFrameConstructor::FindXULTagData. This code is not
// really intended to be used with XUL, though.
if (tag == nsGkAtoms::button ||
tag == nsGkAtoms::checkbox ||
tag == nsGkAtoms::radio ||
tag == nsGkAtoms::autorepeatbutton ||
tag == nsGkAtoms::menu ||
tag == nsGkAtoms::menubutton ||
tag == nsGkAtoms::menuitem ||
tag == nsGkAtoms::menulist ||
tag == nsGkAtoms::scrollbarbutton ||
tag == nsGkAtoms::resizer) {
return true;
}
}
if (content->AttrValueIs(kNameSpaceID_None, nsGkAtoms::role,
nsGkAtoms::button, eIgnoreCase)) {
return true;
}
nsCOMPtr<nsIURI> linkURI;
if (content->IsLink(getter_AddRefs(linkURI))) {
return true;
}
}
return false;
}
static nscoord
AppUnitsFromMM(nsIFrame* aFrame, uint32_t aMM, bool aVertical)
{
nsPresContext* pc = aFrame->PresContext();
nsIPresShell* presShell = pc->PresShell();
float result = float(aMM) *
(pc->DeviceContext()->AppUnitsPerPhysicalInch() / MM_PER_INCH_FLOAT) *
(aVertical ? presShell->GetYResolution() : presShell->GetXResolution());
return NSToCoordRound(result);
}
static nsRect
GetTargetRect(nsIFrame* aRootFrame, const nsPoint& aPointRelativeToRootFrame,
const EventRadiusPrefs* aPrefs)
{
nsMargin m(AppUnitsFromMM(aRootFrame, aPrefs->mSideRadii[3], false),
AppUnitsFromMM(aRootFrame, aPrefs->mSideRadii[0], true),
AppUnitsFromMM(aRootFrame, aPrefs->mSideRadii[1], false),
AppUnitsFromMM(aRootFrame, aPrefs->mSideRadii[2], true));
nsRect r(aPointRelativeToRootFrame, nsSize(0,0));
r.Inflate(m);
return r;
}
static float
ComputeDistanceFromRect(const nsPoint& aPoint, const nsRect& aRect)
{
nscoord dx = NS_MAX(0, NS_MAX(aRect.x - aPoint.x, aPoint.x - aRect.XMost()));
nscoord dy = NS_MAX(0, NS_MAX(aRect.y - aPoint.y, aPoint.y - aRect.YMost()));
return float(NS_hypot(dx, dy));
}
static nsIFrame*
GetClosest(nsIFrame* aRoot, const nsPoint& aPointRelativeToRootFrame,
const EventRadiusPrefs* aPrefs, nsIFrame* aRestrictToDescendants,
nsTArray<nsIFrame*>& aCandidates)
{
nsIFrame* bestTarget = nullptr;
// Lower is better; distance is in appunits
float bestDistance = 1e6f;
for (uint32_t i = 0; i < aCandidates.Length(); ++i) {
nsIFrame* f = aCandidates[i];
if (!IsElementClickable(f)) {
continue;
}
// If our current closest frame is a descendant of 'f', skip 'f' (prefer
// the nested frame).
if (bestTarget && nsLayoutUtils::IsProperAncestorFrameCrossDoc(f, bestTarget, aRoot)) {
continue;
}
if (!nsLayoutUtils::IsAncestorFrameCrossDoc(aRestrictToDescendants, f, aRoot)) {
continue;
}
nsRect borderBox = nsLayoutUtils::TransformFrameRectToAncestor(f,
nsRect(nsPoint(0, 0), f->GetSize()), aRoot);
// distance is in appunits
float distance = ComputeDistanceFromRect(aPointRelativeToRootFrame, borderBox);
nsIContent* content = f->GetContent();
if (content && content->IsElement() &&
content->AsElement()->State().HasState(nsEventStates(NS_EVENT_STATE_VISITED))) {
distance *= aPrefs->mVisitedWeight / 100.0f;
}
if (distance < bestDistance) {
bestDistance = distance;
bestTarget = f;
}
}
return bestTarget;
}
nsIFrame*
FindFrameTargetedByInputEvent(uint8_t aEventStructType,
nsIFrame* aRootFrame,
const nsPoint& aPointRelativeToRootFrame,
uint32_t aFlags)
{
bool ignoreRootScrollFrame = (aFlags & INPUT_IGNORE_ROOT_SCROLL_FRAME) != 0;
nsIFrame* target =
nsLayoutUtils::GetFrameForPoint(aRootFrame, aPointRelativeToRootFrame,
false, ignoreRootScrollFrame);
const EventRadiusPrefs* prefs = GetPrefsFor(aEventStructType);
if (!prefs || !prefs->mEnabled || (target && IsElementClickable(target))) {
return target;
}
nsRect targetRect = GetTargetRect(aRootFrame, aPointRelativeToRootFrame, prefs);
nsAutoTArray<nsIFrame*,8> candidates;
nsresult rv = nsLayoutUtils::GetFramesForArea(aRootFrame, targetRect, candidates,
false, ignoreRootScrollFrame);
if (NS_FAILED(rv)) {
return target;
}
// If the exact target is non-null, only consider candidate targets in the same
// document as the exact target. Otherwise, if an ancestor document has
// a mouse event handler for example, targets that are !IsElementClickable can
// never be targeted --- something nsSubDocumentFrame in an ancestor document
// would be targeted instead.
nsIFrame* restrictToDescendants = target ?
target->PresContext()->PresShell()->GetRootFrame() : aRootFrame;
nsIFrame* closestClickable =
GetClosest(aRootFrame, aPointRelativeToRootFrame, prefs,
restrictToDescendants, candidates);
return closestClickable ? closestClickable : target;
}
}

View File

@ -0,0 +1,31 @@
/* 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/. */
#ifndef mozilla_PositionedEventTargeting_h
#define mozilla_PositionedEventTargeting_h
#include "nsPoint.h"
class nsGUIEvent;
class nsIFrame;
namespace mozilla {
enum {
INPUT_IGNORE_ROOT_SCROLL_FRAME = 0x01
};
/**
* Finds the target frame for a pointer event given the event type and location.
* This can look for frames within a rectangle surrounding the actual location
* that are suitable targets, to account for inaccurate pointing devices.
*/
nsIFrame*
FindFrameTargetedByInputEvent(uint8_t aEventStructType,
nsIFrame* aRootFrame,
const nsPoint& aPointRelativeToRootFrame,
uint32_t aFlags = 0);
}
#endif /* mozilla_PositionedEventTargeting_h */

View File

@ -615,19 +615,9 @@ bool
nsLayoutUtils::IsProperAncestorFrameCrossDoc(nsIFrame* aAncestorFrame, nsIFrame* aFrame,
nsIFrame* aCommonAncestor)
{
if (aFrame == aCommonAncestor)
if (aFrame == aAncestorFrame)
return false;
nsIFrame* parentFrame = GetCrossDocParentFrame(aFrame);
while (parentFrame != aCommonAncestor) {
if (parentFrame == aAncestorFrame)
return true;
parentFrame = GetCrossDocParentFrame(parentFrame);
}
return false;
return IsAncestorFrameCrossDoc(aAncestorFrame, aFrame, aCommonAncestor);
}
// static
@ -635,9 +625,12 @@ bool
nsLayoutUtils::IsAncestorFrameCrossDoc(nsIFrame* aAncestorFrame, nsIFrame* aFrame,
nsIFrame* aCommonAncestor)
{
if (aFrame == aAncestorFrame)
return true;
return IsProperAncestorFrameCrossDoc(aAncestorFrame, aFrame, aCommonAncestor);
for (nsIFrame* f = aFrame; f != aCommonAncestor;
f = GetCrossDocParentFrame(f)) {
if (f == aAncestorFrame)
return true;
}
return aCommonAncestor == aAncestorFrame;
}
// static
@ -645,21 +638,13 @@ bool
nsLayoutUtils::IsProperAncestorFrame(nsIFrame* aAncestorFrame, nsIFrame* aFrame,
nsIFrame* aCommonAncestor)
{
if (aFrame == aCommonAncestor) {
if (aFrame == aAncestorFrame)
return false;
}
nsIFrame* parentFrame = aFrame->GetParent();
while (parentFrame != aCommonAncestor) {
if (parentFrame == aAncestorFrame) {
for (nsIFrame* f = aFrame; f != aCommonAncestor; f = f->GetParent()) {
if (f == aAncestorFrame)
return true;
}
parentFrame = parentFrame->GetParent();
}
return false;
return aCommonAncestor == aAncestorFrame;
}
// static

View File

@ -99,6 +99,7 @@
#ifdef MOZ_REFLOW_PERF
#include "nsFontMetrics.h"
#endif
#include "PositionedEventTargeting.h"
#include "nsIReflowCallback.h"
@ -5891,16 +5892,15 @@ PresShell::HandleEvent(nsIFrame *aFrame,
} else {
eventPoint = nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent, frame);
}
{
bool ignoreRootScrollFrame = false;
if (aEvent->eventStructType == NS_MOUSE_EVENT) {
ignoreRootScrollFrame = static_cast<nsMouseEvent*>(aEvent)->ignoreRootScrollFrame;
}
nsIFrame* target = nsLayoutUtils::GetFrameForPoint(frame, eventPoint,
false, ignoreRootScrollFrame);
if (target) {
frame = target;
}
uint32_t flags = 0;
if (aEvent->eventStructType == NS_MOUSE_EVENT &&
static_cast<nsMouseEvent*>(aEvent)->ignoreRootScrollFrame) {
flags |= INPUT_IGNORE_ROOT_SCROLL_FRAME;
}
nsIFrame* target =
FindFrameTargetedByInputEvent(aEvent->eventStructType, frame, eventPoint, flags);
if (target) {
frame = target;
}
}

View File

@ -131,6 +131,7 @@ MOCHITEST_FILES = \
test_bug667512.html \
test_bug677878.html \
test_bug696020.html \
test_event_target_radius.html \
test_mozPaintCount.html \
test_scroll_selection_into_view.html \
test_bug583889.html \

View File

@ -0,0 +1,177 @@
<!DOCTYPE HTML>
<html id="html" style="height:100%">
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=780847
-->
<head>
<title>Test radii for mouse events</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<style>
.target { position:absolute; left:100px; top:100px; width:100px; height:100px; background:blue; }
</style>
</head>
<body id="body" onload="setTimeout(runTest, 0)" style="margin:0; width:100%; height:100%">
<p id="display"></p>
<div id="content">
<div id="ruler" style="position:absolute; left:0; top:0; width:1mozmm; height:0;"></div>
<div class="target" id="t" onmousedown="x=1"></div>
<div class="target" id="t2" hidden></div>
<input class="target" id="t3_1" hidden></input>
<a href="#" class="target" id="t3_2" hidden></a>
<label class="target" id="t3_3" hidden></label>
<button class="target" id="t3_4" hidden></button>
<select class="target" id="t3_5" hidden></select>
<textarea class="target" id="t3_6" hidden></textarea>
<div role="button" class="target" id="t3_7" hidden></div>
<img class="target" id="t3_8" hidden></img>
<div class="target" style="transform:translate(-80px,0);" id="t4" onmousedown="x=1" hidden></div>
<div class="target" style="left:0; z-index:1" id="t5_left" onmousedown="x=1" hidden></div>
<div class="target" style="left:106px;" id="t5_right" onmousedown="x=1" hidden></div>
<div class="target" style="left:0; top:210px;" id="t5_below" onmousedown="x=1" hidden></div>
<div class="target" id="t6" onmousedown="x=1" hidden>
<div id="t6_inner" style="position:absolute; left:-20px; top:20px; width:60px; height:60px; background:yellow;"></div>
</div>
</div>
<pre id="test">
<script type="application/javascript">
var prefBase = "ui.mouse.radius.";
SpecialPowers.setBoolPref(prefBase + "enabled", true);
SpecialPowers.setIntPref(prefBase + "leftmm", 12);
SpecialPowers.setIntPref(prefBase + "topmm", 8);
SpecialPowers.setIntPref(prefBase + "rightmm", 4);
SpecialPowers.setIntPref(prefBase + "bottommm", 4);
SpecialPowers.setIntPref(prefBase + "visitedWeight", 50);
SimpleTest.waitForExplicitFinish();
var mm = document.getElementById("ruler").getBoundingClientRect().width;
ok(4*mm >= 10, "WARNING: mm " + mm + " too small in this configuration. Test results will be bogus");
function endTest() {
SpecialPowers.clearUserPref(prefBase + "enabled");
SpecialPowers.clearUserPref(prefBase + "leftmmm");
SpecialPowers.clearUserPref(prefBase + "topmm");
SpecialPowers.clearUserPref(prefBase + "rightmm");
SpecialPowers.clearUserPref(prefBase + "bottommm");
SpecialPowers.clearUserPref(prefBase + "visitedWeight");
SimpleTest.finish();
}
var eventTarget;
window.onmousedown = function(event) { eventTarget = event.target; };
function testMouseClick(idPosition, dx, dy, idTarget, msg) {
eventTarget = null;
synthesizeMouse(document.getElementById(idPosition), dx, dy, {});
try {
is(eventTarget.id, idTarget,
"checking '" + idPosition + "' offset " + dx + "," + dy + " [" + msg + "]");
} catch (ex) {
ok(false, "checking '" + idPosition + "' offset " + dx + "," + dy + " [" + msg + "]; got " + eventTarget);
}
}
function setShowing(id, show) {
var e = document.getElementById(id);
e.hidden = !show;
}
function runTest() {
// Test basic functionality: clicks sufficiently close to the element
// should be allowed to hit the element. We test points just inside and
// just outside the edges we set up in the prefs.
testMouseClick("t", 100 + 13*mm, 10, "body", "basic functionality");
testMouseClick("t", 100 + 11*mm, 10, "t", "basic functionality");
testMouseClick("t", 10, 100 + 9*mm, "body", "basic functionality");
testMouseClick("t", 10, 100 + 7*mm, "t", "basic functionality");
testMouseClick("t", -5*mm, 10, "body", "basic functionality");
testMouseClick("t", -3*mm, 10, "t", "basic functionality");
testMouseClick("t", 10, -5*mm, "body", "basic functionality");
testMouseClick("t", 10, -3*mm, "t", "basic functionality");
setShowing("t", false);
// Now test the criteria we use to determine which elements are hittable
// this way.
setShowing("t2", true);
var t2 = document.getElementById("t2");
// Unadorned DIVs are not click radius targets
testMouseClick("t2", 100 + 11*mm, 10, "body", "unadorned DIV");
// DIVs with the right event handlers are click radius targets
t2.onmousedown = function() {};
testMouseClick("t2", 100 + 11*mm, 10, "t2", "DIV with onmousedown");
t2.onmousedown = null;
testMouseClick("t2", 100 + 11*mm, 10, "body", "DIV with onmousedown removed");
t2.onmouseup = function() {};
testMouseClick("t2", 100 + 11*mm, 10, "t2", "DIV with onmouseup");
t2.onmouseup = null;
t2.onclick = function() {};
testMouseClick("t2", 100 + 11*mm, 10, "t2", "DIV with onclick");
t2.onclick = null;
// Keypresses don't make click radius targets
t2.onkeypress = function() {};
testMouseClick("t2", 100 + 11*mm, 10, "body", "DIV with onkeypress");
t2.onkeypress = null;
setShowing("t2", false);
// Now check that certain elements are click radius targets and others are not
for (var i = 1; i <= 8; ++i) {
var id = "t3_" + i;
var shouldHit = i <= 7;
setShowing(id, true);
testMouseClick(id, 100 + 11*mm, 10, shouldHit ? id : "body",
"<" + document.getElementById(id).tagName + "> element");
setShowing(id, false);
}
// Check that our targeting computations take into account the effects of
// CSS transforms
setShowing("t4", true);
testMouseClick("t4", -1, 10, "t4", "translated DIV");
setShowing("t4", false);
// Test the prioritization of multiple targets based on distance to
// the target.
setShowing("t5_left", true);
setShowing("t5_right", true);
setShowing("t5_below", true);
testMouseClick("t5_left", 102, 10, "t5_left", "closest DIV is left");
testMouseClick("t5_left", 102.5, 10, "t5_left",
"closest DIV to midpoint is left because of its higher z-index");
testMouseClick("t5_left", 104, 10, "t5_right", "closest DIV is right");
testMouseClick("t5_left", 10, 104, "t5_left", "closest DIV is left");
testMouseClick("t5_left", 10, 105, "t5_left",
"closest DIV to midpoint is left because of its higher z-index");
testMouseClick("t5_left", 10, 106, "t5_below", "closest DIV is below");
setShowing("t5_left", false);
setShowing("t5_right", false);
setShowing("t5_below", false);
// Test behavior of nested elements.
// The following behaviors are questionable and may need to be changed.
setShowing("t6", true);
testMouseClick("t6_inner", -1, 10, "t6_inner",
"inner element is clickable because its parent is, even when it sticks outside parent");
testMouseClick("t6_inner", 19, -1, "t6_inner",
"when outside both inner and parent, but in range of both, the inner is selected");
testMouseClick("t6_inner", 25, -1, "t6",
"clicking in clickable parent close to inner activates parent, not inner");
setShowing("t6", false);
// Not yet tested:
// -- visited link weight
// -- "Closest" using Euclidean distance
endTest();
}
</script>
</pre>
</body>
</html>

View File

@ -1575,7 +1575,7 @@ nsListControlFrame::GetFormProperty(nsIAtom* aName, nsAString& aValue) const
nsresult error = NS_OK;
bool selected = false;
int32_t indx = val.ToInteger(&error, 10); // Get index from aValue
if (error == 0)
if (NS_SUCCEEDED(error))
selected = IsContentSelectedByIndex(indx);
aValue.Assign(selected ? NS_LITERAL_STRING("1") : NS_LITERAL_STRING("0"));

View File

@ -935,7 +935,7 @@ nsFrameSelection::MoveCaret(uint32_t aKeycode,
aVisualMovement);
if (NS_FAILED(result) || !frame)
return result?result:NS_ERROR_FAILURE;
return NS_FAILED(result) ? result : NS_ERROR_FAILURE;
//set data using mLimiter to stop on scroll views. If we have a limiter then we stop peeking
//when we hit scrollable views. If no limiter then just let it go ahead
@ -5567,7 +5567,7 @@ Selection::SelectionLanguageChange(bool aLangRTL)
uint8_t levelBefore, levelAfter;
result = GetPresContext(getter_AddRefs(context));
if (NS_FAILED(result) || !context)
return result?result:NS_ERROR_FAILURE;
return NS_FAILED(result) ? result : NS_ERROR_FAILURE;
uint8_t level = NS_GET_EMBEDDING_LEVEL(focusFrame);
int32_t focusOffset = GetFocusOffset();

View File

@ -7622,8 +7622,15 @@ nsTextFrame::ReflowText(nsLineLayout& aLineLayout, nscoord aAvailableWidth,
int32_t skipLength = newLineOffset >= 0 ? length - 1 : length;
int32_t whitespaceCount =
GetTrimmableWhitespaceCount(frag, offset, skipLength, 1);
offset += whitespaceCount;
length -= whitespaceCount;
if (whitespaceCount) {
offset += whitespaceCount;
length -= whitespaceCount;
// Make sure this frame maps the trimmable whitespace.
if (NS_UNLIKELY(offset > GetContentEnd())) {
SetLength(offset - GetContentOffset(), &aLineLayout,
ALLOW_FRAME_CREATION_AND_DESTRUCTION);
}
}
}
bool completedFirstLetter = false;

View File

@ -182,11 +182,14 @@ math[display="inline"] {
ms {
display: inline;
}
ms:before {
content: open-quote;
ms:before, ms:after {
content: "\0022";
}
ms:after {
content: close-quote;
ms[lquote]:before {
content: attr(lquote);
}
ms[rquote]:after {
content: attr(rquote);
}
merror {

View File

@ -111,7 +111,6 @@ nsMathMLTokenFrame::SetInitialChildList(ChildListID aListID,
ForceTrimChildTextFrames();
SetQuotes(false);
ProcessTextData();
return rv;
}
@ -248,20 +247,6 @@ nsMathMLTokenFrame::MarkIntrinsicWidthsDirty()
nsMathMLContainerFrame::MarkIntrinsicWidthsDirty();
}
NS_IMETHODIMP
nsMathMLTokenFrame::AttributeChanged(int32_t aNameSpaceID,
nsIAtom* aAttribute,
int32_t aModType)
{
if (nsGkAtoms::lquote_ == aAttribute ||
nsGkAtoms::rquote_ == aAttribute) {
SetQuotes(true);
}
return nsMathMLContainerFrame::
AttributeChanged(aNameSpaceID, aAttribute, aModType);
}
void
nsMathMLTokenFrame::ProcessTextData()
{
@ -369,55 +354,3 @@ nsMathMLTokenFrame::SetTextStyle()
return false;
}
///////////////////////////////////////////////////////////////////////////
// For <ms>, it is assumed that the mathml.css file contains two rules:
// ms:before { content: open-quote; }
// ms:after { content: close-quote; }
// With these two rules, the frame construction code will
// create inline frames that contain text frames which themselves
// contain the text content of the quotes.
// So the main idea in this code is to see if there are lquote and
// rquote attributes. If these are there, we ovewrite the default
// quotes in the text frames.
// XXX this is somewhat bogus, we probably should map lquote and rquote
// to 'content' style rules
//
// But what if the mathml.css file wasn't loaded?
// We also check that we are not relying on null pointers...
static void
SetQuote(nsIFrame* aFrame, nsString& aValue, bool aNotify)
{
if (!aFrame)
return;
nsIFrame* textFrame = aFrame->GetFirstPrincipalChild();
if (!textFrame)
return;
nsIContent* quoteContent = textFrame->GetContent();
if (!quoteContent->IsNodeOfType(nsINode::eTEXT))
return;
quoteContent->SetText(aValue, aNotify);
}
void
nsMathMLTokenFrame::SetQuotes(bool aNotify)
{
if (mContent->Tag() != nsGkAtoms::ms_)
return;
nsAutoString value;
// lquote
if (GetAttribute(mContent, mPresentationData.mstyle,
nsGkAtoms::lquote_, value)) {
SetQuote(nsLayoutUtils::GetBeforeFrame(this), value, aNotify);
}
// rquote
if (GetAttribute(mContent, mPresentationData.mstyle,
nsGkAtoms::rquote_, value)) {
SetQuote(nsLayoutUtils::GetAfterFrame(this), value, aNotify);
}
}

View File

@ -60,11 +60,6 @@ public:
virtual void MarkIntrinsicWidthsDirty();
NS_IMETHOD
AttributeChanged(int32_t aNameSpaceID,
nsIAtom* aAttribute,
int32_t aModType);
virtual nsresult
ChildListChanged(int32_t aModType)
{
@ -85,9 +80,6 @@ protected:
// depending on its textual content
bool SetTextStyle();
// helper to set the quotes of <ms>
void SetQuotes(bool aNotify);
void ForceTrimChildTextFrames();
};

View File

@ -0,0 +1,28 @@
<!DOCTYPE html>
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/licenses/publicdomain/
-->
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
</head>
<body>
<p><canvas width="100" height="100" id="c"></canvas></p>
<script type="text/javascript">
var c = document.getElementById('c').getContext('2d');
c.shadowColor = '#f00';
c.shadowBlur = 4;
c.lineWidth = 2;
c.moveTo(80, 40);
c.lineTo(50, 70);
c.lineTo(20, 40);
c.lineTo(50, 10);
c.closePath();
c.stroke();
</script>
</body>
</html>

View File

@ -0,0 +1,36 @@
<!DOCTYPE html>
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/licenses/publicdomain/
This tests that paths are stored in device space. This means that changing
the transform does not move the points already drawn.
-->
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
</head>
<body>
<p><canvas width="100" height="100" id="c"></canvas></p>
<script type="text/javascript">
var c = document.getElementById('c').getContext('2d');
c.shadowColor = '#f00';
c.shadowBlur = 4;
c.lineWidth = 2;
c.translate(50, 40);
var d = 30;
c.beginPath();
c.moveTo(d, 0);
for (var n = 0; n < 3; n++) {
c.rotate(3.14159 / 2);
c.lineTo(d, 0);
}
c.closePath();
c.stroke();
</script>
</body>
</html>

View File

@ -82,3 +82,6 @@ fails-if(/Mac\x20OS\x20X\x2010\.[56]/.test(http.oscpu)) == 672646-alpha-radial-g
== transformed-path.html transformed-path.html
== 749467-1.html 749467-1-ref.html
# You get a little bit of rounding fuzz on OSX from transforming the paths between user space and device space
fuzzy-if(azureQuartz,2,113) fuzzy-if(d2d,12,17) == 784573-1.html 784573-1-ref.html

View File

@ -0,0 +1,11 @@
<!DOCTYPE html>
<html>
<head><title>Test dir=rtl</title></head>
<body>
<p>ms lquote="A" rquote="B":
<math>
<ms lquote="B" rquote="A">___</ms>
</math>
</p>
</body>
</html>

View File

@ -0,0 +1,11 @@
<!DOCTYPE html>
<html>
<head><title>Test dir=rtl</title></head>
<body>
<p>ms lquote="A" rquote="B":
<math dir="rtl">
<ms lquote="A" rquote="B">___</ms>
</math>
</p>
</body>
</html>

View File

@ -7,9 +7,12 @@ p { height:2em; }
</head>
<body>
<p>:L_R</p>
<p>:L_&#x201D;</p>
<p>:&#x201C;_R</p>
<p>:L_&#x201D;</p>
<p>:&#x201C;_R</p>
<p>:L_"</p>
<p>:"_R</p>
<p>:L_"</p>
<p>:"_R</p>
<p>:"_"</p>
<p>:"_"</p>
<p>:"_"</p>
</body>
</html>

View File

@ -11,6 +11,9 @@ p { height:2em; }
<p>:<ms id="m2" xmlns="http://www.w3.org/1998/Math/MathML">_</ms></p>
<p>:<ms id="m3" xmlns="http://www.w3.org/1998/Math/MathML" lquote="_">_</ms></p>
<p>:<ms id="m4" xmlns="http://www.w3.org/1998/Math/MathML" rquote="_">_</ms></p>
<p>:<ms id="m5" xmlns="http://www.w3.org/1998/Math/MathML" lquote="_" rquote="_">_</ms></p>
<p>:<ms id="m6" xmlns="http://www.w3.org/1998/Math/MathML" lquote="_">_</ms></p>
<p>:<ms id="m7" xmlns="http://www.w3.org/1998/Math/MathML" rquote="_">_</ms></p>
<script>
function doTest() {
var m1 = document.getElementById("m1");
@ -21,6 +24,13 @@ function doTest() {
m3.setAttribute("lquote", "L");
var m4 = document.getElementById("m4");
m4.setAttribute("rquote", "R");
var m5 = document.getElementById("m5");
m5.removeAttribute("lquote");
m5.removeAttribute("rquote");
var m6 = document.getElementById("m6");
m6.removeAttribute("lquote");
var m7 = document.getElementById("m7");
m7.removeAttribute("rquote");
document.documentElement.removeAttribute('class');
}
window.addEventListener("MozReftestInvalidate", doTest, false);

View File

@ -6,6 +6,7 @@
fails == dir-6.html dir-6-ref.html
== dir-7.html dir-7-ref.html
fails == dir-8.html dir-8-ref.html
fails == dir-9.html dir-9-ref.html # Bug 787215
== mirror-op-1.html mirror-op-1-ref.html
!= mirror-op-2.html mirror-op-2-ref.html
!= mirror-op-3.html mirror-op-3-ref.html
@ -71,7 +72,7 @@ fails-if(winWidget) == mfenced-10.html mfenced-10-ref.html
== mstyle-2.xhtml mstyle-2-ref.xhtml
== mstyle-3.xhtml mstyle-3-ref.xhtml
== mstyle-4.xhtml mstyle-4-ref.xhtml
fails == mstyle-5.xhtml mstyle-5-ref.xhtml # See bug 569125#c29
fails == mstyle-5.xhtml mstyle-5-ref.xhtml # Bug 787215
== scale-stretchy-1.xhtml scale-stretchy-1-ref.xhtml
!= scale-stretchy-2.xhtml scale-stretchy-2-ref.xhtml
== scale-stretchy-3.xhtml scale-stretchy-3-ref.xhtml
@ -107,5 +108,5 @@ fails == mstyle-5.xhtml mstyle-5-ref.xhtml # See bug 569125#c29
== whitespace-trim-1.html whitespace-trim-1-ref.html
== whitespace-trim-2.html whitespace-trim-2-ref.html
== whitespace-trim-3.html whitespace-trim-3-ref.html
fails == whitespace-trim-4.html whitespace-trim-4-ref.html # Bug 560100
fails == whitespace-trim-4.html whitespace-trim-4-ref.html # Bug 787215
== whitespace-trim-5.html whitespace-trim-5-ref.html

View File

@ -734,7 +734,7 @@ nsUserFontSet::LogMessage(gfxProxyFontEntry *aProxy,
nsCSSProps::kFontStretchKTable).get(),
aProxy->mSrcIndex);
if (aStatus != 0) {
if (NS_FAILED(aStatus)) {
msg.Append(": ");
switch (aStatus) {
case NS_ERROR_DOM_BAD_URI:

View File

@ -191,10 +191,16 @@ cubeb_stream_init(cubeb * context, cubeb_stream ** stream, char const * stream_n
input.inputProcRefCon = stm;
r = AudioUnitSetProperty(stm->unit, kAudioUnitProperty_SetRenderCallback,
kAudioUnitScope_Global, 0, &input, sizeof(input));
if (r != 0) {
fprintf(stderr, "cubeb_audiounit: FATAL: AudioUnitSetProperty(SetRenderCallback) returned %ld\n", (long) r);
}
assert(r == 0);
r = AudioUnitSetProperty(stm->unit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input,
0, &ss, sizeof(ss));
if (r != 0) {
fprintf(stderr, "cubeb_audiounit: FATAL: AudioUnitSetProperty(StreamFormat) returned %ld\n", (long) r);
}
assert(r == 0);
buffer_size = ss.mSampleRate / 1000.0 * latency * ss.mBytesPerFrame / NBUFS;
@ -204,6 +210,9 @@ cubeb_stream_init(cubeb * context, cubeb_stream ** stream, char const * stream_n
assert(buffer_size % ss.mBytesPerFrame == 0);
r = AudioUnitInitialize(stm->unit);
if (r != 0) {
fprintf(stderr, "cubeb_audiounit: FATAL: AudioUnitInitialize returned %ld\n", (long) r);
}
assert(r == 0);
*stream = stm;

View File

@ -1551,11 +1551,21 @@ void (*_malloc_message)(const char *p1, const char *p2, const char *p3,
#endif
#include <mozilla/Assertions.h>
#include <mozilla/Attributes.h>
/* RELEASE_ASSERT calls jemalloc_crash() instead of calling MOZ_CRASH()
* directly because we want crashing to add a frame to the stack. This makes
* it easier to find the failing assertion in crash stacks. */
MOZ_NEVER_INLINE static void
jemalloc_crash()
{
MOZ_CRASH();
}
#if defined(MOZ_JEMALLOC_HARD_ASSERTS)
# define RELEASE_ASSERT(assertion) do { \
if (!(assertion)) { \
MOZ_CRASH(); \
jemalloc_crash(); \
} \
} while (0)
#else

View File

@ -10,6 +10,7 @@ import android.view.MenuItem;
import org.mozilla.gecko.BrowserApp;
import org.mozilla.gecko.GeckoAppShell;
import org.mozilla.gecko.GeckoEvent;
import org.mozilla.gecko.R;
public class App extends BrowserApp {

View File

@ -20,6 +20,7 @@ import java.net.URL;
import org.mozilla.gecko.GeckoApp;
import org.mozilla.gecko.GeckoAppShell;
import org.mozilla.gecko.GeckoEvent;
import org.mozilla.gecko.WebAppAllocator;
import org.mozilla.gecko.Tab;
import org.mozilla.gecko.Tabs;

View File

@ -1788,6 +1788,29 @@ pref("font.size.inflation.lineThreshold", 400);
*/
pref("font.size.inflation.mappingIntercept", 1);
/*
* When enabled, the touch.radius and mouse.radius prefs allow events to be dispatched
* to nearby elements that are sensitive to the event. See PositionedEventTargeting.cpp.
* The 'mm' prefs define a rectangle around the nominal event target point within which
* we will search for suitable elements. 'visitedWeight' is a percentage weight;
* a value > 100 makes a visited link be treated as further away from the event target
* than it really is, while a value < 100 makes a visited link be treated as closer
* to the event target than it really is.
*/
pref("ui.touch.radius.enabled", false);
pref("ui.touch.radius.leftmm", 8);
pref("ui.touch.radius.topmm", 12);
pref("ui.touch.radius.rightmm", 8);
pref("ui.touch.radius.bottommm", 4);
pref("ui.touch.radius.visitedWeight", 120);
pref("ui.mouse.radius.enabled", false);
pref("ui.mouse.radius.leftmm", 8);
pref("ui.mouse.radius.topmm", 12);
pref("ui.mouse.radius.rightmm", 8);
pref("ui.mouse.radius.bottommm", 4);
pref("ui.mouse.radius.visitedWeight", 120);
#ifdef XP_WIN
pref("font.name.serif.ar", "Times New Roman");

View File

@ -1678,9 +1678,12 @@ NS_SecurityHashURI(nsIURI* aURI)
scheme.EqualsLiteral("news"))
{
nsAutoCString spec;
uint32_t specHash = baseURI->GetSpec(spec);
if (NS_SUCCEEDED(specHash))
uint32_t specHash;
nsresult res = baseURI->GetSpec(spec);
if (NS_SUCCEEDED(res))
specHash = mozilla::HashString(spec);
else
specHash = static_cast<uint32_t>(res);
return specHash;
}

View File

@ -178,12 +178,12 @@ main(int argc, char* argv[])
nsCOMPtr<nsICategoryManager> catman =
do_GetService(NS_CATEGORYMANAGER_CONTRACTID, &rv);
if (NS_FAILED(rv)) return rv;
if (NS_FAILED(rv)) return -1;
nsCString previous;
nsCOMPtr<nsIStreamConverterService> StreamConvService =
do_GetService(kStreamConverterServiceCID, &rv);
if (NS_FAILED(rv)) return rv;
if (NS_FAILED(rv)) return -1;
// Define the *from* content type and *to* content-type for conversion.
static const char fromStr[] = "a/foo";
@ -201,14 +201,14 @@ main(int argc, char* argv[])
nsCOMPtr<nsIChannel> channel;
nsCOMPtr<nsIURI> dummyURI;
rv = NS_NewURI(getter_AddRefs(dummyURI), "http://meaningless");
if (NS_FAILED(rv)) return rv;
if (NS_FAILED(rv)) return -1;
rv = NS_NewInputStreamChannel(getter_AddRefs(channel),
dummyURI,
nullptr, // inStr
"text/plain", // content-type
-1); // XXX fix contentLength
if (NS_FAILED(rv)) return rv;
if (NS_FAILED(rv)) return -1;
nsCOMPtr<nsIRequest> request(do_QueryInterface(channel));
#endif
@ -227,7 +227,7 @@ main(int argc, char* argv[])
nsIStreamListener *converterListener = nullptr;
rv = StreamConvService->AsyncConvertData(fromStr, toStr,
dataReceiver, nullptr, &converterListener);
if (NS_FAILED(rv)) return rv;
if (NS_FAILED(rv)) return -1;
NS_RELEASE(dataReceiver);
// at this point we have a stream listener to push data to, and the one
@ -235,17 +235,17 @@ main(int argc, char* argv[])
// going. Typically these On*() calls would be made inside their respective wrappers On*()
// methods.
rv = converterListener->OnStartRequest(request, nullptr);
if (NS_FAILED(rv)) return rv;
if (NS_FAILED(rv)) return -1;
rv = SEND_DATA("aaa");
if (NS_FAILED(rv)) return rv;
if (NS_FAILED(rv)) return -1;
rv = SEND_DATA("aaa");
if (NS_FAILED(rv)) return rv;
if (NS_FAILED(rv)) return -1;
// Finish the request.
rv = converterListener->OnStopRequest(request, nullptr, rv);
if (NS_FAILED(rv)) return rv;
if (NS_FAILED(rv)) return -1;
NS_RELEASE(converterListener);
#else
@ -253,7 +253,7 @@ main(int argc, char* argv[])
nsCOMPtr<nsIInputStream> convertedData;
rv = StreamConvService->Convert(inputData, fromStr, toStr,
nullptr, getter_AddRefs(convertedData));
if (NS_FAILED(rv)) return rv;
if (NS_FAILED(rv)) return -1;
#endif
// Enter the message pump to allow the URL load to proceed.
@ -264,5 +264,5 @@ main(int argc, char* argv[])
} // this scopes the nsCOMPtrs
// no nsCOMPtrs are allowed to be alive when you call NS_ShutdownXPCOM
NS_ShutdownXPCOM(nullptr);
return rv;
return 0;
}

View File

@ -40,14 +40,14 @@ main(int argc, char* argv[])
nsIInputStream* in = nullptr;
nsCOMPtr<nsIIOService> service(do_GetService(kIOServiceCID, &ret));
if (NS_FAILED(ret)) return ret;
if (NS_FAILED(ret)) return 1;
nsIChannel *channel = nullptr;
ret = service->NewChannel(NS_LITERAL_CSTRING(TEST_URL), nullptr, nullptr, &channel);
if (NS_FAILED(ret)) return ret;
if (NS_FAILED(ret)) return 1;
ret = channel->Open(&in);
if (NS_FAILED(ret)) return ret;
if (NS_FAILED(ret)) return 1;
nsIPersistentProperties* props;
ret = CallCreateInstance(kPersistentPropertiesCID, &props);

Some files were not shown because too many files have changed in this diff Show More