This commit is contained in:
Richard Newman 2011-11-15 08:46:51 -08:00
Родитель 7d165ccb6e 5a09b57b4e
Коммит 6cb2c1daa8
112 изменённых файлов: 3543 добавлений и 1881 удалений

Просмотреть файл

@ -362,8 +362,8 @@ window[chromehidden~="toolbar"] toolbar:not(.toolbar-primary):not(.chromeclass-m
position: fixed;
top: 0;
left: 0;
min-width: 100%;
min-height: 100%;
width: 100%;
height: 100%;
}
#full-screen-warning-container[fade-warning-out] {

Просмотреть файл

@ -976,7 +976,7 @@
</hbox>
<hbox id="full-screen-warning-container" hidden="true" fadeout="true">
<hbox style="min-width: 100%;" pack="center"> <!-- Inner hbox needed due to bug 579776. -->
<hbox style="width: 100%;" pack="center"> <!-- Inner hbox needed due to bug 579776. -->
<hbox id="full-screen-warning-message">
<description id="full-screen-warning-text" value="&domFullScreenWarning.label;"></description>
</hbox>

Просмотреть файл

@ -1,5 +1,6 @@
function test() {
waitForExplicitFinish();
ignoreAllUncaughtExceptions();
// test the main (normal) browser window
testCustomize(window, testChromeless);

Просмотреть файл

@ -1,5 +1,6 @@
function test() {
waitForExplicitFinish();
ignoreAllUncaughtExceptions();
testCustomize(window, finish);
}

Просмотреть файл

@ -40,6 +40,7 @@
function test() {
waitForExplicitFinish();
ignoreAllUncaughtExceptions();
const BOOKMARKS_SIDEBAR_ID = "viewBookmarksSidebar";
const BOOKMARKS_SIDEBAR_TREE_ID = "bookmarks-view";

Просмотреть файл

@ -38,16 +38,9 @@
#include "nsIShellService.idl"
[scriptable, uuid(16e7e8da-8bef-4f41-be5f-045b2e9918e1)]
[scriptable, uuid(89b0a761-d9a0-4c39-ab83-d81566459a31)]
interface nsIWindowsShellService : nsIShellService
{
/**
* The number of unread mail messages for the current user.
*
* @return The number of unread (new) mail messages for the current user.
*/
readonly attribute unsigned long unreadMailCount;
/**
* Provides the shell service an opportunity to do some Win7+ shortcut
* maintenance needed on initial startup of the browser.

Просмотреть файл

@ -803,66 +803,6 @@ nsWindowsShellService::SetDesktopBackgroundColor(PRUint32 aColor)
return NS_OK;
}
NS_IMETHODIMP
nsWindowsShellService::GetUnreadMailCount(PRUint32* aCount)
{
*aCount = 0;
HKEY accountKey;
if (GetMailAccountKey(&accountKey)) {
DWORD type, unreadCount;
DWORD len = sizeof unreadCount;
DWORD res = ::RegQueryValueExW(accountKey, L"MessageCount", 0,
&type, (LPBYTE)&unreadCount, &len);
if (REG_SUCCEEDED(res))
*aCount = unreadCount;
// Close the key we opened.
::RegCloseKey(accountKey);
}
return NS_OK;
}
bool
nsWindowsShellService::GetMailAccountKey(HKEY* aResult)
{
NS_NAMED_LITERAL_STRING(unread,
"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\UnreadMail\\");
HKEY mailKey;
DWORD res = ::RegOpenKeyExW(HKEY_CURRENT_USER, unread.get(), 0,
KEY_ENUMERATE_SUB_KEYS, &mailKey);
PRInt32 i = 0;
do {
PRUnichar subkeyName[MAX_BUF];
DWORD len = sizeof subkeyName;
res = ::RegEnumKeyExW(mailKey, i++, subkeyName, &len, NULL, NULL,
NULL, NULL);
if (REG_SUCCEEDED(res)) {
HKEY accountKey;
res = ::RegOpenKeyExW(mailKey, PromiseFlatString(subkeyName).get(),
0, KEY_READ, &accountKey);
if (REG_SUCCEEDED(res)) {
*aResult = accountKey;
// Close the key we opened.
::RegCloseKey(mailKey);
return true;
}
}
else
break;
}
while (1);
// Close the key we opened.
::RegCloseKey(mailKey);
return false;
}
NS_IMETHODIMP
nsWindowsShellService::OpenApplicationWithURI(nsILocalFile* aApplication,
const nsACString& aURI)

Просмотреть файл

@ -59,8 +59,6 @@ public:
protected:
bool IsDefaultBrowserVista(bool* aIsDefaultBrowser);
bool GetMailAccountKey(HKEY* aResult);
private:
bool mCheckedThisSession;
};

Просмотреть файл

@ -4,6 +4,7 @@
function test()
{
waitForExplicitFinish();
ignoreAllUncaughtExceptions();
let nodes = [
{nodeId: "i1111", result: "i1 i11 i111 i1111"},

Просмотреть файл

@ -8136,8 +8136,6 @@ if test "$MOZ_TREE_CAIRO"; then
SANITY_CHECKING_FEATURE="#undef CAIRO_DO_SANITY_CHECKING"
fi
PNG_FUNCTIONS_FEATURE="#define CAIRO_HAS_PNG_FUNCTIONS 1"
AC_SUBST(PS_SURFACE_FEATURE)
AC_SUBST(PDF_SURFACE_FEATURE)
AC_SUBST(SVG_SURFACE_FEATURE)

Просмотреть файл

@ -110,17 +110,6 @@ public:
return mState;
}
/**
* Request an update of the link state for this element. This will
* make sure that if the element is a link at all then either
* NS_EVENT_STATE_VISITED or NS_EVENT_STATE_UNVISITED is set in
* mState, and a history lookup kicked off if needed to find out
* whether the link is really visited. This method will NOT send any
* state change notifications. If you want them to happen for this
* call, you need to handle them yourself.
*/
virtual void RequestLinkStateUpdate();
/**
* Ask this element to update its state. If aNotify is false, then
* state change notifications will not be dispatched; in that
@ -132,6 +121,11 @@ public:
* removing it from the document).
*/
void UpdateState(bool aNotify);
/**
* Method to update mState with link state information. This does not notify.
*/
void UpdateLinkState(nsEventStates aState);
protected:
/**
@ -142,11 +136,6 @@ protected:
*/
virtual nsEventStates IntrinsicState() const;
/**
* Method to update mState with link state information. This does not notify.
*/
void UpdateLinkState(nsEventStates aState);
/**
* Method to add state bits. This should be called from subclass
* constructors to set up our event state correctly at construction

Просмотреть файл

@ -1735,6 +1735,12 @@ public:
*/
static bool HasPluginWithUncontrolledEventDispatch(nsIContent* aContent);
/**
* Returns the root document in a document hierarchy. Normally this will
* be the chrome document.
*/
static nsIDocument* GetRootDocument(nsIDocument* aDoc);
/**
* Returns the time limit on handling user input before
* nsEventStateManager::IsHandlingUserInput() stops returning true.

Просмотреть файл

@ -166,6 +166,7 @@ public:
// &&-ed in, this is safe.
mAllowDNSPrefetch(true),
mIsBeingUsedAsImage(false),
mHasLinksToUpdate(false),
mPartID(0)
{
SetInDocument();
@ -1489,7 +1490,7 @@ public:
/**
* This method is similar to GetElementById() from nsIDOMDocument but it
* returns a mozilla::dom::Element instead of a nsIDOMElement.
* It prevents converting nsIDOMElement to mozill:dom::Element which is
* It prevents converting nsIDOMElement to mozilla::dom::Element which is
* already converted from mozilla::dom::Element.
*/
virtual Element* GetElementById(const nsAString& aElementId) = 0;
@ -1554,6 +1555,17 @@ public:
virtual nsresult SetNavigationTiming(nsDOMNavigationTiming* aTiming) = 0;
virtual Element* FindImageMap(const nsAString& aNormalizedMapName) = 0;
// Add aLink to the set of links that need their status resolved.
void RegisterPendingLinkUpdate(mozilla::dom::Link* aLink);
// Remove aLink from the set of links that need their status resolved.
// This function must be called when links are removed from the document.
void UnregisterPendingLinkUpdate(mozilla::dom::Link* aElement);
// Update state on links in mLinksToUpdate. This function must
// be called prior to selector matching.
void FlushPendingLinkUpdates();
#define DEPRECATED_OPERATION(_op) e##_op,
enum DeprecatedOperations {
@ -1644,6 +1656,11 @@ protected:
// These are non-owning pointers, the elements are responsible for removing
// themselves when they go away.
nsAutoPtr<nsTHashtable<nsPtrHashKey<nsIContent> > > mFreezableElements;
// The set of all links that need their status resolved. Links must add themselves
// to this set by calling RegisterPendingLinkUpdate when added to a document and must
// remove themselves by calling UnregisterPendingLinkUpdate when removed from a document.
nsTHashtable<nsPtrHashKey<mozilla::dom::Link> > mLinksToUpdate;
// SMIL Animation Controller, lazily-initialized in GetAnimationController
nsRefPtr<nsSMILAnimationController> mAnimationController;
@ -1724,6 +1741,9 @@ protected:
// file, etc.
bool mIsSyntheticDocument;
// True if this document has links whose state needs updating
bool mHasLinksToUpdate;
// The document's script global object, the object from which the
// document can get its script context and scope. This is the
// *inner* window object.

Просмотреть файл

@ -109,6 +109,9 @@ public:
* changes or false if it should not.
*/
void ResetLinkState(bool aNotify);
// This method nevers returns a null element.
Element* GetElement() const { return mElement; }
protected:
virtual ~Link();

Просмотреть файл

@ -5893,6 +5893,20 @@ nsContentUtils::HasPluginWithUncontrolledEventDispatch(nsIContent* aContent)
return result;
}
/* static */
nsIDocument*
nsContentUtils::GetRootDocument(nsIDocument* aDoc)
{
if (!aDoc) {
return nsnull;
}
nsIDocument* doc = aDoc;
while (doc->GetParentDocument()) {
doc = doc->GetParentDocument();
}
return doc;
}
// static
void
nsContentUtils::ReleaseWrapper(nsISupports* aScriptObjectHolder,

Просмотреть файл

@ -51,6 +51,17 @@
NS_IMPL_ISUPPORTS1(nsDataDocumentContentPolicy, nsIContentPolicy)
// Helper method for ShouldLoad()
// Checks a URI for the given flags. Returns true if the URI has the flags,
// and false if not (or if we weren't able to tell).
static bool
HasFlags(nsIURI* aURI, PRUint32 aURIFlags)
{
bool hasFlags;
nsresult rv = NS_URIChainHasFlags(aURI, aURIFlags, &hasFlags);
return NS_SUCCEEDED(rv) && hasFlags;
}
NS_IMETHODIMP
nsDataDocumentContentPolicy::ShouldLoad(PRUint32 aContentType,
nsIURI *aContentLocation,
@ -87,21 +98,26 @@ nsDataDocumentContentPolicy::ShouldLoad(PRUint32 aContentType,
}
if (doc->IsBeingUsedAsImage()) {
// Allow local resources for SVG-as-an-image documents, but disallow
// everything else, to prevent data leakage
bool hasFlags;
nsresult rv = NS_URIChainHasFlags(aContentLocation,
nsIProtocolHandler::URI_IS_LOCAL_RESOURCE,
&hasFlags);
if (NS_FAILED(rv) || !hasFlags) {
// resource is not local (or we couldn't tell) - reject!
// We only allow SVG images to load content from URIs that are local and
// also satisfy one of the following conditions:
// - URI inherits security context, e.g. data URIs
// OR
// - URI loadable by subsumers, e.g. moz-filedata URIs
// Any URI that doesn't meet these requirements will be rejected below.
if (!HasFlags(aContentLocation,
nsIProtocolHandler::URI_IS_LOCAL_RESOURCE) ||
(!HasFlags(aContentLocation,
nsIProtocolHandler::URI_INHERITS_SECURITY_CONTEXT) &&
!HasFlags(aContentLocation,
nsIProtocolHandler::URI_LOADABLE_BY_SUBSUMERS))) {
*aDecision = nsIContentPolicy::REJECT_TYPE;
// report error, if we can.
// Report error, if we can.
if (node) {
nsIPrincipal* requestingPrincipal = node->NodePrincipal();
nsRefPtr<nsIURI> principalURI;
rv = requestingPrincipal->GetURI(getter_AddRefs(principalURI));
nsresult rv =
requestingPrincipal->GetURI(getter_AddRefs(principalURI));
if (NS_SUCCEEDED(rv) && principalURI) {
nsScriptSecurityManager::ReportError(
nsnull, NS_LITERAL_STRING("CheckSameOriginError"), principalURI,
@ -112,8 +128,8 @@ nsDataDocumentContentPolicy::ShouldLoad(PRUint32 aContentType,
doc->GetDocumentURI()) {
// Check for (& disallow) recursive image-loads
bool isRecursiveLoad;
rv = aContentLocation->EqualsExceptRef(doc->GetDocumentURI(),
&isRecursiveLoad);
nsresult rv = aContentLocation->EqualsExceptRef(doc->GetDocumentURI(),
&isRecursiveLoad);
if (NS_FAILED(rv) || isRecursiveLoad) {
NS_WARNING("Refusing to recursively load image");
*aDecision = nsIContentPolicy::REJECT_TYPE;
@ -122,12 +138,12 @@ nsDataDocumentContentPolicy::ShouldLoad(PRUint32 aContentType,
return NS_OK;
}
// Allow all loads for non-external-resource documents
if (!doc->GetDisplayDocument()) {
// Allow all loads for non-resource documents
if (!doc->IsResourceDoc()) {
return NS_OK;
}
// For external resources, blacklist some load types
// For resource documents, blacklist some load types
if (aContentType == nsIContentPolicy::TYPE_OBJECT ||
aContentType == nsIContentPolicy::TYPE_DOCUMENT ||
aContentType == nsIContentPolicy::TYPE_SUBDOCUMENT ||

Просмотреть файл

@ -1554,6 +1554,8 @@ nsDocument::nsDocument(const char* aContentType)
// Start out mLastStyleSheetSet as null, per spec
SetDOMStringToNull(mLastStyleSheetSet);
mLinksToUpdate.Init();
}
static PLDHashOperator
@ -7971,6 +7973,41 @@ nsIDocument::EnumerateFreezableElements(FreezableElementEnumerator aEnumerator,
mFreezableElements->EnumerateEntries(EnumerateFreezables, &data);
}
void
nsIDocument::RegisterPendingLinkUpdate(Link* aLink)
{
mLinksToUpdate.PutEntry(aLink);
mHasLinksToUpdate = true;
}
void
nsIDocument::UnregisterPendingLinkUpdate(Link* aLink)
{
if (!mHasLinksToUpdate)
return;
mLinksToUpdate.RemoveEntry(aLink);
}
static PLDHashOperator
EnumeratePendingLinkUpdates(nsPtrHashKey<Link>* aEntry, void* aData)
{
aEntry->GetKey()->GetElement()->UpdateLinkState(aEntry->GetKey()->LinkState());
return PL_DHASH_NEXT;
}
void
nsIDocument::FlushPendingLinkUpdates()
{
if (!mHasLinksToUpdate)
return;
nsAutoScriptBlocker scriptBlocker;
mLinksToUpdate.EnumerateEntries(EnumeratePendingLinkUpdates, nsnull);
mLinksToUpdate.Clear();
mHasLinksToUpdate = false;
}
already_AddRefed<nsIDocument>
nsIDocument::CreateStaticClone(nsISupports* aCloneContainer)
{
@ -8535,19 +8572,6 @@ GetCommonAncestor(nsIDocument* aDoc1, nsIDocument* aDoc2)
return parent;
}
// Returns the root document in a document hierarchy.
static nsIDocument*
GetRootDocument(nsIDocument* aDoc)
{
if (!aDoc)
return nsnull;
nsIDocument* doc = aDoc;
while (doc->GetParentDocument()) {
doc = doc->GetParentDocument();
}
return doc;
}
class nsCallRequestFullScreen : public nsRunnable
{
public:
@ -8622,8 +8646,8 @@ nsDocument::RequestFullScreen(Element* aElement, bool aWasCallerChrome)
}
// Remember the root document, so that if a full-screen document is hidden
// we can reset full-screen state the remaining visible full-screen documents.
sFullScreenRootDoc = do_GetWeakReference(GetRootDocument(this));
// we can reset full-screen state in the remaining visible full-screen documents.
sFullScreenRootDoc = do_GetWeakReference(nsContentUtils::GetRootDocument(this));
// Set the full-screen element. This sets the full-screen style on the
// element, and the full-screen-ancestor styles on ancestors of the element

Просмотреть файл

@ -1248,11 +1248,6 @@ Element::NotifyStateChange(nsEventStates aStates)
}
}
void
Element::RequestLinkStateUpdate()
{
}
void
Element::UpdateLinkState(nsEventStates aState)
{
@ -5385,6 +5380,7 @@ inline static nsresult FindMatchingElements(nsINode* aRoot,
nsIDocument* doc = aRoot->OwnerDoc();
TreeMatchContext matchingContext(false, nsRuleWalker::eRelevantLinkUnvisited,
doc);
doc->FlushPendingLinkUpdates();
// Fast-path selectors involving IDs. We can only do this if aRoot
// is in the document and the document is not in quirks mode, since
@ -5493,6 +5489,7 @@ nsGenericElement::MozMatchesSelector(const nsAString& aSelector, nsresult* aResu
*aResult = ParseSelectorList(this, aSelector, getter_Transfers(selectorList));
if (NS_SUCCEEDED(*aResult)) {
OwnerDoc()->FlushPendingLinkUpdates();
TreeMatchContext matchingContext(false,
nsRuleWalker::eRelevantLinkUnvisited,
OwnerDoc());

Просмотреть файл

@ -81,6 +81,7 @@ _TEST_FILES_0 = \
test_2d.composite.uncovered.image.source-in.html \
test_2d.composite.uncovered.image.source-out.html \
test_2d.drawImage.zerocanvas.html \
test_toDataURL_alpha.html \
test_toDataURL_lowercase_ascii.html \
test_toDataURL_parameters.html \
test_mozGetAsFile.html \

Просмотреть файл

@ -0,0 +1,206 @@
<!DOCTYPE html>
<html>
<head>
<title>Canvas test: toDataURL parameters (Bug 564388)</title>
<script src="/MochiKit/MochiKit.js"></script>
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" href="/tests/SimpleTest/test.css">
</head>
<body>
<p>
For image types that do not support an alpha channel, the image must be
composited onto a solid black background using the source-over operator,
and the resulting image must be the one used to create the data: URL.
</p>
<p> See:
<a href="http://www.whatwg.org/specs/web-apps/current-work/multipage/the-canvas-element.html#dom-canvas-todataurl">
http://www.whatwg.org/specs/web-apps/current-work/multipage/the-canvas-element.html#dom-canvas-todataurl
</a>
</p>
<p>Mozilla
<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=650720">Bug 650720</a>
</p>
<p class="output">Output:</p>
<!--
Author's note:
To add more cases to this test:
- To add a row (another color value)
* Add a row to the table below, using the canvas id format
(c<row>-<col>)
* Update runTests to include the new row in the loop
- To add a column (another image format)
* Add a column to the table below, using the canvas id format above
* Update runTests to call do_canvas, passing your column number,
the image format, and any options to pass to the toDataUrl function
Vaguely derived from Philip Taylor's toDataURL.jpeg.alpha test:
http://philip.html5.org/tests/canvas/suite/tests/toDataURL.jpeg.alpha.html
-->
<table>
<tr>
<th>Type:</th>
<th>image/png</th>
<th>image/jpeg</th>
<th>image/bmp<br />(24 bpp)</th>
<th>image/bmp<br />(32 bpp)</th>
</tr>
<tr>
<td id="c1">rgba(128, 255, 128, 0.5)</td>
<td><canvas id="c1-1" class="output" width="100" height="50">
<p class="fallback">FAIL (fallback content)</p></canvas></td>
<td><canvas id="c1-2" class="output" width="100" height="50">
<p class="fallback">FAIL (fallback content)</p></canvas></td>
<td><canvas id="c1-3" class="output" width="100" height="50">
<p class="fallback">FAIL (fallback content)</p></canvas></td>
<td><canvas id="c1-4" class="output" width="100" height="50">
<p class="fallback">FAIL (fallback content)</p></canvas></td>
</tr>
<tr>
<td id="c2">rgba(255, 128, 128, 0.75)</td>
<td><canvas id="c2-1" class="output" width="100" height="50">
<p class="fallback">FAIL (fallback content)</p></canvas></td>
<td><canvas id="c2-2" class="output" width="100" height="50">
<p class="fallback">FAIL (fallback content)</p></canvas></td>
<td><canvas id="c2-3" class="output" width="100" height="50">
<p class="fallback">FAIL (fallback content)</p></canvas></td>
<td><canvas id="c2-4" class="output" width="100" height="50">
<p class="fallback">FAIL (fallback content)</p></canvas></td>
</tr>
<tr>
<td id="c3">rgba(128, 128, 255, 0.25)</td>
<td><canvas id="c3-1" class="output" width="100" height="50">
<p class="fallback">FAIL (fallback content)</p></canvas></td>
<td><canvas id="c3-2" class="output" width="100" height="50">
<p class="fallback">FAIL (fallback content)</p></canvas></td>
<td><canvas id="c3-3" class="output" width="100" height="50">
<p class="fallback">FAIL (fallback content)</p></canvas></td>
<td><canvas id="c3-4" class="output" width="100" height="50">
<p class="fallback">FAIL (fallback content)</p></canvas></td>
</tr>
<tr>
<td id="c4">rgba(255, 255, 255, 1.0)</td>
<td><canvas id="c4-1" class="output" width="100" height="50">
<p class="fallback">FAIL (fallback content)</p></canvas></td>
<td><canvas id="c4-2" class="output" width="100" height="50">
<p class="fallback">FAIL (fallback content)</p></canvas></td>
<td><canvas id="c4-3" class="output" width="100" height="50">
<p class="fallback">FAIL (fallback content)</p></canvas></td>
<td><canvas id="c4-4" class="output" width="100" height="50">
<p class="fallback">FAIL (fallback content)</p></canvas></td>
</tr>
<tr>
<td id="c5">rgba(255, 255, 255, 0)</td>
<td><canvas id="c5-1" class="output" width="100" height="50">
<p class="fallback">FAIL (fallback content)</p></canvas></td>
<td><canvas id="c5-2" class="output" width="100" height="50">
<p class="fallback">FAIL (fallback content)</p></canvas></td>
<td><canvas id="c5-3" class="output" width="100" height="50">
<p class="fallback">FAIL (fallback content)</p></canvas></td>
<td><canvas id="c5-4" class="output" width="100" height="50">
<p class="fallback">FAIL (fallback content)</p></canvas></td>
</tr>
<tr>
<td id="c6">rgba(0, 0, 0, 1.0)</td>
<td><canvas id="c6-1" class="output" width="100" height="50">
<p class="fallback">FAIL (fallback content)</p></canvas></td>
<td><canvas id="c6-2" class="output" width="100" height="50">
<p class="fallback">FAIL (fallback content)</p></canvas></td>
<td><canvas id="c6-3" class="output" width="100" height="50">
<p class="fallback">FAIL (fallback content)</p></canvas></td>
<td><canvas id="c6-4" class="output" width="100" height="50">
<p class="fallback">FAIL (fallback content)</p></canvas></td>
</tr>
<tr>
<td id="c7">rgba(0, 0, 0, 0)</td>
<td><canvas id="c7-1" class="output" width="100" height="50">
<p class="fallback">FAIL (fallback content)</p></canvas></td>
<td><canvas id="c7-2" class="output" width="100" height="50">
<p class="fallback">FAIL (fallback content)</p></canvas></td>
<td><canvas id="c7-3" class="output" width="100" height="50">
<p class="fallback">FAIL (fallback content)</p></canvas></td>
<td><canvas id="c7-4" class="output" width="100" height="50">
<p class="fallback">FAIL (fallback content)</p></canvas></td>
</tr>
</table>
<script>
var finishedTests = [];
function isPixel(ctx, x,y, r,g,b,a, d)
{
var pos = x + "," + y;
var colour = r + "," + g + "," + b + "," + a;
var pixel = ctx.getImageData(x, y, 1, 1);
var pr = pixel.data[0],
pg = pixel.data[1],
pb = pixel.data[2],
pa = pixel.data[3];
ok(r-d <= pr && pr <= r+d &&
g-d <= pg && pg <= g+d &&
b-d <= pb && pb <= b+d &&
a-d <= pa && pa <= a+d,
"pixel "+pos+" of "+ctx.canvas.id+" is "+pr+","+pg+","+pb+","+pa+
"; expected "+colour+" +/- "+d);
}
function do_canvas(row, col, type, options)
{
finishedTests[row + '_' + col] = false;
var canvas = document.getElementById('c' + row + '-' + col);
var ctx = canvas.getContext('2d');
ctx.fillStyle = document.getElementById('c' + row).textContent;
ctx.fillRect(0, 0, 100, 50);
var data = canvas.toDataURL(type, options);
ctx.fillStyle = '#000';
ctx.fillRect(0, 0, 100, 50);
var img = new Image();
var color = document.getElementById('c' + row).textContent;
color = color.substr(5, color.length - 6); // strip off the 'argb()'
var colors = color.replace(' ', '', 'g').split(',');
var r = colors[0]*colors[3],
g = colors[1]*colors[3],
b = colors[2]*colors[3];
img.onload = function ()
{
ctx.drawImage(img, 0, 0);
isPixel(ctx, 50,25, r,g,b,255, 8);
finishedTests[row + '_' + col] = true;
};
img.src = data;
}
function checkFinished()
{
for (var t in finishedTests) {
if (!finishedTests[t]) {
setTimeout(checkFinished, 500);
return;
}
}
SimpleTest.finish();
}
function runTests()
{
for (var row = 1; row <= 7; row++) {
do_canvas(row, 1, 'image/png');
do_canvas(row, 2, 'image/jpeg');
do_canvas(row, 3, 'image/bmp');
do_canvas(row, 4, 'image/bmp', '-moz-parse-options:bpp=32');
}
setTimeout(checkFinished, 500);
}
SimpleTest.waitForExplicitFinish();
addLoadEvent(runTests);
</script>
</html>

Просмотреть файл

@ -118,7 +118,6 @@ public:
virtual bool IsLink(nsIURI** aURI) const;
virtual void GetLinkTarget(nsAString& aTarget);
virtual nsLinkState GetLinkState() const;
virtual void RequestLinkStateUpdate();
virtual already_AddRefed<nsIURI> GetHrefURI() const;
nsresult SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
@ -216,9 +215,13 @@ nsHTMLAnchorElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
NS_ENSURE_SUCCESS(rv, rv);
// Prefetch links
if (aDocument && nsHTMLDNSPrefetch::IsAllowed(OwnerDoc())) {
nsHTMLDNSPrefetch::PrefetchLow(this);
if (aDocument) {
aDocument->RegisterPendingLinkUpdate(this);
if (nsHTMLDNSPrefetch::IsAllowed(OwnerDoc())) {
nsHTMLDNSPrefetch::PrefetchLow(this);
}
}
return rv;
}
@ -228,6 +231,11 @@ nsHTMLAnchorElement::UnbindFromTree(bool aDeep, bool aNullParent)
// If this link is ever reinserted into a document, it might
// be under a different xml:base, so forget the cached state now.
Link::ResetLinkState(false);
nsIDocument* doc = GetCurrentDoc();
if (doc) {
doc->UnregisterPendingLinkUpdate(this);
}
nsGenericHTMLElement::UnbindFromTree(aDeep, aNullParent);
}
@ -389,12 +397,6 @@ nsHTMLAnchorElement::GetLinkState() const
return Link::GetLinkState();
}
void
nsHTMLAnchorElement::RequestLinkStateUpdate()
{
UpdateLinkState(Link::LinkState());
}
already_AddRefed<nsIURI>
nsHTMLAnchorElement::GetHrefURI() const
{

Просмотреть файл

@ -99,7 +99,6 @@ public:
virtual bool IsLink(nsIURI** aURI) const;
virtual void GetLinkTarget(nsAString& aTarget);
virtual nsLinkState GetLinkState() const;
virtual void RequestLinkStateUpdate();
virtual already_AddRefed<nsIURI> GetHrefURI() const;
virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
@ -213,7 +212,10 @@ nsHTMLAreaElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
bool aCompileEventHandlers)
{
Link::ResetLinkState(false);
if (aDocument) {
aDocument->RegisterPendingLinkUpdate(this);
}
return nsGenericHTMLElement::BindToTree(aDocument, aParent,
aBindingParent,
aCompileEventHandlers);
@ -225,6 +227,11 @@ nsHTMLAreaElement::UnbindFromTree(bool aDeep, bool aNullParent)
// If this link is ever reinserted into a document, it might
// be under a different xml:base, so forget the cached state now.
Link::ResetLinkState(false);
nsIDocument* doc = GetCurrentDoc();
if (doc) {
doc->UnregisterPendingLinkUpdate(this);
}
nsGenericHTMLElement::UnbindFromTree(aDeep, aNullParent);
}
@ -314,12 +321,6 @@ nsHTMLAreaElement::GetLinkState() const
return Link::GetLinkState();
}
void
nsHTMLAreaElement::RequestLinkStateUpdate()
{
UpdateLinkState(Link::LinkState());
}
already_AddRefed<nsIURI>
nsHTMLAreaElement::GetHrefURI() const
{

Просмотреть файл

@ -111,7 +111,6 @@ public:
virtual bool IsLink(nsIURI** aURI) const;
virtual void GetLinkTarget(nsAString& aTarget);
virtual nsLinkState GetLinkState() const;
virtual void RequestLinkStateUpdate();
virtual already_AddRefed<nsIURI> GetHrefURI() const;
virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const;
@ -213,6 +212,10 @@ nsHTMLLinkElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
aBindingParent,
aCompileEventHandlers);
NS_ENSURE_SUCCESS(rv, rv);
if (aDocument) {
aDocument->RegisterPendingLinkUpdate(this);
}
void (nsHTMLLinkElement::*update)() = &nsHTMLLinkElement::UpdateStyleSheetInternal;
nsContentUtils::AddScriptRunner(NS_NewRunnableMethod(this, update));
@ -246,6 +249,9 @@ nsHTMLLinkElement::UnbindFromTree(bool aDeep, bool aNullParent)
// Once we have XPCOMGC we shouldn't need to call UnbindFromTree during Unlink
// and so this messy event dispatch can go away.
nsCOMPtr<nsIDocument> oldDoc = GetCurrentDoc();
if (oldDoc) {
oldDoc->UnregisterPendingLinkUpdate(this);
}
CreateAndDispatchEvent(oldDoc, NS_LITERAL_STRING("DOMLinkRemoved"));
nsGenericHTMLElement::UnbindFromTree(aDeep, aNullParent);
UpdateStyleSheetInternal(oldDoc);
@ -379,12 +385,6 @@ nsHTMLLinkElement::GetLinkState() const
return Link::GetLinkState();
}
void
nsHTMLLinkElement::RequestLinkStateUpdate()
{
UpdateLinkState(Link::LinkState());
}
already_AddRefed<nsIURI>
nsHTMLLinkElement::GetHrefURI() const
{

Просмотреть файл

@ -274,6 +274,9 @@ _TEST_FILES = \
test_bug583533.html \
test_restore_from_parser_fragment.html \
test_bug617528.html \
test_bug660959-1.html \
test_bug660959-2.html \
test_bug660959-3.html \
test_checked.html \
test_bug677658.html \
test_bug677463.html \
@ -286,6 +289,8 @@ _TEST_FILES = \
file_fullscreen-denied-inner.html \
file_fullscreen-hidden.html \
file_fullscreen-navigation.html \
file_fullscreen-esc-exit.html \
file_fullscreen-esc-exit-inner.html \
test_li_attributes_reflection.html \
test_ol_attributes_reflection.html \
test_bug651956.html \

Просмотреть файл

@ -0,0 +1,58 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=700764
Verify that an ESC key press in a subdoc of a full-screen doc causes us to
exit DOM full-screen mode.
-->
<head>
<title>Test for Bug 700764</title>
<script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
<style>
body:not(:-moz-full-screen) {
background-color: blue;
}
</style>
</head>
<body>
<script type="application/javascript">
/** Test for Bug 700764 **/
function ok(condition, msg) {
parent.ok(condition, msg);
}
function is(a, b, msg) {
parent.is(a, b, msg);
}
var escKeyReceived = false;
var escKeySent = false;
function keyHandler(event) {
if (escKeyReceived == Components.interfaces.nsIDOMKeyEvent.DOM_VK_ESC) {
escKeyReceived = true;
}
}
window.addEventListener("keydown", keyHandler, true);
window.addEventListener("keyup", keyHandler, true);
window.addEventListener("keypress", keyHandler, true);
function startTest() {
ok(!document.mozFullScreen, "Subdoc should not be in full-screen mode");
ok(parent.document.mozFullScreen, "Parent should be in full-screen mode");
escKeySent = true;
window.focus();
synthesizeKey("VK_ESCAPE", {});
}
</script>
</pre>
<p>Inner frame</p>
</body>
</html>

Просмотреть файл

@ -0,0 +1,63 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=700764
Verify that an ESC key press in a subdoc of a full-screen doc causes us to
exit DOM full-screen mode.
-->
<head>
<title>Test for Bug 700764</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<style>
body:-moz-full-screen, div:-moz-full-screen {
background-color: red;
}
</style>
</head>
<body onload="startTest();">
<script type="application/javascript">
function ok(condition, msg) {
opener.ok(condition, msg);
}
function is(a, b, msg) {
opener.is(a, b, msg);
}
function finish() {
opener.nextTest();
}
function fullscreenchange1(event) {
ok(document.mozFullScreen, "Should have entered full-screen mode");
document.removeEventListener("mozfullscreenchange", fullscreenchange1, false);
document.addEventListener("mozfullscreenchange", fullscreenchange2, false);
ok(!document.getElementById("subdoc").contentWindow.escKeySent, "Should not yet have sent ESC key press.");
document.getElementById("subdoc").contentWindow.startTest();
}
function fullscreenchange2(event) {
document.removeEventListener("mozfullscreenchange", fullscreenchange2, false);
ok(document.getElementById("subdoc").contentWindow.escKeySent, "Should have sent ESC key press.");
ok(!document.getElementById("subdoc").contentWindow.escKeyReceived, "ESC key press to exit should not be delivered.");
ok(!document.mozFullScreen, "Should have left full-screen mode on ESC key press");
finish();
}
function startTest() {
document.addEventListener("mozfullscreenchange", fullscreenchange1, false);
SimpleTest.waitForFocus(function() {document.body.mozRequestFullScreen();});
}
</script>
<!-- This subframe conducts the test. -->
<iframe id="subdoc" src="file_fullscreen-esc-exit-inner.html"></iframe>
</pre>
</body>
</html>

Просмотреть файл

@ -0,0 +1,26 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=660959
-->
<head>
<title>Test for Bug 660959</title>
<script type="application/javascript" src="/MochiKit/packed.js"></script>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script src="reflect.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=660959">Mozilla Bug 660959</a>
<p id="display"></p>
<div id="content" style="display: none">
<a href="#" id="testa"></a>
</div>
<pre id="test">
<script>
is($("content").querySelector(":link, :visited"), $("testa"),
"Should find a link even in a display:none subtree");
</script>
</pre>
</body>
</html>

Просмотреть файл

@ -0,0 +1,31 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=660959
-->
<head>
<title>Test for Bug 660959</title>
<script type="application/javascript" src="/MochiKit/packed.js"></script>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script src="reflect.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<style>
:link, :visited {
color: red;
}
</style>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=660959">Mozilla Bug 660959</a>
<p id="display"></p>
<div id="content" style="display: none">
<a href="#" id="a"></a>
</div>
<pre id="test">
<script type="application/javascript">
var a = document.getElementById("a");
is(window.getComputedStyle(a).color, "rgb(255, 0, 0)", "Link is not right color?");
</script>
</pre>
</body>
</html>

Просмотреть файл

@ -0,0 +1,29 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=660959
-->
<head>
<title>Test for Bug 660959</title>
<script type="application/javascript" src="/MochiKit/packed.js"></script>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script src="reflect.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=660959">Mozilla Bug 660959</a>
<p id="display"></p>
<div id="content" style="display: none">
<a href="http://www.example.com"></a>
<div id="foo">
<span id="test"></span>
</div>
</div>
<pre id="test">
<script>
is($("foo").querySelector(":link + * span, :visited + * span"), $("test"),
"Should be able to find link siblings even in a display:none subtree");
</script>
</pre>
</body>
</html>

Просмотреть файл

@ -36,6 +36,7 @@ SpecialPowers.setBoolPref("full-screen-api.allow-trusted-requests-only", false);
// run in an iframe, which by default will not have the mozallowfullscreen
// attribute set, so full-screen won't work.
var gTestWindows = [
"file_fullscreen-esc-exit.html",
"file_fullscreen-denied.html",
"file_fullscreen-api.html",
"file_fullscreen-api-keys.html",

Просмотреть файл

@ -1600,6 +1600,16 @@ nsHTMLDocument::Open(const nsAString& aContentTypeOrUrl,
return NS_OK;
}
// No calling document.open() without a script global object
if (!mScriptGlobalObject) {
return NS_OK;
}
nsPIDOMWindow* outer = GetWindow();
if (!outer || (GetInnerWindow() != outer->GetCurrentInnerWindow())) {
return NS_OK;
}
// check whether we're in the middle of unload. If so, ignore this call.
nsCOMPtr<nsIDocShell> shell = do_QueryReferent(mDocumentContainer);
if (!shell) {

Просмотреть файл

@ -89,19 +89,23 @@ nsMathMLElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
aCompileEventHandlers);
NS_ENSURE_SUCCESS(rv, rv);
if (aDocument && !aDocument->GetMathMLEnabled()) {
// Enable MathML and setup the style sheet during binding, not element
// construction, because we could move a MathML element from the document
// that created it to another document.
aDocument->SetMathMLEnabled();
aDocument->EnsureCatalogStyleSheet(kMathMLStyleSheetURI);
if (aDocument) {
aDocument->RegisterPendingLinkUpdate(this);
if (!aDocument->GetMathMLEnabled()) {
// Enable MathML and setup the style sheet during binding, not element
// construction, because we could move a MathML element from the document
// that created it to another document.
aDocument->SetMathMLEnabled();
aDocument->EnsureCatalogStyleSheet(kMathMLStyleSheetURI);
// Rebuild style data for the presshell, because style system
// optimizations may have taken place assuming MathML was disabled.
// (See nsRuleNode::CheckSpecifiedProperties.)
nsCOMPtr<nsIPresShell> shell = aDocument->GetShell();
if (shell) {
shell->GetPresContext()->PostRebuildAllStyleDataEvent(nsChangeHint(0));
// Rebuild style data for the presshell, because style system
// optimizations may have taken place assuming MathML was disabled.
// (See nsRuleNode::CheckSpecifiedProperties.)
nsCOMPtr<nsIPresShell> shell = aDocument->GetShell();
if (shell) {
shell->GetPresContext()->PostRebuildAllStyleDataEvent(nsChangeHint(0));
}
}
}
@ -114,6 +118,11 @@ nsMathMLElement::UnbindFromTree(bool aDeep, bool aNullParent)
// If this link is ever reinserted into a document, it might
// be under a different xml:base, so forget the cached state now.
Link::ResetLinkState(false);
nsIDocument* doc = GetCurrentDoc();
if (doc) {
doc->UnregisterPendingLinkUpdate(this);
}
nsMathMLElementBase::UnbindFromTree(aDeep, aNullParent);
}
@ -622,12 +631,6 @@ nsMathMLElement::GetLinkState() const
return Link::GetLinkState();
}
void
nsMathMLElement::RequestLinkStateUpdate()
{
UpdateLinkState(Link::LinkState());
}
already_AddRefed<nsIURI>
nsMathMLElement::GetHrefURI() const
{

Просмотреть файл

@ -116,7 +116,6 @@ public:
virtual bool IsLink(nsIURI** aURI) const;
virtual void GetLinkTarget(nsAString& aTarget);
virtual nsLinkState GetLinkState() const;
virtual void RequestLinkStateUpdate();
virtual already_AddRefed<nsIURI> GetHrefURI() const;
nsresult SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
const nsAString& aValue, bool aNotify)

Просмотреть файл

@ -0,0 +1,14 @@
<?xml version="1.0"?>
<svg xmlns="http://www.w3.org/2000/svg" class="reftest-wait">
<script>
<![CDATA[
function boom()
{
document.documentElement.removeChild(document.getElementById("a"));
document.documentElement.removeAttribute("class");
}
]]>
</script>
<animate id="a" begin="a.end; -0.1s" end="a.begin+0.2s" onend="boom()"/>
<animate id="a" begin="a.end; -0.1s" end="a.begin+0.2s"/>
</svg>

После

Ширина:  |  Высота:  |  Размер: 398 B

Просмотреть файл

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg">
<animate id="b" end="b.end" dur="3s" />
</svg>

После

Ширина:  |  Высота:  |  Размер: 90 B

Просмотреть файл

@ -42,4 +42,6 @@ load 670313-1.svg
load 678822-1.svg
load 678847-1.svg
load 678938-1.svg
load 690994-1.svg
load 697640-1.svg
load 699325-1.svg

Просмотреть файл

@ -1622,10 +1622,6 @@ nsSMILTimedElement::GetNextInterval(const nsSMILInterval* aPrevInterval,
beginAfter = aPrevInterval->End()->Time();
prevIntervalWasZeroDur
= aPrevInterval->End()->Time() == aPrevInterval->Begin()->Time();
if (aFixedBeginTime) {
prevIntervalWasZeroDur &=
aPrevInterval->Begin()->Time() == aFixedBeginTime->Time();
}
} else {
beginAfter.SetMillis(LL_MININT);
}
@ -1647,17 +1643,17 @@ nsSMILTimedElement::GetNextInterval(const nsSMILInterval* aPrevInterval,
tempBegin = new nsSMILInstanceTime(nsSMILTimeValue(0));
} else {
PRInt32 beginPos = 0;
// If we're updating the current interval then skip any begin time that is
// dependent on the current interval's begin time. e.g.
// <animate id="a" begin="b.begin; a.begin+2s"...
// If b's interval disappears whilst 'a' is in the waiting state the begin
// time at "a.begin+2s" should be skipped since 'a' never begun.
do {
tempBegin =
GetNextGreaterOrEqual(mBeginInstances, beginAfter, beginPos);
if (!tempBegin || !tempBegin->Time().IsDefinite()) {
return false;
}
// If we're updating the current interval then skip any begin time that is
// dependent on the current interval's begin time. e.g.
// <animate id="a" begin="b.begin; a.begin+2s"...
// If b's interval disappears whilst 'a' is in the waiting state the begin
// time at "a.begin+2s" should be skipped since 'a' never begun.
} while (aReplacedInterval &&
tempBegin->GetBaseTime() == aReplacedInterval->Begin());
}
@ -1668,37 +1664,55 @@ nsSMILTimedElement::GetNextInterval(const nsSMILInterval* aPrevInterval,
// Calculate end time
{
PRInt32 endPos = 0;
// As above with begin times, avoid creating self-referential loops
// between instance times by checking that the newly found end instance
// time is not already dependent on the end of the current interval.
do {
tempEnd =
GetNextGreaterOrEqual(mEndInstances, tempBegin->Time(), endPos);
// SMIL doesn't allow for coincident zero-duration intervals, so if the
// previous interval was zero-duration, and tempEnd is going to give us
// another zero duration interval, then look for another end to use
// instead.
if (tempEnd && prevIntervalWasZeroDur &&
tempEnd->Time() == beginAfter) {
tempEnd = GetNextGreater(mEndInstances, tempBegin->Time(), endPos);
}
// As above with begin times, avoid creating self-referential loops
// between instance times by checking that the newly found end instance
// time is not already dependent on the end of the current interval.
} while (tempEnd && aReplacedInterval &&
tempEnd->GetBaseTime() == aReplacedInterval->End());
// If the last interval ended at the same point and was zero-duration and
// this one is too, look for another end to use instead
if (tempEnd && tempEnd->Time() == tempBegin->Time() &&
prevIntervalWasZeroDur) {
tempEnd = GetNextGreater(mEndInstances, tempBegin->Time(), endPos);
}
// If all the ends are before the beginning we have a bad interval UNLESS:
// a) We never had any end attribute to begin with (and hence we should
// just use the active duration after allowing for the possibility of
// an end instance provided by a DOM call), OR
// b) We have no definite end instances (SMIL only says "if the instance
// list is empty"--but if we have indefinite/unresolved instance times
// then there must be a good reason we haven't used them (since they
// will be >= tempBegin) such as avoiding creating a self-referential
// loop. In any case, the interval should be allowed to be open.), OR
// c) We have end events which leave the interval open-ended.
bool openEndedIntervalOk = mEndSpecs.IsEmpty() ||
!HaveDefiniteEndTimes() ||
if (!tempEnd) {
// If all the ends are before the beginning we have a bad interval
// UNLESS:
// a) We never had any end attribute to begin with (the SMIL pseudocode
// places this condition earlier in the flow but that fails to allow
// for DOM calls when no "indefinite" condition is given), OR
// b) We never had any end instance times to begin with, OR
// c) We have end events which leave the interval open-ended.
bool openEndedIntervalOk = mEndSpecs.IsEmpty() ||
mEndInstances.IsEmpty() ||
EndHasEventConditions();
if (!tempEnd && !openEndedIntervalOk)
return false; // Bad interval
// The above conditions correspond with the SMIL pseudocode but SMIL
// doesn't address self-dependent instance times which we choose to
// ignore.
//
// Therefore we add a qualification of (b) above that even if
// there are end instance times but they all depend on the end of the
// current interval we should act as if they didn't exist and allow the
// open-ended interval.
//
// In the following condition we don't use |= because it doesn't provide
// short-circuit behavior.
openEndedIntervalOk = openEndedIntervalOk ||
(aReplacedInterval &&
AreEndTimesDependentOn(aReplacedInterval->End()));
if (!openEndedIntervalOk) {
return false; // Bad interval
}
}
nsSMILTimeValue intervalEnd = tempEnd
? tempEnd->Time() : nsSMILTimeValue();
@ -1710,17 +1724,21 @@ nsSMILTimedElement::GetNextInterval(const nsSMILInterval* aPrevInterval,
}
NS_ABORT_IF_FALSE(tempEnd, "Failed to get end point for next interval");
// If we get two zero-length intervals in a row we will potentially have an
// infinite loop so we break it here by searching for the next begin time
// greater than tempEnd on the next time around.
if (tempEnd->Time().IsDefinite() && tempBegin->Time() == tempEnd->Time()) {
// When we choose the interval endpoints, we don't allow coincident
// zero-duration intervals, so if we arrive here and we have a zero-duration
// interval starting at the same point as a previous zero-duration interval,
// then it must be because we've applied constraints to the active duration.
// In that case, we will potentially run into an infinite loop, so we break
// it by searching for the next interval that starts AFTER our current
// zero-duration interval.
if (prevIntervalWasZeroDur && tempEnd->Time() == beginAfter) {
if (prevIntervalWasZeroDur) {
beginAfter.SetMillis(tempEnd->Time().GetMillis() + 1);
beginAfter.SetMillis(tempBegin->Time().GetMillis() + 1);
prevIntervalWasZeroDur = false;
continue;
}
prevIntervalWasZeroDur = true;
}
prevIntervalWasZeroDur = tempBegin->Time() == tempEnd->Time();
// Check for valid interval
if (tempEnd->Time() > zeroTime ||
@ -2252,17 +2270,6 @@ nsSMILTimedElement::GetPreviousInterval() const
: mOldIntervals[mOldIntervals.Length()-1].get();
}
bool
nsSMILTimedElement::HaveDefiniteEndTimes() const
{
if (mEndInstances.IsEmpty())
return false;
// mEndInstances is sorted so if the first time is not definite then none of
// them are
return mEndInstances[0]->Time().IsDefinite();
}
bool
nsSMILTimedElement::EndHasEventConditions() const
{
@ -2273,6 +2280,21 @@ nsSMILTimedElement::EndHasEventConditions() const
return false;
}
bool
nsSMILTimedElement::AreEndTimesDependentOn(
const nsSMILInstanceTime* aBase) const
{
if (mEndInstances.IsEmpty())
return false;
for (PRUint32 i = 0; i < mEndInstances.Length(); ++i) {
if (mEndInstances[i]->GetBaseTime() != aBase) {
return false;
}
}
return true;
}
//----------------------------------------------------------------------
// Hashtable callback functions

Просмотреть файл

@ -525,8 +525,9 @@ protected:
const nsSMILInstanceTime* GetEffectiveBeginInstance() const;
const nsSMILInterval* GetPreviousInterval() const;
bool HasPlayed() const { return !mOldIntervals.IsEmpty(); }
bool HaveDefiniteEndTimes() const;
bool EndHasEventConditions() const;
bool AreEndTimesDependentOn(
const nsSMILInstanceTime* aBase) const;
// Reset the current interval by first passing ownership to a temporary
// variable so that if Unlink() results in us receiving a callback,

Просмотреть файл

@ -145,6 +145,10 @@ nsSVGAElement::BindToTree(nsIDocument *aDocument, nsIContent *aParent,
aBindingParent,
aCompileEventHandlers);
NS_ENSURE_SUCCESS(rv, rv);
if (aDocument) {
aDocument->RegisterPendingLinkUpdate(this);
}
return NS_OK;
}
@ -155,6 +159,11 @@ nsSVGAElement::UnbindFromTree(bool aDeep, bool aNullParent)
// If this link is ever reinserted into a document, it might
// be under a different xml:base, so forget the cached state now.
Link::ResetLinkState(false);
nsIDocument* doc = GetCurrentDoc();
if (doc) {
doc->UnregisterPendingLinkUpdate(this);
}
nsSVGAElementBase::UnbindFromTree(aDeep, aNullParent);
}
@ -165,12 +174,6 @@ nsSVGAElement::GetLinkState() const
return Link::GetLinkState();
}
void
nsSVGAElement::RequestLinkStateUpdate()
{
UpdateLinkState(Link::LinkState());
}
already_AddRefed<nsIURI>
nsSVGAElement::GetHrefURI() const
{

Просмотреть файл

@ -91,7 +91,6 @@ public:
virtual bool IsLink(nsIURI** aURI) const;
virtual void GetLinkTarget(nsAString& aTarget);
virtual nsLinkState GetLinkState() const;
virtual void RequestLinkStateUpdate();
virtual already_AddRefed<nsIURI> GetHrefURI() const;
virtual nsEventStates IntrinsicState() const;
nsresult SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,

Просмотреть файл

@ -16,6 +16,7 @@
<script class="testbody" type="application/javascript">
<![CDATA[
SimpleTest.waitForExplicitFinish();
SimpleTest.ignoreAllUncaughtExceptions();
Components.utils.import("resource://gre/modules/NetUtil.jsm");
Components.utils.import("resource://gre/modules/Services.jsm");

Просмотреть файл

@ -62,6 +62,8 @@ import android.webkit.MimeTypeMap;
import android.media.MediaScannerConnection;
import android.media.MediaScannerConnection.MediaScannerConnectionClient;
import android.provider.Settings;
import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.AccessibilityEvent;
import android.util.*;
import android.net.Uri;
@ -411,8 +413,6 @@ public class GeckoAppShell
GeckoAppShell.nativeRun(combinedArgs);
}
private static GeckoEvent mLastDrawEvent;
private static void sendPendingEventsToGecko() {
try {
while (!gPendingEvents.isEmpty()) {
@ -1359,6 +1359,13 @@ public class GeckoAppShell
return true;
}
}
public static boolean getAccessibilityEnabled() {
AccessibilityManager accessibilityManager =
(AccessibilityManager) GeckoApp.mAppContext.getSystemService(Context.ACCESSIBILITY_SERVICE);
return accessibilityManager.isEnabled();
}
public static void addPluginView(final View view,
final double x, final double y,
final double w, final double h) {
@ -1620,6 +1627,16 @@ public class GeckoAppShell
}
}
// unused
public static String handleGeckoMessage(String message) {
return "";
}
// unused
static void checkUriVisited(String uri) {}
// unused
static void markUriVisited(final String uri) {}
public static void enableBatteryNotifications() {
GeckoBatteryManager.enableNotifications();
}

Просмотреть файл

@ -73,6 +73,8 @@ public class GeckoEvent {
public static final int SURFACE_DESTROYED = 14;
public static final int GECKO_EVENT_SYNC = 15;
public static final int ACTIVITY_START = 17;
public static final int SAVE_STATE = 18;
public static final int BROADCAST = 19;
public static final int IME_COMPOSITION_END = 0;
public static final int IME_COMPOSITION_BEGIN = 1;
@ -104,7 +106,7 @@ public class GeckoEvent {
public int mMetaState, mFlags;
public int mKeyCode, mUnicodeChar;
public int mOffset, mCount;
public String mCharacters;
public String mCharacters, mCharactersExtra;
public int mRangeType, mRangeStyles;
public int mRangeForeColor, mRangeBackColor;
public Location mLocation;
@ -223,6 +225,12 @@ public class GeckoEvent {
mP1 = new Point(screenw, screenh);
}
public GeckoEvent(String subject, String data) {
mType = BROADCAST;
mCharacters = subject;
mCharactersExtra = data;
}
public GeckoEvent(String uri) {
mType = LOAD_URI;
mCharacters = uri;

Просмотреть файл

@ -12,6 +12,7 @@
<script type="application/javascript">
<![CDATA[
SimpleTest.waitForExplicitFinish();
SimpleTest.ignoreAllUncaughtExceptions();
function getMisspelledWords(editor) {
return editor.selectionController.getSelection(Components.interfaces.nsISelectionController.SELECTION_SPELLCHECK).toString();

Просмотреть файл

@ -308,6 +308,63 @@ struct BaseRect {
T XMost() const { return x + width; }
T YMost() const { return y + height; }
// Round the rectangle edges to integer coordinates, such that the rounded
// rectangle has the same set of pixel centers as the original rectangle.
// Edges at offset 0.5 round up.
// Suitable for most places where integral device coordinates
// are needed, but note that any translation should be applied first to
// avoid pixel rounding errors.
// Note that this is *not* rounding to nearest integer if the values are negative.
// They are always rounding as floor(n + 0.5).
// See https://bugzilla.mozilla.org/show_bug.cgi?id=410748#c14
// If you need similar method which is using NS_round(), you should create
// new |RoundAwayFromZero()| method.
void Round()
{
T x0 = static_cast<T>(floor(T(X()) + 0.5));
T y0 = static_cast<T>(floor(T(Y()) + 0.5));
T x1 = static_cast<T>(floor(T(XMost()) + 0.5));
T y1 = static_cast<T>(floor(T(YMost()) + 0.5));
x = x0;
y = y0;
width = x1 - x0;
height = y1 - y0;
}
// Snap the rectangle edges to integer coordinates, such that the
// original rectangle contains the resulting rectangle.
void RoundIn()
{
T x0 = static_cast<T>(ceil(T(X())));
T y0 = static_cast<T>(ceil(T(Y())));
T x1 = static_cast<T>(floor(T(XMost())));
T y1 = static_cast<T>(floor(T(YMost())));
x = x0;
y = y0;
width = x1 - x0;
height = y1 - y0;
}
// Snap the rectangle edges to integer coordinates, such that the
// resulting rectangle contains the original rectangle.
void RoundOut()
{
T x0 = static_cast<T>(floor(T(X())));
T y0 = static_cast<T>(floor(T(Y())));
T x1 = static_cast<T>(ceil(T(XMost())));
T y1 = static_cast<T>(ceil(T(YMost())));
x = x0;
y = y0;
width = x1 - x0;
height = y1 - y0;
}
// Scale 'this' by aScale, converting coordinates to integers so that the result is
// the smallest integer-coordinate rectangle containing the unrounded result.
// Note: this can turn an empty rectangle into a non-empty rectangle

526
gfx/2d/Blur.cpp Normal file
Просмотреть файл

@ -0,0 +1,526 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla gfx.
*
* The Initial Developer of the Original Code is Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include <algorithm>
#include <math.h>
#include "CheckedInt.h"
#include "mozilla/Util.h"
#include "mozilla/gfx/Blur.h"
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif
using namespace std;
namespace mozilla {
namespace gfx {
/**
* Box blur involves looking at one pixel, and setting its value to the average
* of its neighbouring pixels.
* @param aInput The input buffer.
* @param aOutput The output buffer.
* @param aLeftLobe The number of pixels to blend on the left.
* @param aRightLobe The number of pixels to blend on the right.
* @param aWidth The number of columns in the buffers.
* @param aRows The number of rows in the buffers.
* @param aSkipRect An area to skip blurring in.
* XXX shouldn't we pass stride in separately here?
*/
static void
BoxBlurHorizontal(unsigned char* aInput,
unsigned char* aOutput,
int32_t aLeftLobe,
int32_t aRightLobe,
int32_t aWidth,
int32_t aRows,
const IntRect& aSkipRect)
{
MOZ_ASSERT(aWidth > 0);
int32_t boxSize = aLeftLobe + aRightLobe + 1;
bool skipRectCoversWholeRow = 0 >= aSkipRect.x &&
aWidth <= aSkipRect.XMost();
for (int32_t y = 0; y < aRows; y++) {
// Check whether the skip rect intersects this row. If the skip
// rect covers the whole surface in this row, we can avoid
// this row entirely (and any others along the skip rect).
bool inSkipRectY = y >= aSkipRect.y &&
y < aSkipRect.YMost();
if (inSkipRectY && skipRectCoversWholeRow) {
y = aSkipRect.YMost() - 1;
continue;
}
int32_t alphaSum = 0;
for (int32_t i = 0; i < boxSize; i++) {
int32_t pos = i - aLeftLobe;
// See assertion above; if aWidth is zero, then we would have no
// valid position to clamp to.
pos = max(pos, 0);
pos = min(pos, aWidth - 1);
alphaSum += aInput[aWidth * y + pos];
}
for (int32_t x = 0; x < aWidth; x++) {
// Check whether we are within the skip rect. If so, go
// to the next point outside the skip rect.
if (inSkipRectY && x >= aSkipRect.x &&
x < aSkipRect.XMost()) {
x = aSkipRect.XMost();
if (x >= aWidth)
break;
// Recalculate the neighbouring alpha values for
// our new point on the surface.
alphaSum = 0;
for (int32_t i = 0; i < boxSize; i++) {
int32_t pos = x + i - aLeftLobe;
// See assertion above; if aWidth is zero, then we would have no
// valid position to clamp to.
pos = max(pos, 0);
pos = min(pos, aWidth - 1);
alphaSum += aInput[aWidth * y + pos];
}
}
int32_t tmp = x - aLeftLobe;
int32_t last = max(tmp, 0);
int32_t next = min(tmp + boxSize, aWidth - 1);
aOutput[aWidth * y + x] = alphaSum / boxSize;
alphaSum += aInput[aWidth * y + next] -
aInput[aWidth * y + last];
}
}
}
/**
* Identical to BoxBlurHorizontal, except it blurs top and bottom instead of
* left and right.
* XXX shouldn't we pass stride in separately here?
*/
static void
BoxBlurVertical(unsigned char* aInput,
unsigned char* aOutput,
int32_t aTopLobe,
int32_t aBottomLobe,
int32_t aWidth,
int32_t aRows,
const IntRect& aSkipRect)
{
MOZ_ASSERT(aRows > 0);
int32_t boxSize = aTopLobe + aBottomLobe + 1;
bool skipRectCoversWholeColumn = 0 >= aSkipRect.y &&
aRows <= aSkipRect.YMost();
for (int32_t x = 0; x < aWidth; x++) {
bool inSkipRectX = x >= aSkipRect.x &&
x < aSkipRect.XMost();
if (inSkipRectX && skipRectCoversWholeColumn) {
x = aSkipRect.XMost() - 1;
continue;
}
int32_t alphaSum = 0;
for (int32_t i = 0; i < boxSize; i++) {
int32_t pos = i - aTopLobe;
// See assertion above; if aRows is zero, then we would have no
// valid position to clamp to.
pos = max(pos, 0);
pos = min(pos, aRows - 1);
alphaSum += aInput[aWidth * pos + x];
}
for (int32_t y = 0; y < aRows; y++) {
if (inSkipRectX && y >= aSkipRect.y &&
y < aSkipRect.YMost()) {
y = aSkipRect.YMost();
if (y >= aRows)
break;
alphaSum = 0;
for (int32_t i = 0; i < boxSize; i++) {
int32_t pos = y + i - aTopLobe;
// See assertion above; if aRows is zero, then we would have no
// valid position to clamp to.
pos = max(pos, 0);
pos = min(pos, aRows - 1);
alphaSum += aInput[aWidth * pos + x];
}
}
int32_t tmp = y - aTopLobe;
int32_t last = max(tmp, 0);
int32_t next = min(tmp + boxSize, aRows - 1);
aOutput[aWidth * y + x] = alphaSum/boxSize;
alphaSum += aInput[aWidth * next + x] -
aInput[aWidth * last + x];
}
}
}
static void ComputeLobes(int32_t aRadius, int32_t aLobes[3][2])
{
int32_t major, minor, final;
/* See http://www.w3.org/TR/SVG/filters.html#feGaussianBlur for
* some notes about approximating the Gaussian blur with box-blurs.
* The comments below are in the terminology of that page.
*/
int32_t z = aRadius / 3;
switch (aRadius % 3) {
case 0:
// aRadius = z*3; choose d = 2*z + 1
major = minor = final = z;
break;
case 1:
// aRadius = z*3 + 1
// This is a tricky case since there is no value of d which will
// yield a radius of exactly aRadius. If d is odd, i.e. d=2*k + 1
// for some integer k, then the radius will be 3*k. If d is even,
// i.e. d=2*k, then the radius will be 3*k - 1.
// So we have to choose values that don't match the standard
// algorithm.
major = z + 1;
minor = final = z;
break;
case 2:
// aRadius = z*3 + 2; choose d = 2*z + 2
major = final = z + 1;
minor = z;
break;
default:
// Mathematical impossibility!
MOZ_ASSERT(false);
major = minor = final = 0;
}
MOZ_ASSERT(major + minor + final == aRadius);
aLobes[0][0] = major;
aLobes[0][1] = minor;
aLobes[1][0] = minor;
aLobes[1][1] = major;
aLobes[2][0] = final;
aLobes[2][1] = final;
}
static void
SpreadHorizontal(unsigned char* aInput,
unsigned char* aOutput,
int32_t aRadius,
int32_t aWidth,
int32_t aRows,
int32_t aStride,
const IntRect& aSkipRect)
{
if (aRadius == 0) {
memcpy(aOutput, aInput, aStride * aRows);
return;
}
bool skipRectCoversWholeRow = 0 >= aSkipRect.x &&
aWidth <= aSkipRect.XMost();
for (int32_t y = 0; y < aRows; y++) {
// Check whether the skip rect intersects this row. If the skip
// rect covers the whole surface in this row, we can avoid
// this row entirely (and any others along the skip rect).
bool inSkipRectY = y >= aSkipRect.y &&
y < aSkipRect.YMost();
if (inSkipRectY && skipRectCoversWholeRow) {
y = aSkipRect.YMost() - 1;
continue;
}
for (int32_t x = 0; x < aWidth; x++) {
// Check whether we are within the skip rect. If so, go
// to the next point outside the skip rect.
if (inSkipRectY && x >= aSkipRect.x &&
x < aSkipRect.XMost()) {
x = aSkipRect.XMost();
if (x >= aWidth)
break;
}
int32_t sMin = max(x - aRadius, 0);
int32_t sMax = min(x + aRadius, aWidth - 1);
int32_t v = 0;
for (int32_t s = sMin; s <= sMax; ++s) {
v = max<int32_t>(v, aInput[aStride * y + s]);
}
aOutput[aStride * y + x] = v;
}
}
}
static void
SpreadVertical(unsigned char* aInput,
unsigned char* aOutput,
int32_t aRadius,
int32_t aWidth,
int32_t aRows,
int32_t aStride,
const IntRect& aSkipRect)
{
if (aRadius == 0) {
memcpy(aOutput, aInput, aStride * aRows);
return;
}
bool skipRectCoversWholeColumn = 0 >= aSkipRect.y &&
aRows <= aSkipRect.YMost();
for (int32_t x = 0; x < aWidth; x++) {
bool inSkipRectX = x >= aSkipRect.x &&
x < aSkipRect.XMost();
if (inSkipRectX && skipRectCoversWholeColumn) {
x = aSkipRect.XMost() - 1;
continue;
}
for (int32_t y = 0; y < aRows; y++) {
// Check whether we are within the skip rect. If so, go
// to the next point outside the skip rect.
if (inSkipRectX && y >= aSkipRect.y &&
y < aSkipRect.YMost()) {
y = aSkipRect.YMost();
if (y >= aRows)
break;
}
int32_t sMin = max(y - aRadius, 0);
int32_t sMax = min(y + aRadius, aRows - 1);
int32_t v = 0;
for (int32_t s = sMin; s <= sMax; ++s) {
v = max<int32_t>(v, aInput[aStride * s + x]);
}
aOutput[aStride * y + x] = v;
}
}
}
static CheckedInt<int32_t>
RoundUpToMultipleOf4(int32_t aVal)
{
CheckedInt<int32_t> val(aVal);
val += 3;
val /= 4;
val *= 4;
return val;
}
AlphaBoxBlur::AlphaBoxBlur(const Rect& aRect,
const IntSize& aSpreadRadius,
const IntSize& aBlurRadius,
const Rect* aDirtyRect,
const Rect* aSkipRect)
: mSpreadRadius(aSpreadRadius),
mBlurRadius(aBlurRadius),
mData(NULL)
{
Rect rect(aRect);
rect.Inflate(Size(aBlurRadius + aSpreadRadius));
rect.RoundOut();
if (aDirtyRect) {
// If we get passed a dirty rect from layout, we can minimize the
// shadow size and make painting faster.
mHasDirtyRect = true;
mDirtyRect = *aDirtyRect;
Rect requiredBlurArea = mDirtyRect.Intersect(rect);
requiredBlurArea.Inflate(Size(aBlurRadius + aSpreadRadius));
rect = requiredBlurArea.Intersect(rect);
} else {
mHasDirtyRect = false;
}
if (rect.IsEmpty()) {
return;
}
if (aSkipRect) {
// If we get passed a skip rect, we can lower the amount of
// blurring/spreading we need to do. We convert it to IntRect to avoid
// expensive int<->float conversions if we were to use Rect instead.
Rect skipRect = *aSkipRect;
skipRect.RoundIn();
skipRect.Deflate(Size(aBlurRadius + aSpreadRadius));
mSkipRect = IntRect(skipRect.x, skipRect.y, skipRect.width, skipRect.height);
IntRect shadowIntRect(rect.x, rect.y, rect.width, rect.height);
mSkipRect.IntersectRect(mSkipRect, shadowIntRect);
if (mSkipRect.IsEqualInterior(shadowIntRect))
return;
mSkipRect -= shadowIntRect.TopLeft();
} else {
mSkipRect = IntRect(0, 0, 0, 0);
}
mRect = IntRect(rect.x, rect.y, rect.width, rect.height);
CheckedInt<int32_t> stride = RoundUpToMultipleOf4(mRect.width);
if (stride.valid()) {
mStride = stride.value();
CheckedInt<int32_t> size = CheckedInt<int32_t>(mStride) * mRect.height *
sizeof(unsigned char);
if (size.valid()) {
mData = static_cast<unsigned char*>(malloc(size.value()));
memset(mData, 0, size.value());
}
}
}
AlphaBoxBlur::~AlphaBoxBlur()
{
free(mData);
}
unsigned char*
AlphaBoxBlur::GetData()
{
return mData;
}
IntSize
AlphaBoxBlur::GetSize()
{
IntSize size(mRect.width, mRect.height);
return size;
}
int32_t
AlphaBoxBlur::GetStride()
{
return mStride;
}
IntRect
AlphaBoxBlur::GetRect()
{
return mRect;
}
Rect*
AlphaBoxBlur::GetDirtyRect()
{
if (mHasDirtyRect) {
return &mDirtyRect;
}
return NULL;
}
void
AlphaBoxBlur::Blur()
{
if (!mData) {
return;
}
// no need to do all this if not blurring or spreading
if (mBlurRadius != IntSize(0,0) || mSpreadRadius != IntSize(0,0)) {
int32_t stride = GetStride();
// No need to use CheckedInt here - we have validated it in the constructor.
size_t szB = stride * GetSize().height * sizeof(unsigned char);
unsigned char* tmpData = static_cast<unsigned char*>(malloc(szB));
if (!tmpData)
return; // OOM
memset(tmpData, 0, szB);
if (mSpreadRadius.width > 0 || mSpreadRadius.height > 0) {
SpreadHorizontal(mData, tmpData, mSpreadRadius.width, GetSize().width, GetSize().height, stride, mSkipRect);
SpreadVertical(tmpData, mData, mSpreadRadius.height, GetSize().width, GetSize().height, stride, mSkipRect);
}
if (mBlurRadius.width > 0) {
int32_t lobes[3][2];
ComputeLobes(mBlurRadius.width, lobes);
BoxBlurHorizontal(mData, tmpData, lobes[0][0], lobes[0][1], stride, GetSize().height, mSkipRect);
BoxBlurHorizontal(tmpData, mData, lobes[1][0], lobes[1][1], stride, GetSize().height, mSkipRect);
BoxBlurHorizontal(mData, tmpData, lobes[2][0], lobes[2][1], stride, GetSize().height, mSkipRect);
} else {
memcpy(tmpData, mData, stride * GetSize().height);
}
if (mBlurRadius.height > 0) {
int32_t lobes[3][2];
ComputeLobes(mBlurRadius.height, lobes);
BoxBlurVertical(tmpData, mData, lobes[0][0], lobes[0][1], stride, GetSize().height, mSkipRect);
BoxBlurVertical(mData, tmpData, lobes[1][0], lobes[1][1], stride, GetSize().height, mSkipRect);
BoxBlurVertical(tmpData, mData, lobes[2][0], lobes[2][1], stride, GetSize().height, mSkipRect);
} else {
memcpy(mData, tmpData, stride * GetSize().height);
}
free(tmpData);
}
}
/**
* Compute the box blur size (which we're calling the blur radius) from
* the standard deviation.
*
* Much of this, the 3 * sqrt(2 * pi) / 4, is the known value for
* approximating a Gaussian using box blurs. This yields quite a good
* approximation for a Gaussian. Then we multiply this by 1.5 since our
* code wants the radius of the entire triple-box-blur kernel instead of
* the diameter of an individual box blur. For more details, see:
* http://www.w3.org/TR/SVG11/filters.html#feGaussianBlurElement
* https://bugzilla.mozilla.org/show_bug.cgi?id=590039#c19
*/
static const Float GAUSSIAN_SCALE_FACTOR = (3 * sqrt(2 * M_PI) / 4) * 1.5;
IntSize
AlphaBoxBlur::CalculateBlurRadius(const Point& aStd)
{
IntSize size(static_cast<int32_t>(floor(aStd.x * GAUSSIAN_SCALE_FACTOR + 0.5)),
static_cast<int32_t>(floor(aStd.y * GAUSSIAN_SCALE_FACTOR + 0.5)));
return size;
}
}
}

180
gfx/2d/Blur.h Normal file
Просмотреть файл

@ -0,0 +1,180 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla gfx.
*
* The Initial Developer of the Original Code is Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "mozilla/gfx/Rect.h"
#include "mozilla/gfx/Point.h"
namespace mozilla {
namespace gfx {
/**
* Implementation of a triple box blur approximation of a Gaussian blur.
*
* A Gaussian blur is good for blurring because, when done independently
* in the horizontal and vertical directions, it matches the result that
* would be obtained using a different (rotated) set of axes. A triple
* box blur is a very close approximation of a Gaussian.
*
* Creates an 8-bit alpha channel context for callers to draw in,
* spreads the contents of that context, and blurs the contents.
*
* A spread N makes each output pixel the maximum value of all source
* pixels within a square of side length 2N+1 centered on the output pixel.
*
* A temporary surface is created in the Init function. The caller then draws
* any desired content onto the context acquired through GetContext, and lastly
* calls Paint to apply the blurred content as an alpha mask.
*/
class AlphaBoxBlur
{
public:
/** Constructs a box blur and initializes the backing surface.
*
* @param aRect The coordinates of the surface to create in device units.
*
* @param aBlurRadius The blur radius in pixels. This is the radius of the
* entire (triple) kernel function. Each individual box blur has radius
* approximately 1/3 this value, or diameter approximately 2/3 this value.
* This parameter should nearly always be computed using CalculateBlurRadius,
* below.
*
* @param aDirtyRect A pointer to a dirty rect, measured in device units, if
* available. This will be used for optimizing the blur operation. It is
* safe to pass NULL here.
*
* @param aSkipRect A pointer to a rect, measured in device units, that
* represents an area where blurring is unnecessary and shouldn't be done for
* speed reasons. It is safe to pass NULL here.
*/
AlphaBoxBlur(const Rect& aRect,
const IntSize& aSpreadRadius,
const IntSize& aBlurRadius,
const Rect* aDirtyRect,
const Rect* aSkipRect);
~AlphaBoxBlur();
/**
* Return the pointer to memory allocated by the constructor for the 8-bit
* alpha surface you need to be blurred. After you draw to this surface, call
* Blur(), below, to have its contents blurred.
*/
unsigned char* GetData();
/**
* Return the size, in pixels, of the 8-bit alpha surface backed by the
* pointer returned by GetData().
*/
IntSize GetSize();
/**
* Return the stride, in bytes, of the 8-bit alpha surface backed by the
* pointer returned by GetData().
*/
int32_t GetStride();
/**
* Returns the device-space rectangle the 8-bit alpha surface covers.
*/
IntRect GetRect();
/**
* Return a pointer to a dirty rect, as passed in to the constructor, or NULL
* if none was passed in.
*/
Rect* GetDirtyRect();
/**
* Perform the blur in-place on the surface backed by the pointer returned by
* GetData().
*/
void Blur();
/**
* Calculates a blur radius that, when used with box blur, approximates a
* Gaussian blur with the given standard deviation. The result of this
* function should be used as the aBlurRadius parameter to AlphaBoxBlur's
* constructor, above.
*/
static IntSize CalculateBlurRadius(const Point& aStandardDeviation);
private:
/**
* A rect indicating the area where blurring is unnecessary, and the blur
* algorithm should skip over it.
*/
IntRect mSkipRect;
/**
* The device-space rectangle the the backing 8-bit alpha surface covers.
*/
IntRect mRect;
/**
* A copy of the dirty rect passed to the constructor. This will only be valid if
* mHasDirtyRect is true.
*/
Rect mDirtyRect;
/**
* The spread radius, in pixels.
*/
IntSize mSpreadRadius;
/**
* The blur radius, in pixels.
*/
IntSize mBlurRadius;
/**
* A pointer to the backing 8-bit alpha surface.
*/
unsigned char* mData;
/**
* The stride of the data contained in mData.
*/
int32_t mStride;
/**
* Whether mDirtyRect contains valid data.
*/
bool mHasDirtyRect;
};
}
}

Просмотреть файл

@ -56,6 +56,7 @@ EXPORTS_mozilla/gfx = \
BaseMargin.h \
BaseRect.h \
BaseSize.h \
Blur.h \
PathHelpers.h \
Point.h \
Matrix.h \
@ -68,6 +69,7 @@ CPPSRCS = \
Matrix.cpp \
DrawTargetCairo.cpp \
SourceSurfaceCairo.cpp \
Blur.cpp \
$(NULL)

Просмотреть файл

@ -45,26 +45,21 @@
namespace mozilla {
namespace gfx {
struct Point :
public BasePoint<Float, Point> {
typedef BasePoint<Float, Point> Super;
Point() : Super() {}
Point(Float aX, Float aY) : Super(aX, aY) {}
};
struct IntPoint :
public BasePoint<int32_t, Point> {
typedef BasePoint<int32_t, Point> Super;
public BasePoint<int32_t, IntPoint> {
typedef BasePoint<int32_t, IntPoint> Super;
IntPoint() : Super() {}
IntPoint(int32_t aX, int32_t aY) : Super(aX, aY) {}
};
struct Size :
public BaseSize<Float, Size> {
typedef BaseSize<Float, Size> Super;
struct Point :
public BasePoint<Float, Point> {
typedef BasePoint<Float, Point> Super;
Size() : Super() {}
Size(Float aWidth, Float aHeight) : Super(aWidth, aHeight) {}
Point() : Super() {}
Point(Float aX, Float aY) : Super(aX, aY) {}
Point(const IntPoint& point) : Super(point.x, point.y) {}
};
struct IntSize :
@ -75,6 +70,15 @@ struct IntSize :
IntSize(int32_t aWidth, int32_t aHeight) : Super(aWidth, aHeight) {}
};
struct Size :
public BaseSize<Float, Size> {
typedef BaseSize<Float, Size> Super;
Size() : Super() {}
Size(Float aWidth, Float aHeight) : Super(aWidth, aHeight) {}
explicit Size(const IntSize& size) : Super(size.width, size.height) {}
};
}
}

Просмотреть файл

@ -55,17 +55,6 @@ struct Margin :
: Super(aLeft, aTop, aRight, aBottom) {}
};
struct Rect :
public BaseRect<Float, Rect, Point, Size, Margin> {
typedef BaseRect<Float, Rect, Point, mozilla::gfx::Size, Margin> Super;
Rect() : Super() {}
Rect(Point aPos, mozilla::gfx::Size aSize) :
Super(aPos, aSize) {}
Rect(Float _x, Float _y, Float _width, Float _height) :
Super(_x, _y, _width, _height) {}
};
struct IntRect :
public BaseRect<int32_t, IntRect, IntPoint, IntSize, Margin> {
typedef BaseRect<int32_t, IntRect, IntPoint, mozilla::gfx::IntSize, Margin> Super;
@ -75,6 +64,24 @@ struct IntRect :
Super(aPos, aSize) {}
IntRect(int32_t _x, int32_t _y, int32_t _width, int32_t _height) :
Super(_x, _y, _width, _height) {}
// Rounding isn't meaningful on an integer rectangle.
void Round() {}
void RoundIn() {}
void RoundOut() {}
};
struct Rect :
public BaseRect<Float, Rect, Point, Size, Margin> {
typedef BaseRect<Float, Rect, Point, mozilla::gfx::Size, Margin> Super;
Rect() : Super() {}
Rect(Point aPos, mozilla::gfx::Size aSize) :
Super(aPos, aSize) {}
Rect(Float _x, Float _y, Float _width, Float _height) :
Super(_x, _y, _width, _height) {}
explicit Rect(const IntRect& rect) :
Super(rect.x, rect.y, rect.width, rect.height) {}
};
}

Просмотреть файл

@ -145,8 +145,9 @@ void
BasicPlanarYCbCrImage::SetData(const Data& aData)
{
// Do some sanity checks to prevent integer overflow
if (aData.mYSize.width > 16384 || aData.mYSize.height > 16384) {
NS_ERROR("Illegal width or height");
if (aData.mYSize.width > PlanarYCbCrImage::MAX_DIMENSION ||
aData.mYSize.height > PlanarYCbCrImage::MAX_DIMENSION) {
NS_ERROR("Illegal image source width or height");
return;
}
@ -159,6 +160,11 @@ BasicPlanarYCbCrImage::SetData(const Data& aData)
gfxIntSize size(mScaleHint);
gfxUtils::GetYCbCrToRGBDestFormatAndSize(aData, format, size);
if (size.width > PlanarYCbCrImage::MAX_DIMENSION ||
size.height > PlanarYCbCrImage::MAX_DIMENSION) {
NS_ERROR("Illegal image dest width or height");
return;
}
mStride = gfxASurface::FormatStrideForWidth(format, size.width);
mBuffer = AllocateBuffer(size.height * mStride);

Просмотреть файл

@ -48,8 +48,8 @@ BlendState ComponentAlphaBlend
SrcBlend = One;
DestBlend = Inv_Src1_Color;
BlendOp = Add;
SrcBlendAlpha = Src1_Alpha;
DestBlendAlpha = Inv_Src1_Alpha;
SrcBlendAlpha = One;
DestBlendAlpha = Inv_Src_Alpha;
BlendOpAlpha = Add;
RenderTargetWriteMask[0] = 0x0F; // All
};
@ -172,7 +172,7 @@ PS_OUTPUT ComponentAlphaShader(const VS_OUTPUT aVertex) : SV_Target
result.vSrc = tRGB.Sample(LayerTextureSamplerLinear, aVertex.vTexCoords);
result.vAlpha = 1.0 - tRGBWhite.Sample(LayerTextureSamplerLinear, aVertex.vTexCoords) + result.vSrc;
result.vAlpha.a = result.vAlpha.g;
result.vSrc.a = result.vAlpha.g;
result.vSrc *= fLayerOpacity;
result.vAlpha *= fLayerOpacity;
return result;

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -37,14 +37,12 @@
#include "gfxBlur.h"
#include "nsMathUtils.h"
#include "nsTArray.h"
#include "mozilla/gfx/Blur.h"
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif
using namespace mozilla::gfx;
gfxAlphaBoxBlur::gfxAlphaBoxBlur()
: mBlur(nsnull)
{
}
@ -59,418 +57,63 @@ gfxAlphaBoxBlur::Init(const gfxRect& aRect,
const gfxRect* aDirtyRect,
const gfxRect* aSkipRect)
{
mSpreadRadius = aSpreadRadius;
mBlurRadius = aBlurRadius;
gfxRect rect(aRect);
rect.Inflate(aBlurRadius + aSpreadRadius);
rect.RoundOut();
Rect rect(aRect.x, aRect.y, aRect.width, aRect.height);
IntSize spreadRadius(aSpreadRadius.width, aSpreadRadius.height);
IntSize blurRadius(aBlurRadius.width, aBlurRadius.height);
nsAutoPtr<Rect> dirtyRect;
if (aDirtyRect) {
// If we get passed a dirty rect from layout, we can minimize the
// shadow size and make painting faster.
mHasDirtyRect = true;
mDirtyRect = *aDirtyRect;
gfxRect requiredBlurArea = mDirtyRect.Intersect(rect);
requiredBlurArea.Inflate(aBlurRadius + aSpreadRadius);
rect = requiredBlurArea.Intersect(rect);
} else {
mHasDirtyRect = false;
dirtyRect = new Rect(aDirtyRect->x, aDirtyRect->y, aDirtyRect->width, aDirtyRect->height);
}
// Check rect empty after accounting for aDirtyRect, since that may have
// make the rectangle empty. BoxBlurVertical and BoxBlurHorizontal require
// that we have a nonzero number of rows and columns.
if (rect.IsEmpty())
return nsnull;
nsAutoPtr<Rect> skipRect;
if (aSkipRect) {
// If we get passed a skip rect, we can lower the amount of
// blurring/spreading we need to do. We convert it to nsIntRect to avoid
// expensive int<->float conversions if we were to use gfxRect instead.
gfxRect skipRect = *aSkipRect;
skipRect.RoundIn();
skipRect.Deflate(aBlurRadius + aSpreadRadius);
gfxUtils::GfxRectToIntRect(skipRect, &mSkipRect);
nsIntRect shadowIntRect;
gfxUtils::GfxRectToIntRect(rect, &shadowIntRect);
mSkipRect.IntersectRect(mSkipRect, shadowIntRect);
if (mSkipRect.IsEqualInterior(shadowIntRect))
return nsnull;
mSkipRect -= shadowIntRect.TopLeft();
} else {
mSkipRect = nsIntRect(0, 0, 0, 0);
skipRect = new Rect(aSkipRect->x, aSkipRect->y, aSkipRect->width, aSkipRect->height);
}
mBlur = new AlphaBoxBlur(rect, spreadRadius, blurRadius, dirtyRect, skipRect);
unsigned char* data = mBlur->GetData();
if (!data)
return nsnull;
IntSize size = mBlur->GetSize();
// Make an alpha-only surface to draw on. We will play with the data after
// everything is drawn to create a blur effect.
mImageSurface = new gfxImageSurface(gfxIntSize(static_cast<PRInt32>(rect.Width()), static_cast<PRInt32>(rect.Height())),
mImageSurface = new gfxImageSurface(data, gfxIntSize(size.width, size.height),
mBlur->GetStride(),
gfxASurface::ImageFormatA8);
if (!mImageSurface || mImageSurface->CairoStatus())
if (mImageSurface->CairoStatus())
return nsnull;
IntRect irect = mBlur->GetRect();
gfxPoint topleft(irect.TopLeft().x, irect.TopLeft().y);
// Use a device offset so callers don't need to worry about translating
// coordinates, they can draw as if this was part of the destination context
// at the coordinates of rect.
mImageSurface->SetDeviceOffset(-rect.TopLeft());
mImageSurface->SetDeviceOffset(-topleft);
mContext = new gfxContext(mImageSurface);
return mContext;
}
/**
* Box blur involves looking at one pixel, and setting its value to the average
* of its neighbouring pixels.
* @param aInput The input buffer.
* @param aOutput The output buffer.
* @param aLeftLobe The number of pixels to blend on the left.
* @param aRightLobe The number of pixels to blend on the right.
* @param aWidth The number of columns in the buffers.
* @param aRows The number of rows in the buffers.
* @param aSkipRect An area to skip blurring in.
* XXX shouldn't we pass stride in separately here?
*/
static void
BoxBlurHorizontal(unsigned char* aInput,
unsigned char* aOutput,
PRInt32 aLeftLobe,
PRInt32 aRightLobe,
PRInt32 aWidth,
PRInt32 aRows,
const nsIntRect& aSkipRect)
{
NS_ASSERTION(aWidth > 0, "Can't handle zero width here");
PRInt32 boxSize = aLeftLobe + aRightLobe + 1;
bool skipRectCoversWholeRow = 0 >= aSkipRect.x &&
aWidth <= aSkipRect.XMost();
if (boxSize == 1) {
memcpy(aOutput, aInput, aWidth*aRows);
return;
}
PRUint32 reciprocal = (PRUint64(1) << 32)/boxSize;
for (PRInt32 y = 0; y < aRows; y++) {
// Check whether the skip rect intersects this row. If the skip
// rect covers the whole surface in this row, we can avoid
// this row entirely (and any others along the skip rect).
bool inSkipRectY = y >= aSkipRect.y &&
y < aSkipRect.YMost();
if (inSkipRectY && skipRectCoversWholeRow) {
y = aSkipRect.YMost() - 1;
continue;
}
PRUint32 alphaSum = 0;
for (PRInt32 i = 0; i < boxSize; i++) {
PRInt32 pos = i - aLeftLobe;
// See assertion above; if aWidth is zero, then we would have no
// valid position to clamp to.
pos = NS_MAX(pos, 0);
pos = NS_MIN(pos, aWidth - 1);
alphaSum += aInput[aWidth * y + pos];
}
for (PRInt32 x = 0; x < aWidth; x++) {
// Check whether we are within the skip rect. If so, go
// to the next point outside the skip rect.
if (inSkipRectY && x >= aSkipRect.x &&
x < aSkipRect.XMost()) {
x = aSkipRect.XMost();
if (x >= aWidth)
break;
// Recalculate the neighbouring alpha values for
// our new point on the surface.
alphaSum = 0;
for (PRInt32 i = 0; i < boxSize; i++) {
PRInt32 pos = x + i - aLeftLobe;
// See assertion above; if aWidth is zero, then we would have no
// valid position to clamp to.
pos = NS_MAX(pos, 0);
pos = NS_MIN(pos, aWidth - 1);
alphaSum += aInput[aWidth * y + pos];
}
}
PRInt32 tmp = x - aLeftLobe;
PRInt32 last = NS_MAX(tmp, 0);
PRInt32 next = NS_MIN(tmp + boxSize, aWidth - 1);
aOutput[aWidth * y + x] = (PRUint64(alphaSum)*reciprocal) >> 32;
alphaSum += aInput[aWidth * y + next] -
aInput[aWidth * y + last];
}
}
}
/**
* Identical to BoxBlurHorizontal, except it blurs top and bottom instead of
* left and right.
* XXX shouldn't we pass stride in separately here?
*/
static void
BoxBlurVertical(unsigned char* aInput,
unsigned char* aOutput,
PRInt32 aTopLobe,
PRInt32 aBottomLobe,
PRInt32 aWidth,
PRInt32 aRows,
const nsIntRect& aSkipRect)
{
NS_ASSERTION(aRows > 0, "Can't handle zero rows here");
PRInt32 boxSize = aTopLobe + aBottomLobe + 1;
bool skipRectCoversWholeColumn = 0 >= aSkipRect.y &&
aRows <= aSkipRect.YMost();
if (boxSize == 1) {
memcpy(aOutput, aInput, aWidth*aRows);
return;
}
PRUint32 reciprocal = (PRUint64(1) << 32)/boxSize;
for (PRInt32 x = 0; x < aWidth; x++) {
bool inSkipRectX = x >= aSkipRect.x &&
x < aSkipRect.XMost();
if (inSkipRectX && skipRectCoversWholeColumn) {
x = aSkipRect.XMost() - 1;
continue;
}
PRUint32 alphaSum = 0;
for (PRInt32 i = 0; i < boxSize; i++) {
PRInt32 pos = i - aTopLobe;
// See assertion above; if aRows is zero, then we would have no
// valid position to clamp to.
pos = NS_MAX(pos, 0);
pos = NS_MIN(pos, aRows - 1);
alphaSum += aInput[aWidth * pos + x];
}
for (PRInt32 y = 0; y < aRows; y++) {
if (inSkipRectX && y >= aSkipRect.y &&
y < aSkipRect.YMost()) {
y = aSkipRect.YMost();
if (y >= aRows)
break;
alphaSum = 0;
for (PRInt32 i = 0; i < boxSize; i++) {
PRInt32 pos = y + i - aTopLobe;
// See assertion above; if aRows is zero, then we would have no
// valid position to clamp to.
pos = NS_MAX(pos, 0);
pos = NS_MIN(pos, aRows - 1);
alphaSum += aInput[aWidth * pos + x];
}
}
PRInt32 tmp = y - aTopLobe;
PRInt32 last = NS_MAX(tmp, 0);
PRInt32 next = NS_MIN(tmp + boxSize, aRows - 1);
aOutput[aWidth * y + x] = (PRUint64(alphaSum)*reciprocal) >> 32;
alphaSum += aInput[aWidth * next + x] -
aInput[aWidth * last + x];
}
}
}
static void ComputeLobes(PRInt32 aRadius, PRInt32 aLobes[3][2])
{
PRInt32 major, minor, final;
/* See http://www.w3.org/TR/SVG/filters.html#feGaussianBlur for
* some notes about approximating the Gaussian blur with box-blurs.
* The comments below are in the terminology of that page.
*/
PRInt32 z = aRadius/3;
switch (aRadius % 3) {
case 0:
// aRadius = z*3; choose d = 2*z + 1
major = minor = final = z;
break;
case 1:
// aRadius = z*3 + 1
// This is a tricky case since there is no value of d which will
// yield a radius of exactly aRadius. If d is odd, i.e. d=2*k + 1
// for some integer k, then the radius will be 3*k. If d is even,
// i.e. d=2*k, then the radius will be 3*k - 1.
// So we have to choose values that don't match the standard
// algorithm.
major = z + 1;
minor = final = z;
break;
case 2:
// aRadius = z*3 + 2; choose d = 2*z + 2
major = final = z + 1;
minor = z;
break;
default:
NS_ERROR("Mathematical impossibility.");
major = minor = final = 0;
}
NS_ASSERTION(major + minor + final == aRadius,
"Lobes don't sum to the right length");
aLobes[0][0] = major;
aLobes[0][1] = minor;
aLobes[1][0] = minor;
aLobes[1][1] = major;
aLobes[2][0] = final;
aLobes[2][1] = final;
}
static void
SpreadHorizontal(unsigned char* aInput,
unsigned char* aOutput,
PRInt32 aRadius,
PRInt32 aWidth,
PRInt32 aRows,
PRInt32 aStride,
const nsIntRect& aSkipRect)
{
if (aRadius == 0) {
memcpy(aOutput, aInput, aStride*aRows);
return;
}
bool skipRectCoversWholeRow = 0 >= aSkipRect.x &&
aWidth <= aSkipRect.XMost();
for (PRInt32 y = 0; y < aRows; y++) {
// Check whether the skip rect intersects this row. If the skip
// rect covers the whole surface in this row, we can avoid
// this row entirely (and any others along the skip rect).
bool inSkipRectY = y >= aSkipRect.y &&
y < aSkipRect.YMost();
if (inSkipRectY && skipRectCoversWholeRow) {
y = aSkipRect.YMost() - 1;
continue;
}
for (PRInt32 x = 0; x < aWidth; x++) {
// Check whether we are within the skip rect. If so, go
// to the next point outside the skip rect.
if (inSkipRectY && x >= aSkipRect.x &&
x < aSkipRect.XMost()) {
x = aSkipRect.XMost();
if (x >= aWidth)
break;
}
PRInt32 sMin = NS_MAX(x - aRadius, 0);
PRInt32 sMax = NS_MIN(x + aRadius, aWidth - 1);
PRInt32 v = 0;
for (PRInt32 s = sMin; s <= sMax; ++s) {
v = NS_MAX<PRInt32>(v, aInput[aStride * y + s]);
}
aOutput[aStride * y + x] = v;
}
}
}
static void
SpreadVertical(unsigned char* aInput,
unsigned char* aOutput,
PRInt32 aRadius,
PRInt32 aWidth,
PRInt32 aRows,
PRInt32 aStride,
const nsIntRect& aSkipRect)
{
if (aRadius == 0) {
memcpy(aOutput, aInput, aStride*aRows);
return;
}
bool skipRectCoversWholeColumn = 0 >= aSkipRect.y &&
aRows <= aSkipRect.YMost();
for (PRInt32 x = 0; x < aWidth; x++) {
bool inSkipRectX = x >= aSkipRect.x &&
x < aSkipRect.XMost();
if (inSkipRectX && skipRectCoversWholeColumn) {
x = aSkipRect.XMost() - 1;
continue;
}
for (PRInt32 y = 0; y < aRows; y++) {
// Check whether we are within the skip rect. If so, go
// to the next point outside the skip rect.
if (inSkipRectX && y >= aSkipRect.y &&
y < aSkipRect.YMost()) {
y = aSkipRect.YMost();
if (y >= aRows)
break;
}
PRInt32 sMin = NS_MAX(y - aRadius, 0);
PRInt32 sMax = NS_MIN(y + aRadius, aRows - 1);
PRInt32 v = 0;
for (PRInt32 s = sMin; s <= sMax; ++s) {
v = NS_MAX<PRInt32>(v, aInput[aStride * s + x]);
}
aOutput[aStride * y + x] = v;
}
}
}
void
gfxAlphaBoxBlur::Paint(gfxContext* aDestinationCtx, const gfxPoint& offset)
{
if (!mContext)
return;
unsigned char* boxData = mImageSurface->Data();
mBlur->Blur();
// no need to do all this if not blurring or spreading
if (mBlurRadius != gfxIntSize(0,0) || mSpreadRadius != gfxIntSize(0,0)) {
nsTArray<unsigned char> tempAlphaDataBuf;
PRSize szB = mImageSurface->GetDataSize();
if (!tempAlphaDataBuf.SetLength(szB))
return; // OOM
unsigned char* tmpData = tempAlphaDataBuf.Elements();
// .SetLength above doesn't initialise the new elements since
// they are unsigned chars and so have no default constructor.
// So we have to initialise them by hand.
memset(tmpData, 0, szB);
PRInt32 stride = mImageSurface->Stride();
PRInt32 rows = mImageSurface->Height();
PRInt32 width = mImageSurface->Width();
if (mSpreadRadius.width > 0 || mSpreadRadius.height > 0) {
SpreadHorizontal(boxData, tmpData, mSpreadRadius.width, width, rows, stride, mSkipRect);
SpreadVertical(tmpData, boxData, mSpreadRadius.height, width, rows, stride, mSkipRect);
}
if (mBlurRadius.width > 0) {
PRInt32 lobes[3][2];
ComputeLobes(mBlurRadius.width, lobes);
BoxBlurHorizontal(boxData, tmpData, lobes[0][0], lobes[0][1], stride, rows, mSkipRect);
BoxBlurHorizontal(tmpData, boxData, lobes[1][0], lobes[1][1], stride, rows, mSkipRect);
BoxBlurHorizontal(boxData, tmpData, lobes[2][0], lobes[2][1], stride, rows, mSkipRect);
} else {
memcpy(tmpData, boxData, stride*rows);
}
if (mBlurRadius.height > 0) {
PRInt32 lobes[3][2];
ComputeLobes(mBlurRadius.height, lobes);
BoxBlurVertical(tmpData, boxData, lobes[0][0], lobes[0][1], stride, rows, mSkipRect);
BoxBlurVertical(boxData, tmpData, lobes[1][0], lobes[1][1], stride, rows, mSkipRect);
BoxBlurVertical(tmpData, boxData, lobes[2][0], lobes[2][1], stride, rows, mSkipRect);
} else {
memcpy(boxData, tmpData, stride*rows);
}
}
Rect* dirtyrect = mBlur->GetDirtyRect();
// Avoid a semi-expensive clip operation if we can, otherwise
// clip to the dirty rect
if (mHasDirtyRect) {
if (dirtyrect) {
aDestinationCtx->Save();
aDestinationCtx->NewPath();
aDestinationCtx->Rectangle(mDirtyRect);
gfxRect dirty(dirtyrect->x, dirtyrect->y, dirtyrect->width, dirtyrect->height);
aDestinationCtx->Rectangle(dirty);
aDestinationCtx->Clip();
aDestinationCtx->Mask(mImageSurface, offset);
aDestinationCtx->Restore();
@ -479,23 +122,9 @@ gfxAlphaBoxBlur::Paint(gfxContext* aDestinationCtx, const gfxPoint& offset)
}
}
/**
* Compute the box blur size (which we're calling the blur radius) from
* the standard deviation.
*
* Much of this, the 3 * sqrt(2 * pi) / 4, is the known value for
* approximating a Gaussian using box blurs. This yields quite a good
* approximation for a Gaussian. Then we multiply this by 1.5 since our
* code wants the radius of the entire triple-box-blur kernel instead of
* the diameter of an individual box blur. For more details, see:
* http://www.w3.org/TR/SVG11/filters.html#feGaussianBlurElement
* https://bugzilla.mozilla.org/show_bug.cgi?id=590039#c19
*/
static const gfxFloat GAUSSIAN_SCALE_FACTOR = (3 * sqrt(2 * M_PI) / 4) * 1.5;
gfxIntSize gfxAlphaBoxBlur::CalculateBlurRadius(const gfxPoint& aStd)
{
return gfxIntSize(
static_cast<PRInt32>(floor(aStd.x * GAUSSIAN_SCALE_FACTOR + 0.5)),
static_cast<PRInt32>(floor(aStd.y * GAUSSIAN_SCALE_FACTOR + 0.5)));
Point std(aStd.x, aStd.y);
IntSize size = AlphaBoxBlur::CalculateBlurRadius(std);
return gfxIntSize(size.width, size.height);
}

Просмотреть файл

@ -42,7 +42,12 @@
#include "gfxImageSurface.h"
#include "gfxTypes.h"
#include "gfxUtils.h"
#include "nsRect.h"
namespace mozilla {
namespace gfx {
class AlphaBoxBlur;
}
}
/**
* Implementation of a triple box blur approximation of a Gaussian blur.
@ -122,15 +127,6 @@ public:
static gfxIntSize CalculateBlurRadius(const gfxPoint& aStandardDeviation);
protected:
/**
* The spread radius, in pixels.
*/
gfxIntSize mSpreadRadius;
/**
* The blur radius, in pixels.
*/
gfxIntSize mBlurRadius;
/**
* The context of the temporary alpha surface.
*/
@ -141,18 +137,10 @@ protected:
*/
nsRefPtr<gfxImageSurface> mImageSurface;
/**
* A copy of the dirty rect passed to Init(). This will only be valid if
* mHasDirtyRect is TRUE.
*/
gfxRect mDirtyRect;
/**
* A rect indicating the area where blurring is unnecessary, and the blur
* algorithm should skip over it.
*/
nsIntRect mSkipRect;
bool mHasDirtyRect;
/**
* The object that actually does the blurring for us.
*/
nsAutoPtr<mozilla::gfx::AlphaBoxBlur> mBlur;
};
#endif /* GFX_BLUR_H */

Просмотреть файл

@ -55,52 +55,6 @@ gfxRect::WithinEpsilonOfIntegerPixels(gfxFloat aEpsilon) const
WithinEpsilonOfInteger(height, aEpsilon));
}
void
gfxRect::Round()
{
// Note that don't use NS_round here. See the comment for this method in gfxRect.h
gfxFloat x0 = floor(X() + 0.5);
gfxFloat y0 = floor(Y() + 0.5);
gfxFloat x1 = floor(XMost() + 0.5);
gfxFloat y1 = floor(YMost() + 0.5);
x = x0;
y = y0;
width = x1 - x0;
height = y1 - y0;
}
void
gfxRect::RoundIn()
{
gfxFloat x0 = ceil(X());
gfxFloat y0 = ceil(Y());
gfxFloat x1 = floor(XMost());
gfxFloat y1 = floor(YMost());
x = x0;
y = y0;
width = x1 - x0;
height = y1 - y0;
}
void
gfxRect::RoundOut()
{
gfxFloat x0 = floor(X());
gfxFloat y0 = floor(Y());
gfxFloat x1 = ceil(XMost());
gfxFloat y1 = ceil(YMost());
x = x0;
y = y0;
width = x1 - x0;
height = y1 - y0;
}
/* Clamp r to CAIRO_COORD_MIN .. CAIRO_COORD_MAX
* these are to be device coordinates.
*

Просмотреть файл

@ -107,27 +107,6 @@ struct THEBES_API gfxRect :
*/
bool WithinEpsilonOfIntegerPixels(gfxFloat aEpsilon) const;
// Round the rectangle edges to integer coordinates, such that the rounded
// rectangle has the same set of pixel centers as the original rectangle.
// Edges at offset 0.5 round up.
// Suitable for most places where integral device coordinates
// are needed, but note that any translation should be applied first to
// avoid pixel rounding errors.
// Note that this is *not* rounding to nearest integer if the values are negative.
// They are always rounding as floor(n + 0.5).
// See https://bugzilla.mozilla.org/show_bug.cgi?id=410748#c14
// If you need similar method which is using NS_round(), you should create
// new |RoundAwayFromZero()| method.
void Round();
// Snap the rectangle edges to integer coordinates, such that the
// original rectangle contains the resulting rectangle.
void RoundIn();
// Snap the rectangle edges to integer coordinates, such that the
// resulting rectangle contains the original rectangle.
void RoundOut();
gfxPoint AtCorner(mozilla::css::Corner corner) const {
switch (corner) {
case NS_CORNER_TOP_LEFT: return TopLeft();

Просмотреть файл

@ -441,15 +441,12 @@ nsBMPEncoder::ConvertHostARGBRow(const PRUint8* aSrc, PRUint8* aDest,
PRUint8 *pixelOut = &aDest[x * BytesPerPixel(mBMPInfoHeader.bpp)];
PRUint8 alpha = (pixelIn & 0xff000000) >> 24;
if (alpha == 0) {
pixelOut[0] = pixelOut[1] = pixelOut[2] = 0;
} else {
pixelOut[0] = (((pixelIn & 0xff0000) >> 16) * 255 + alpha / 2) / alpha;
pixelOut[1] = (((pixelIn & 0x00ff00) >> 8) * 255 + alpha / 2) / alpha;
pixelOut[2] = (((pixelIn & 0x0000ff) >> 0) * 255 + alpha / 2) / alpha;
if(mBMPInfoHeader.bpp == 32) {
pixelOut[3] = alpha;
}
pixelOut[0] = (((pixelIn & 0xff0000) >> 16));
pixelOut[1] = (((pixelIn & 0x00ff00) >> 8));
pixelOut[2] = (((pixelIn & 0x0000ff) >> 0));
if (mBMPInfoHeader.bpp == 32) {
pixelOut[3] = alpha;
}
}
}

Просмотреть файл

@ -365,14 +365,9 @@ nsJPEGEncoder::ConvertHostARGBRow(const PRUint8* aSrc, PRUint8* aDest,
const PRUint32& pixelIn = ((const PRUint32*)(aSrc))[x];
PRUint8 *pixelOut = &aDest[x * 3];
PRUint8 alpha = (pixelIn & 0xff000000) >> 24;
if (alpha == 0) {
pixelOut[0] = pixelOut[1] = pixelOut[2] = 0;
} else {
pixelOut[0] = (((pixelIn & 0xff0000) >> 16) * 255 + alpha / 2) / alpha;
pixelOut[1] = (((pixelIn & 0x00ff00) >> 8) * 255 + alpha / 2) / alpha;
pixelOut[2] = (((pixelIn & 0x0000ff) >> 0) * 255 + alpha / 2) / alpha;
}
pixelOut[0] = (((pixelIn & 0xff0000) >> 16));
pixelOut[1] = (((pixelIn & 0x00ff00) >> 8));
pixelOut[2] = (((pixelIn & 0x0000ff) >> 0));
}
}

Просмотреть файл

@ -36,10 +36,16 @@ function failTest ()
}
ok(false, "timing out after " + currentTest.timeout + "ms. "
+ "Animated image still doesn't look correct, " + "after call #"
+ currentTest.onStopFrameCounter + " to onStopFrame");
+ "Animated image still doesn't look correct, after poll #"
+ currentTest.pollCounter);
currentTest.wereFailures = true;
if (currentTest.currentSnapshotDataURI) {
currentTest.outputDebugInfo("Snapshot #" + currentTest.pollCounter,
"snapNum" + currentTest.pollCounter,
currentTest.currentSnapshotDataURI);
}
currentTest.enableDisplay(document.getElementById(currentTest.debugElementId));
currentTest.cleanUpAndFinish();
@ -96,7 +102,7 @@ function AnimationTest(pollFreq, timeout, referenceElementId, imageElementId,
this.srcAttr = srcAttr;
this.debugElementId = debugElementId;
this.referenceSnapshot = ""; // value will be set in takeReferenceSnapshot()
this.onStopFrameCounter = 0;
this.pollCounter = 0;
this.isTestFinished = false;
this.numRefsTaken = 0;
this.blankWaitTime = 0;
@ -124,6 +130,7 @@ AnimationTest.prototype.outputDebugInfo = function(message, id, dataUri)
debugElement.appendChild(newDataUriElement);
var brElement = document.createElement("br");
debugElement.appendChild(brElement);
todo(false, "Debug (" + id + "): " + message + " " + dataUri);
};
AnimationTest.prototype.isFinished = function()
@ -199,14 +206,12 @@ AnimationTest.prototype.setupPolledImage = function ()
var currentSnapshot = snapshotWindow(window, false);
var result = compareSnapshots(currentSnapshot, this.referenceSnapshot, true);
var dataString = "Snapshot #" + this.onStopFrameCounter;
this.outputDebugInfo(dataString, 'snap' + this.onStopFrameCounter,
currentSnapshot.toDataURL());
this.currentSnapshotDataURI = currentSnapshot.toDataURL();
if (result[0]) {
// SUCCESS!
ok(true, "Animated image looks correct, " + "at call #"
+ this.onStopFrameCounter + " to onStopFrame");
ok(true, "Animated image looks correct, at poll #"
+ this.pollCounter);
this.cleanUpAndFinish();
}
@ -226,7 +231,7 @@ AnimationTest.prototype.checkImage = function ()
return;
}
this.onStopFrameCounter++;
this.pollCounter++;
// We need this for some tests, because we need to force the
// test image to be visible.
@ -237,14 +242,12 @@ AnimationTest.prototype.checkImage = function ()
var currentSnapshot = snapshotWindow(window, false);
var result = compareSnapshots(currentSnapshot, this.referenceSnapshot, true);
var dataString = "Snapshot #" + this.onStopFrameCounter;
this.outputDebugInfo(dataString, 'snap' + this.onStopFrameCounter,
currentSnapshot.toDataURL());
this.currentSnapshotDataURI = currentSnapshot.toDataURL();
if (result[0]) {
// SUCCESS!
ok(true, "Animated image looks correct, " + "at call #"
+ this.onStopFrameCounter + " to onStopFrame");
ok(true, "Animated image looks correct, at poll #"
+ this.pollCounter);
this.cleanUpAndFinish();
}

Двоичные данные
image/test/unit/image1png16x16.jpg

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 1.1 KiB

После

Ширина:  |  Высота:  |  Размер: 1.1 KiB

Двоичные данные
image/test/unit/image1png64x64.jpg

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 4.4 KiB

После

Ширина:  |  Высота:  |  Размер: 4.4 KiB

Просмотреть файл

@ -171,7 +171,7 @@ var encodedBytes = streamToArray(istream);
var refName = "image1png16x16.jpg";
var refFile = do_get_file(refName);
istream = getFileInputStream(refFile);
do_check_eq(istream.available(), 1081);
do_check_eq(istream.available(), 1078);
var referenceBytes = streamToArray(istream);
// compare the encoder's output to the reference file.
@ -190,7 +190,7 @@ encodedBytes = streamToArray(istream);
refName = "image1png64x64.jpg";
refFile = do_get_file(refName);
istream = getFileInputStream(refFile);
do_check_eq(istream.available(), 4493);
do_check_eq(istream.available(), 4503);
referenceBytes = streamToArray(istream);
// compare the encoder's output to the reference file.

Просмотреть файл

@ -6930,12 +6930,20 @@ Parser::primaryExpr(TokenKind tt, JSBool afterDot)
#if JS_HAS_XML_SUPPORT
case TOK_STAR:
if (tc->inStrictMode()) {
reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_SYNTAX_ERROR);
return NULL;
}
pn = qualifiedIdentifier();
if (!pn)
return NULL;
break;
case TOK_AT:
if (tc->inStrictMode()) {
reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_SYNTAX_ERROR);
return NULL;
}
pn = attributeIdentifier();
if (!pn)
return NULL;

Просмотреть файл

@ -0,0 +1,17 @@
/*
* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/licenses/publicdomain/
*/
function checkSyntaxError(code) {
var error;
try {
eval(code);
} catch (e) {
error = e;
}
assertEq(error.name, 'SyntaxError');
}
checkSyntaxError('"use strict"; *');
checkSyntaxError('"use strict"; @7');

Просмотреть файл

@ -1400,7 +1400,16 @@ JSObject::makeDenseArraySlow(JSContext *cx)
if (slots[i].isMagic(JS_ARRAY_HOLE))
continue;
setSlot(next, slots[i]);
/*
* No barrier is needed here because the set of reachable objects before
* and after slowification is the same. During slowification, the
* autoArray rooter guarantees that all slots will be marked.
*
* It's important that we avoid a barrier here because the fixed slots
* of a dense array can be garbage; a write barrier after the switch to
* a slow array could cause a crash.
*/
initSlotUnchecked(next, slots[i]);
if (!addDataProperty(cx, id, next, JSPROP_ENUMERATE)) {
setMap(oldMap);

Просмотреть файл

@ -342,7 +342,8 @@ regexp_finalize(JSContext *cx, JSObject *obj)
static void
regexp_trace(JSTracer *trc, JSObject *obj)
{
obj->asRegExp()->purge(trc->context);
if (IS_GC_MARKING_TRACER(trc))
obj->asRegExp()->purge(trc->context);
}
Class js::RegExpClass = {

Просмотреть файл

@ -4547,7 +4547,8 @@ nsCSSFrameConstructor::ResolveStyleContext(nsStyleContext* aParentStyleContext,
nsFrameConstructorState* aState)
{
nsStyleSet *styleSet = mPresShell->StyleSet();
aContent->OwnerDoc()->FlushPendingLinkUpdates();
if (aContent->IsElement()) {
if (aState) {
return styleSet->ResolveStyleFor(aContent->AsElement(),

Просмотреть файл

@ -1111,6 +1111,7 @@ nsFrameManager::ReResolveStyleContext(nsPresContext *aPresContext,
nsIContent* content = localContent ? localContent : aParentContent;
if (content && content->IsElement()) {
content->OwnerDoc()->FlushPendingLinkUpdates();
RestyleTracker::RestyleData restyleData;
if (aRestyleTracker.GetRestyleData(content->AsElement(), &restyleData)) {
if (NS_UpdateHint(aMinChange, restyleData.mChangeHint)) {

Просмотреть файл

@ -6283,13 +6283,13 @@ IsFullScreenAndRestrictedKeyEvent(nsIContent* aTarget, const nsEvent* aEvent)
// Bail out if the event is not a key event, or the target's document is
// not in DOM full screen mode, or full-screen key input is not restricted.
nsIDocument *doc;
nsIDocument *root = nsnull;
if (!aTarget ||
(aEvent->message != NS_KEY_DOWN &&
aEvent->message != NS_KEY_UP &&
aEvent->message != NS_KEY_PRESS) ||
!(doc = aTarget->OwnerDoc()) ||
!doc->IsFullScreenDoc() ||
!(root = nsContentUtils::GetRootDocument(aTarget->OwnerDoc())) ||
!root->IsFullScreenDoc() ||
!nsContentUtils::IsFullScreenKeyInputRestricted()) {
return false;
}
@ -6368,9 +6368,10 @@ PresShell::HandleEventInternal(nsEvent* aEvent, nsIView *aView,
case NS_KEY_UP: {
nsIDocument *doc = mCurrentEventContent ?
mCurrentEventContent->OwnerDoc() : nsnull;
if (doc &&
doc->IsFullScreenDoc() &&
static_cast<const nsKeyEvent*>(aEvent)->keyCode == NS_VK_ESCAPE) {
nsIDocument* root = nsnull;
if (static_cast<const nsKeyEvent*>(aEvent)->keyCode == NS_VK_ESCAPE &&
(root = nsContentUtils::GetRootDocument(doc)) &&
root->IsFullScreenDoc()) {
// Prevent default action on ESC key press when exiting
// DOM full-screen mode. This prevents the browser ESC key
// handler from stopping all loads in the document, which
@ -6382,7 +6383,7 @@ PresShell::HandleEventInternal(nsEvent* aEvent, nsIView *aView,
// ESC key released while in DOM full-screen mode.
// Exit full-screen mode.
NS_DispatchToCurrentThread(
NS_NewRunnableMethod(mCurrentEventContent->OwnerDoc(),
NS_NewRunnableMethod(root,
&nsIDocument::CancelFullScreen));
}
} else if (IsFullScreenAndRestrictedKeyEvent(mCurrentEventContent, aEvent)) {

Просмотреть файл

@ -0,0 +1,37 @@
<!DOCTYPE html>
<!-- This test checks to be sure we can render SVG-as-an-image
from a MozBlobBuilder-generated 'moz-filedata' URI. -->
<html class="reftest-wait">
<head>
<script>
function go() {
// Generate a moz-filedata URL encoding of an SVG document
var filedataURL = generateMozFiledataURL();
// Tell our img element to render the URL
var img = document.getElementsByTagName("img")[0]
img.src = filedataURL;
// Once our img loads, take reftest snapshot.
img.addEventListener("load", function() {
document.documentElement.removeAttribute("class");
});
}
// Helper function -- returns a moz-filedata URL representing a
// 100x100 fully-lime SVG document.
function generateMozFiledataURL() {
var blobBuilder = new self.MozBlobBuilder;
var svg =
'<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100">' +
'<rect height="100%" width="100%" fill="lime"/>' +
'</svg>';
blobBuilder.append(svg);
return self.URL.createObjectURL(blobBuilder.getBlob("image/svg+xml"));
}
</script>
</head>
<body onload="go()">
<img src="">
</body>
</html>

Просмотреть файл

@ -0,0 +1,46 @@
<!DOCTYPE html>
<!-- This test checks to be sure we allow MozBlobBuilder-generated
'moz-filedata' URIs *inside of* SVG-as-an-image. -->
<html class="reftest-wait">
<head>
<script>
function go() {
// Generate a moz-filedata URL encoding of an SVG document
var filedataURL = generateMozFiledataURL();
// Now generate a data URI, containing our moz-filedata URI
var outerSVG =
'<svg xmlns="http://www.w3.org/2000/svg" ' +
'xmlns:xlink="http://www.w3.org/1999/xlink" ' +
'width="100" height="100">' +
'<image height="100" width="100" ' +
'xlink:href="' + filedataURL + '"/>' +
'</svg>';
// Tell our img element to render the URL
var img = document.getElementsByTagName("img")[0]
img.src = "data:image/svg+xml," + outerSVG;
// Once our img loads, take reftest snapshot.
img.addEventListener("load", function() {
document.documentElement.removeAttribute("class");
});
}
// Helper function -- returns a moz-filedata URL representing a
// 100x100 fully-lime SVG document.
function generateMozFiledataURL() {
var blobBuilder = new self.MozBlobBuilder;
var svg =
'<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100">' +
'<rect height="100%" width="100%" fill="lime"/>' +
'</svg>';
blobBuilder.append(svg);
return self.URL.createObjectURL(blobBuilder.getBlob("image/svg+xml"));
}
</script>
</head>
<body onload="go()">
<img src="">
</body>
</html>

Просмотреть файл

@ -55,6 +55,8 @@ fails == canvas-drawImage-slice-1b.html lime100x100-ref.html # XXX all edges fuz
random == img-and-image-1.html img-and-image-1-ref.svg # bug 645267
# More complex <img> tests
== img-blobBuilder-1.html lime100x100-ref.html
== img-blobBuilder-2.html lime100x100-ref.html
== img-content-outside-viewBox-1.html img-content-outside-viewBox-1-ref.html
== img-dyn-1.html img-dyn-1-ref.html
== img-foreignObject-1.html lime100x100-ref.html
@ -120,11 +122,11 @@ random == img-and-image-1.html img-and-image-1-ref.svg # bug 645267
# tests for external resources vs. data URIs in SVG as an image
== svg-image-datauri-1.html lime100x100.svg
HTTP == svg-image-datauri-1.html lime100x100.svg
fails-if(Android) == svg-image-external-1.html lime100x100.svg
== svg-image-external-1.html blue100x100.svg
HTTP == svg-image-external-1.html blue100x100.svg
== svg-stylesheet-datauri-1.html lime100x100.svg
HTTP == svg-stylesheet-datauri-1.html lime100x100.svg
random == svg-stylesheet-external-1.html lime100x100.svg # see bug 629885 comment 9
== svg-stylesheet-external-1.html blue100x100.svg
HTTP == svg-stylesheet-external-1.html blue100x100.svg
# test that :visited status is ignored in image documents

Просмотреть файл

@ -1249,8 +1249,6 @@ nsCSSRuleProcessor::GetWindowsThemeIdentifier()
nsEventStates
nsCSSRuleProcessor::GetContentState(Element* aElement)
{
// FIXME: RequestLinkStateUpdate is a hack; see bug 660959.
aElement->RequestLinkStateUpdate();
nsEventStates state = aElement->State();
// If we are not supposed to mark visited links as such, be sure to
@ -1271,8 +1269,6 @@ nsCSSRuleProcessor::GetContentState(Element* aElement)
bool
nsCSSRuleProcessor::IsLink(Element* aElement)
{
// FIXME: RequestLinkStateUpdate is a hack; see bug 660959.
aElement->RequestLinkStateUpdate();
nsEventStates state = aElement->State();
return state.HasAtLeastOneOfStates(NS_EVENT_STATE_VISITED | NS_EVENT_STATE_UNVISITED);
}

Просмотреть файл

@ -447,6 +447,7 @@ nsComputedDOMStyle::GetPropertyCSSValue(const nsAString& aPropertyName,
nsCOMPtr<nsIDocument> document = do_QueryReferent(mDocumentWeak);
NS_ENSURE_TRUE(document, NS_ERROR_NOT_AVAILABLE);
document->FlushPendingLinkUpdates();
nsCSSProperty prop = nsCSSProps::LookupProperty(aPropertyName);

Просмотреть файл

@ -175,37 +175,6 @@ nsSVGMarkerFrame::PaintMark(nsSVGRenderState *aContext,
return NS_OK;
}
nsRect
nsSVGMarkerFrame::RegionMark(nsSVGPathGeometryFrame *aMarkedFrame,
const nsSVGMark *aMark, float aStrokeWidth)
{
// If the flag is set when we get here, it means this marker frame
// has already been used in calculating the current mark region, and
// the document has a marker reference loop.
if (mInUse)
return nsRect(0,0,0,0);
AutoMarkerReferencer markerRef(this, aMarkedFrame);
mStrokeWidth = aStrokeWidth;
mX = aMark->x;
mY = aMark->y;
mAutoAngle = aMark->angle;
// Force children to update their covered region
for (nsIFrame* kid = mFrames.FirstChild();
kid;
kid = kid->GetNextSibling()) {
nsISVGChildFrame* child = do_QueryFrame(kid);
if (child)
child->UpdateCoveredRegion();
}
// Now get the combined covered region
return nsSVGUtils::GetCoveredRegion(mFrames);
}
gfxRect
nsSVGMarkerFrame::GetMarkBBoxContribution(const gfxMatrix &aToBBoxUserspace,
PRUint32 aFlags,

Просмотреть файл

@ -92,9 +92,6 @@ public:
nsSVGMark *aMark,
float aStrokeWidth);
nsRect RegionMark(nsSVGPathGeometryFrame *aMarkedFrame,
const nsSVGMark *aMark, float aStrokeWidth);
gfxRect GetMarkBBoxContribution(const gfxMatrix &aToBBoxUserspace,
PRUint32 aFlags,
nsSVGPathGeometryFrame *aMarkedFrame,

Просмотреть файл

@ -16,6 +16,7 @@ XUL <resizer> tests
<!-- test code goes here -->
<script type="application/javascript"><![CDATA[
SimpleTest.waitForExplicitFinish();
SimpleTest.ignoreAllUncaughtExceptions();
function openPopup()
{

Просмотреть файл

@ -168,7 +168,7 @@ Tester.prototype = {
"\tTodo: " + todoCount + "\n");
} else {
this.dumper.dump("TEST-UNEXPECTED-FAIL | (browser-test.js) | " +
"No tests to run. Did you pass an invalid --test-path?");
"No tests to run. Did you pass an invalid --test-path?\n");
}
this.dumper.dump("\n*** End BrowserChrome Test Results ***\n");
@ -188,7 +188,7 @@ Tester.prototype = {
if (this.currentTest)
this.currentTest.addResult(new testMessage(msg));
else
this.dumper.dump("TEST-INFO | (browser-test.js) | " + msg);
this.dumper.dump("TEST-INFO | (browser-test.js) | " + msg.replace(/\n$/, "") + "\n");
} catch (ex) {
// Swallow exception so we don't lead to another error being reported,
// throwing us into an infinite loop
@ -471,6 +471,10 @@ function testScope(aTester, aTest) {
self.SimpleTest.expectUncaughtException();
};
this.ignoreAllUncaughtExceptions = function test_ignoreAllUncaughtExceptions() {
self.SimpleTest.ignoreAllUncaughtExceptions();
};
this.finish = function test_finish() {
self.__done = true;
if (self.SimpleTest._expectingUncaughtException) {

Просмотреть файл

@ -15,24 +15,35 @@
**/
var SimpleTest = { };
var parentRunner = null;
if (parent) {
parentRunner = parent.TestRunner;
if (!parentRunner && parent.wrappedJSObject) {
parentRunner = parent.wrappedJSObject.TestRunner;
var isPrimaryTestWindow = !!parent.TestRunner;
// Finds the TestRunner for this test run and the SpecialPowers object (in
// case it is not defined) from a parent/opener window.
//
// Finding the SpecialPowers object is needed when we have ChromePowers in
// harness.xul and we need SpecialPowers in the iframe, and also for tests
// like test_focus.xul where we open a window which opens another window which
// includes SimpleTest.js.
(function() {
function ancestor(w) {
return w.parent != w ? w.parent : w.opener;
}
// This is the case where we have ChromePowers in harness.xul and we need it in the iframe
if (window.SpecialPowers == undefined && parent.SpecialPowers !== undefined) {
window.SpecialPowers = parent.SpecialPowers;
var w = ancestor(window);
while (w && (!parentRunner || !window.SpecialPowers)) {
if (!parentRunner) {
parentRunner = w.TestRunner;
if (!parentRunner && w.wrappedJSObject) {
parentRunner = w.wrappedJSObject.TestRunner;
}
}
if (!window.SpecialPowers) {
window.SpecialPowers = w.SpecialPowers;
}
w = ancestor(w);
}
}
// Workaround test_focus.xul where we open a window which opens another window which includes SimpleTest.js
if (window.SpecialPowers == undefined && window.opener && window.opener.SpecialPowers !== undefined) {
window.SpecialPowers = window.opener.SpecialPowers;
}
})();
/* Helper functions pulled out of various MochiKit modules */
if (typeof(repr) == 'undefined') {
@ -703,12 +714,22 @@ SimpleTest.expectUncaughtException = function () {
SimpleTest._expectingUncaughtException = true;
};
/**
* Indicates to the test framework that all of the uncaught exceptions
* during the test are known problems that should be fixed in the future,
* but which should not cause the test to fail currently.
*/
SimpleTest.ignoreAllUncaughtExceptions = function () {
SimpleTest._ignoringAllUncaughtExceptions = true;
};
addLoadEvent(function() {
if (SimpleTest._stopOnLoad) {
SimpleTest.finish();
}
});
if (isPrimaryTestWindow) {
addLoadEvent(function() {
if (SimpleTest._stopOnLoad) {
SimpleTest.finish();
}
});
}
// --------------- Test.Builder/Test.More isDeeply() -----------------
@ -924,19 +945,18 @@ window.onerror = function simpletestOnerror(errorMsg, url, lineNumber) {
// Log the message.
// XXX Chrome mochitests sometimes trigger this window.onerror handler,
// but there are a number of uncaught JS exceptions from those tests
// currently, so we can't log them as errors just yet. For now, when
// not in a plain mochitest, just dump it so that the error is visible but
// doesn't cause a test failure. See bug 652494.
// but there are a number of uncaught JS exceptions from those tests.
// For now, for tests that self identify as having unintentional uncaught
// exceptions, just dump it so that the error is visible but doesn't cause
// a test failure. See bug 652494.
var message = "An error occurred: " + errorMsg + " at " + url + ":" + lineNumber;
var href = SpecialPowers.getPrivilegedProps(window, 'location.href');
var isPlainMochitest = href.substring(0,7) != "chrome:";
var isExpected = !!SimpleTest._expectingUncaughtException;
if (isPlainMochitest) {
if (!SimpleTest._ignoringAllUncaughtExceptions) {
SimpleTest.ok(isExpected, funcIdentifier, message);
SimpleTest._expectingUncaughtException = false;
} else {
SimpleTest.info(funcIdentifier + " " + message);
SimpleTest.todo(false, funcIdentifier, message);
}
// There is no Components.stack.caller to log. (See bug 511888.)

Просмотреть файл

@ -2,7 +2,7 @@
// CFGrowlAdditions.c
// Growl
//
// Created by Mac-arena the Bored Zo on Wed Jun 18 2004.
// Created by Peter Hosey on Wed Jun 18 2004.
// Copyright 2005-2006 The Growl Project.
//
// This file is under the BSD License, refer to License.txt for details

Просмотреть файл

@ -2,7 +2,7 @@
// CFGrowlAdditions.h
// Growl
//
// Created by Mac-arena the Bored Zo on Wed Jun 18 2004.
// Created by Peter Hosey on Wed Jun 18 2004.
// Copyright 2005-2006 The Growl Project.
//
// This file is under the BSD License, refer to License.txt for details

Просмотреть файл

@ -293,7 +293,7 @@ static BOOL registerWhenGrowlIsReady = NO;
/*if Growl launches, and the user hasn't already said NO to installing
* it, store this notification for posting
*/
if (!userChoseNotToInstallGrowl) {
if (!([self isGrowlInstalled] || userChoseNotToInstallGrowl)) {
if (!queuedGrowlNotifications)
queuedGrowlNotifications = [[NSMutableArray alloc] init];
[queuedGrowlNotifications addObject:userInfo];
@ -448,7 +448,7 @@ static BOOL registerWhenGrowlIsReady = NO;
} else {
[mRegDict removeObjectForKey:GROWL_APP_LOCATION];
}
[myURL release];
[NSMakeCollectable(myURL) release];
}
}
}
@ -549,7 +549,7 @@ static BOOL registerWhenGrowlIsReady = NO;
if (!iconData) {
NSURL *URL = copyCurrentProcessURL();
iconData = [copyIconDataForURL(URL) autorelease];
[URL release];
[NSMakeCollectable(URL) release];
}
return iconData;
@ -724,25 +724,96 @@ static BOOL registerWhenGrowlIsReady = NO;
#pragma mark -
+ (OSStatus) getPSN:(struct ProcessSerialNumber *)outAppPSN forAppWithBundleAtPath:(NSString *)appPath {
OSStatus err;
while ((err = GetNextProcess(outAppPSN)) == noErr) {
NSDictionary *dict = [NSMakeCollectable(ProcessInformationCopyDictionary(outAppPSN, kProcessDictionaryIncludeAllInformationMask)) autorelease];
NSString *bundlePath = [dict objectForKey:@"BundlePath"];
if ([bundlePath isEqualToString:appPath]) {
//Match!
break;
}
}
return err;
}
+ (BOOL) launchApplicationWithBundleAtPath:(NSString *)appPath openDocumentURL:(NSURL *)regItemURL {
const struct LSLaunchURLSpec spec = {
.appURL = (CFURLRef)[NSURL fileURLWithPath:appPath],
.itemURLs = (CFArrayRef)(regItemURL ? [NSArray arrayWithObject:regItemURL] : nil),
.passThruParams = NULL,
.launchFlags = kLSLaunchDontAddToRecents | kLSLaunchDontSwitch | kLSLaunchNoParams | kLSLaunchAsync,
.asyncRefCon = NULL
};
OSStatus err = LSOpenFromURLSpec(&spec, NULL);
if (err != noErr) {
NSLog(@"Could not launch application at path %@ (with document %@) because LSOpenFromURLSpec returned %i (%s)", appPath, regItemURL, err, GetMacOSStatusCommentString(err));
}
return (err == noErr);
}
+ (BOOL) sendOpenEventToProcessWithProcessSerialNumber:(struct ProcessSerialNumber *)appPSN openDocumentURL:(NSURL *)regItemURL {
OSStatus err;
BOOL success = NO;
AEStreamRef stream = AEStreamCreateEvent(kCoreEventClass, kAEOpenDocuments,
//Target application
typeProcessSerialNumber, appPSN, sizeof(*appPSN),
kAutoGenerateReturnID, kAnyTransactionID);
if (!stream) {
NSLog(@"%@: Could not create open-document event to register this application with Growl", [self class]);
} else {
if (regItemURL) {
NSString *regItemURLString = [regItemURL absoluteString];
NSData *regItemURLUTF8Data = [regItemURLString dataUsingEncoding:NSUTF8StringEncoding];
err = AEStreamWriteKeyDesc(stream, keyDirectObject, typeFileURL, [regItemURLUTF8Data bytes], [regItemURLUTF8Data length]);
if (err != noErr) {
NSLog(@"%@: Could not set direct object of open-document event to register this application with Growl because AEStreamWriteKeyDesc returned %li/%s", [self class], (long)err, GetMacOSStatusCommentString(err));
}
}
AppleEvent event;
err = AEStreamClose(stream, &event);
if (err != noErr) {
NSLog(@"%@: Could not finish open-document event to register this application with Growl because AEStreamClose returned %li/%s", [self class], (long)err, GetMacOSStatusCommentString(err));
} else {
err = AESendMessage(&event, /*reply*/ NULL, kAENoReply | kAEDontReconnect | kAENeverInteract | kAEDontRecord, kAEDefaultTimeout);
if (err != noErr) {
NSLog(@"%@: Could not send open-document event to register this application with Growl because AESend returned %li/%s", [self class], (long)err, GetMacOSStatusCommentString(err));
}
AEDisposeDesc(&event);
}
success = (err == noErr);
}
return success;
}
+ (BOOL) _launchGrowlIfInstalledWithRegistrationDictionary:(NSDictionary *)regDict {
BOOL success = NO;
NSBundle *growlPrefPaneBundle;
NSBundle *growlPrefPaneBundle = nil;
NSString *growlHelperAppPath;
#ifdef DEBUG
//For a debug build, first look for a running GHA. It might not actually be within a Growl prefpane bundle.
//First look for a running GHA. It might not actually be within a Growl prefpane bundle.
growlHelperAppPath = [[GrowlPathUtilities runningHelperAppBundle] bundlePath];
if (!growlHelperAppPath) {
if (growlHelperAppPath) {
//The GHA bundle path should be: .../Growl.prefPane/Contents/Resources/GrowlHelperApp.app
NSArray *growlHelperAppPathComponents = [growlHelperAppPath pathComponents];
NSString *growlPrefPaneBundlePath = [NSString pathWithComponents:[growlHelperAppPathComponents subarrayWithRange:(NSRange){ 0UL, [growlHelperAppPathComponents count] - 3UL }]];
growlPrefPaneBundle = [NSBundle bundleWithPath:growlPrefPaneBundlePath];
//Make sure we actually got a Growl.prefPane and not, say, a Growl project folder. (NSBundle can be liberal in its acceptance of a directory as a bundle at times.)
if (![[growlPrefPaneBundle bundleIdentifier] isEqualToString:GROWL_PREFPANE_BUNDLE_IDENTIFIER])
growlPrefPaneBundle = nil;
}
//If we didn't get a Growl prefpane bundle by finding the bundle that contained GHA, look it up directly.
if (!growlPrefPaneBundle) {
growlPrefPaneBundle = [GrowlPathUtilities growlPrefPaneBundle];
}
//If we don't already have the path to a running GHA, then
if (!growlHelperAppPath) {
//Look for an installed-but-not-running GHA.
growlHelperAppPath = [growlPrefPaneBundle pathForResource:@"GrowlHelperApp"
ofType:@"app"];
}
NSLog(@"Will use GrowlHelperApp at %@", growlHelperAppPath);
#else
growlPrefPaneBundle = [GrowlPathUtilities growlPrefPaneBundle];
growlHelperAppPath = [growlPrefPaneBundle pathForResource:@"GrowlHelperApp"
ofType:@"app"];
#endif
#ifdef GROWL_WITH_INSTALLER
if (growlPrefPaneBundle) {
@ -762,16 +833,12 @@ static BOOL registerWhenGrowlIsReady = NO;
struct ProcessSerialNumber appPSN = {
0, kNoProcess
};
while ((err = GetNextProcess(&appPSN)) == noErr) {
NSDictionary *dict = [(id)ProcessInformationCopyDictionary(&appPSN, kProcessDictionaryIncludeAllInformationMask) autorelease];
NSString *bundlePath = [dict objectForKey:@"BundlePath"];
if ([bundlePath isEqualToString:growlHelperAppPath]) {
//Match!
break;
}
}
err = [self getPSN:&appPSN forAppWithBundleAtPath:growlHelperAppPath];
BOOL foundGrowlProcess = (err == noErr);
BOOL foundNoGrowlProcess = (err == procNotFound);
if (err == noErr) {
//If both of these are false, the process search failed with an error (and I don't mean procNotFound).
if (foundGrowlProcess || foundNoGrowlProcess) {
NSURL *regItemURL = nil;
BOOL passRegDict = NO;
@ -814,35 +881,10 @@ static BOOL registerWhenGrowlIsReady = NO;
}
}
AEStreamRef stream = AEStreamCreateEvent(kCoreEventClass, kAEOpenDocuments,
//Target application
typeProcessSerialNumber, &appPSN, sizeof(appPSN),
kAutoGenerateReturnID, kAnyTransactionID);
if (!stream) {
NSLog(@"%@: Could not create open-document event to register this application with Growl", [self class]);
} else {
if (passRegDict) {
NSString *regItemURLString = [regItemURL absoluteString];
NSData *regItemURLUTF8Data = [regItemURLString dataUsingEncoding:NSUTF8StringEncoding];
err = AEStreamWriteKeyDesc(stream, keyDirectObject, typeFileURL, [regItemURLUTF8Data bytes], [regItemURLUTF8Data length]);
if (err != noErr) {
NSLog(@"%@: Could not set direct object of open-document event to register this application with Growl because AEStreamWriteKeyDesc returned %li/%s", [self class], (long)err, GetMacOSStatusCommentString(err));
}
}
AppleEvent event;
err = AEStreamClose(stream, &event);
if (err != noErr) {
NSLog(@"%@: Could not finish open-document event to register this application with Growl because AEStreamClose returned %li/%s", [self class], (long)err, GetMacOSStatusCommentString(err));
} else {
err = AESendMessage(&event, /*reply*/ NULL, kAENoReply | kAEDontReconnect | kAENeverInteract | kAEDontRecord, kAEDefaultTimeout);
if (err != noErr) {
NSLog(@"%@: Could not send open-document event to register this application with Growl because AESend returned %li/%s", [self class], (long)err, GetMacOSStatusCommentString(err));
}
}
success = (err == noErr);
}
if (foundNoGrowlProcess)
success = [self launchApplicationWithBundleAtPath:growlHelperAppPath openDocumentURL:(passRegDict ? regItemURL : nil)];
else
success = [self sendOpenEventToProcessWithProcessSerialNumber:&appPSN openDocumentURL:(passRegDict ? regItemURL : nil)];
}
}
}

Просмотреть файл

@ -293,6 +293,7 @@ struct GrowlNetworkNotification {
#define GROWL_PATHWAY_EXTENSION XSTR("growlPathway")
#define GROWL_VIEW_EXTENSION XSTR("growlView")
#define GROWL_STYLE_EXTENSION XSTR("growlStyle")
#define GROWL_PATHEXTENSION_TICKET XSTR("growlTicket")
/* --- These following macros are intended for plug-ins --- */

Просмотреть файл

@ -10,8 +10,6 @@
#import <Cocoa/Cocoa.h>
#import "GrowlPathUtilities.h"
#import "GrowlPreferencesController.h"
#import "GrowlTicketController.h"
#import "GrowlDefinesInternal.h"
static NSBundle *helperAppBundle;

Просмотреть файл

@ -1,4 +1,4 @@
Copyright (c) The Growl Project, 2004-2009
Copyright (c) The Growl Project, 2004-2011
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

Просмотреть файл

@ -92,8 +92,7 @@ DispatchNamedNotification(const nsAString &aName,
{
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
if ([GrowlApplicationBridge isGrowlInstalled] == NO ||
[GrowlApplicationBridge isGrowlRunning] == NO)
if ([GrowlApplicationBridge isGrowlRunning] == NO)
return NS_ERROR_NOT_AVAILABLE;
mozGrowlDelegate *delegate =
@ -146,9 +145,6 @@ nsAlertsService::Init()
{
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
if ([GrowlApplicationBridge isGrowlInstalled] == NO)
return NS_ERROR_SERVICE_NOT_AVAILABLE;
NS_ASSERTION([GrowlApplicationBridge growlDelegate] == nil,
"We already registered with Growl!");

Просмотреть файл

@ -160,9 +160,9 @@
#define NS_TYPEAHEADFIND_CID \
{ 0xe7f70966, 0x9a37, 0x48d7, { 0x8a, 0xeb, 0x35, 0x99, 0x8f, 0x31, 0x09, 0x0e} }
// {42ef1d52-3351-4973-98f8-d18f089bccfa}
// {5edc87c2-6960-44e5-8431-bdfbb56f6aff}
#define NS_URLCLASSIFIERPREFIXSET_CID \
{ 0x42ef1d52, 0x3351, 0x4973, { 0x98, 0xf8, 0xd1, 0x8f, 0x08, 0x9b, 0xcc, 0xfa} }
{ 0x5edc87c2, 0x6960, 0x44e5, { 0x84, 0x31, 0xbd, 0xfb, 0xb5, 0x6f, 0x6a, 0xff} }
// {5eb7c3c1-ec1f-4007-87cc-eefb37d68ce6}
#define NS_URLCLASSIFIERDBSERVICE_CID \

Просмотреть файл

@ -41,7 +41,7 @@
interface nsIArray;
[scriptable, uuid(42ef1d52-3351-4973-98f8-d18f089bccfa)]
[scriptable, uuid(5edc87c2-6960-44e5-8431-bdfbb56f6aff)]
interface nsIUrlClassifierPrefixSet : nsISupports
{
void setPrefixes([const, array, size_is(aLength)] in unsigned long aPrefixes,
@ -51,7 +51,7 @@ interface nsIUrlClassifierPrefixSet : nsISupports
boolean contains(in unsigned long aPrefix);
boolean probe(in unsigned long aPrefix, in unsigned long aKey,
inout boolean aReady);
PRUint32 estimateSize();
PRUint32 sizeOfIncludingThis(in boolean aCountMe);
PRUint32 getKey();
boolean isEmpty();
void loadFromFile(in nsIFile aFile);

Просмотреть файл

@ -3653,7 +3653,7 @@ nsUrlClassifierDBServiceWorker::LoadPrefixSet(nsCOMPtr<nsIFile> & aFile)
#ifdef DEBUG
PRUint32 size = 0;
rv = mPrefixSet->EstimateSize(&size);
rv = mPrefixSet->SizeOfIncludingThis(true, &size);
LOG(("SB tree done, size = %d bytes\n", size));
NS_ENSURE_SUCCESS(rv, rv);
#endif

Просмотреть файл

@ -42,6 +42,7 @@
#include "nsCOMPtr.h"
#include "nsDebug.h"
#include "nsTArray.h"
#include "nsString.h"
#include "nsUrlClassifierPrefixSet.h"
#include "nsIUrlClassifierPrefixSet.h"
#include "nsIRandomGenerator.h"
@ -67,6 +68,78 @@ static const PRLogModuleInfo *gUrlClassifierPrefixSetLog = nsnull;
#define LOG_ENABLED() (false)
#endif
class nsPrefixSetReporter : public nsIMemoryReporter
{
public:
nsPrefixSetReporter(nsUrlClassifierPrefixSet * aParent, const nsACString & aName);
virtual ~nsPrefixSetReporter() {};
NS_DECL_ISUPPORTS
NS_DECL_NSIMEMORYREPORTER
private:
nsCString mPath;
nsUrlClassifierPrefixSet * mParent;
};
NS_IMPL_THREADSAFE_ISUPPORTS1(nsPrefixSetReporter, nsIMemoryReporter)
nsPrefixSetReporter::nsPrefixSetReporter(nsUrlClassifierPrefixSet * aParent,
const nsACString & aName)
: mParent(aParent)
{
mPath.Assign(NS_LITERAL_CSTRING("explicit/storage/prefixset"));
if (!aName.IsEmpty()) {
mPath.Append("/");
mPath.Append(aName);
}
}
NS_IMETHODIMP
nsPrefixSetReporter::GetProcess(nsACString & aProcess)
{
aProcess.Truncate();
return NS_OK;
}
NS_IMETHODIMP
nsPrefixSetReporter::GetPath(nsACString & aPath)
{
aPath.Assign(mPath);
return NS_OK;
}
NS_IMETHODIMP
nsPrefixSetReporter::GetKind(PRInt32 * aKind)
{
*aKind = nsIMemoryReporter::KIND_HEAP;
return NS_OK;
}
NS_IMETHODIMP
nsPrefixSetReporter::GetUnits(PRInt32 * aUnits)
{
*aUnits = nsIMemoryReporter::UNITS_BYTES;
return NS_OK;
}
NS_IMETHODIMP
nsPrefixSetReporter::GetAmount(PRInt64 * aAmount)
{
PRUint32 size;
nsresult rv = mParent->SizeOfIncludingThis(true, &size);
*aAmount = size;
return rv;
}
NS_IMETHODIMP
nsPrefixSetReporter::GetDescription(nsACString & aDescription)
{
aDescription.Assign(NS_LITERAL_CSTRING("Memory used by a PrefixSet for "
"UrlClassifier, in bytes."));
return NS_OK;
}
NS_IMPL_THREADSAFE_ISUPPORTS1(nsUrlClassifierPrefixSet, nsIUrlClassifierPrefixSet)
nsUrlClassifierPrefixSet::nsUrlClassifierPrefixSet()
@ -84,6 +157,14 @@ nsUrlClassifierPrefixSet::nsUrlClassifierPrefixSet()
if (NS_FAILED(rv)) {
LOG(("Failed to initialize PrefixSet"));
}
mReporter = new nsPrefixSetReporter(this, NS_LITERAL_CSTRING("all"));
NS_RegisterMemoryReporter(mReporter);
}
nsUrlClassifierPrefixSet::~nsUrlClassifierPrefixSet()
{
NS_UnregisterMemoryReporter(mReporter);
}
nsresult
@ -199,6 +280,8 @@ PRUint32 nsUrlClassifierPrefixSet::BinSearch(PRUint32 start,
NS_IMETHODIMP
nsUrlClassifierPrefixSet::Contains(PRUint32 aPrefix, bool * aFound)
{
mPrefixSetLock.AssertCurrentThreadOwns();
*aFound = false;
if (!mHasPrefixes) {
@ -244,15 +327,18 @@ nsUrlClassifierPrefixSet::Contains(PRUint32 aPrefix, bool * aFound)
}
NS_IMETHODIMP
nsUrlClassifierPrefixSet::EstimateSize(PRUint32 * aSize)
nsUrlClassifierPrefixSet::SizeOfIncludingThis(bool aCountMe, PRUint32 * aSize)
{
MutexAutoLock lock(mPrefixSetLock);
*aSize = sizeof(bool);
if (mHasPrefixes) {
*aSize += sizeof(PRUint16) * mDeltas.Length();
*aSize += sizeof(PRUint32) * mIndexPrefixes.Length();
*aSize += sizeof(PRUint32) * mIndexStarts.Length();
if (aCountMe) {
size_t usable = moz_malloc_usable_size(this);
*aSize = (PRUint32)(usable ? usable : sizeof(*this));
} else {
*aSize = 0;
}
*aSize += mDeltas.SizeOf();
*aSize += mIndexPrefixes.SizeOf();
*aSize += mIndexStarts.SizeOf();
return NS_OK;
}

Просмотреть файл

@ -45,16 +45,19 @@
#include "nsID.h"
#include "nsIFile.h"
#include "nsIUrlClassifierPrefixSet.h"
#include "nsIMemoryReporter.h"
#include "nsToolkitCompsCID.h"
#include "mozilla/Mutex.h"
#include "mozilla/CondVar.h"
#include "mozilla/FileUtils.h"
class nsPrefixSetReporter;
class nsUrlClassifierPrefixSet : public nsIUrlClassifierPrefixSet
{
public:
nsUrlClassifierPrefixSet();
virtual ~nsUrlClassifierPrefixSet() {};
virtual ~nsUrlClassifierPrefixSet();
// Can send an empty Array to clean the tree
NS_IMETHOD SetPrefixes(const PRUint32* aArray, PRUint32 aLength);
@ -69,7 +72,7 @@ public:
NS_IMETHOD Probe(PRUint32 aPrefix, PRUint32 aKey, bool* aReady, bool* aFound);
// Return the estimated size of the set on disk and in memory,
// in bytes
NS_IMETHOD EstimateSize(PRUint32* aSize);
NS_IMETHOD SizeOfIncludingThis(bool aCountMe, PRUint32* aSize);
NS_IMETHOD IsEmpty(bool * aEmpty);
NS_IMETHOD LoadFromFile(nsIFile* aFile);
NS_IMETHOD StoreToFile(nsIFile* aFile);
@ -85,6 +88,7 @@ protected:
mozilla::Mutex mPrefixSetLock;
mozilla::CondVar mSetIsReady;
nsRefPtr<nsPrefixSetReporter> mReporter;
PRUint32 BinSearch(PRUint32 start, PRUint32 end, PRUint32 target);
nsresult LoadFromFd(mozilla::AutoFDClose & fileFd);
@ -103,6 +107,7 @@ protected:
nsTArray<PRUint32> mIndexStarts;
// array containing deltas from indices.
nsTArray<PRUint16> mDeltas;
};
#endif

Просмотреть файл

@ -28,6 +28,12 @@ function arrContains(arr, target) {
return (!(i < 0 || i >= arr.length) && arr[i] == target);
}
function wrappedProbe(pset, prefix) {
let key = pset.getKey();
let dummy = {};
return pset.probe(prefix, key, dummy);
};
// doRandomLookups: we use this to test for false membership with random input
// over the range of prefixes (unsigned 32-bits integers).
// pset: a nsIUrlClassifierPrefixSet to test.
@ -39,7 +45,7 @@ function doRandomLookups(pset, prefixes, N) {
while (arrContains(prefixes, randInt))
randInt = Math.floor(Math.random() * Math.pow(2, 32));
do_check_false(pset.contains(randInt));
do_check_false(wrappedProbe(pset, randInt));
}
}
@ -50,7 +56,7 @@ function doExpectedLookups(pset, prefixes, N) {
for (let i = 0; i < N; i++) {
prefixes.forEach(function (x) {
dump("Checking " + x + "\n");
do_check_true(pset.contains(x));
do_check_true(wrappedProbe(pset, x));
});
}
}
@ -63,11 +69,11 @@ function testBasicPset() {
let prefixes = [2,100,50,2000,78000,1593203];
pset.setPrefixes(prefixes, prefixes.length);
do_check_true(pset.contains(100));
do_check_false(pset.contains(100000));
do_check_true(pset.contains(1593203));
do_check_false(pset.contains(999));
do_check_false(pset.contains(0));
do_check_true(wrappedProbe(pset, 100));
do_check_false(wrappedProbe(pset, 100000));
do_check_true(wrappedProbe(pset, 1593203));
do_check_false(wrappedProbe(pset, 999));
do_check_false(wrappedProbe(pset, 0));
}
function testDuplicates() {
@ -76,12 +82,12 @@ function testDuplicates() {
let prefixes = [1,1,2,2,2,3,3,3,3,3,3,5,6,6,7,7,9,9,9];
pset.setPrefixes(prefixes, prefixes.length);
do_check_true(pset.contains(1));
do_check_true(pset.contains(2));
do_check_true(pset.contains(5));
do_check_true(pset.contains(9));
do_check_false(pset.contains(4));
do_check_false(pset.contains(8));
do_check_true(wrappedProbe(pset, 1));
do_check_true(wrappedProbe(pset, 2));
do_check_true(wrappedProbe(pset, 5));
do_check_true(wrappedProbe(pset, 9));
do_check_false(wrappedProbe(pset, 4));
do_check_false(wrappedProbe(pset, 8));
}
function testSimplePset() {
@ -114,7 +120,7 @@ function testReSetPrefixes() {
doExpectedLookups(pset, secondPrefixes, 1);
for (let i = 0; i < prefixes.length; i++) {
do_check_false(pset.contains(prefixes[i]));
do_check_false(wrappedProbe(pset, prefixes[i]));
}
}
@ -142,12 +148,12 @@ function testTinySet() {
let prefixes = [1];
pset.setPrefixes(prefixes, prefixes.length);
do_check_true(pset.contains(1));
do_check_false(pset.contains(100000));
do_check_true(wrappedProbe(pset, 1));
do_check_false(wrappedProbe(pset, 100000));
prefixes = [];
pset.setPrefixes(prefixes, prefixes.length);
do_check_false(pset.contains(1));
do_check_false(wrappedProbe(pset, 1));
}
let tests = [testBasicPset,

Просмотреть файл

@ -2623,12 +2623,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
<h1><a name="growl"></a>Growl License</h1>
<p>This license applies to certain files in the directory
<span class="path">toolkit/components/alerts/src/mac/growl/</span> and
<span class="path">camino/growl/</span>. (This code only ships in the Mac
OS X version of the product.)
<span class="path">toolkit/components/alerts/mac/growl/</span>.
(This code only ships in the Mac OS X version of the product.)
<pre>
Copyright (c) The Growl Project, 2004-2009
Copyright (c) The Growl Project, 2004-2011
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,

Просмотреть файл

@ -2942,16 +2942,18 @@ var XPIProvider = {
let state = this.getInstallLocationStates();
// If the database exists then the previous file cache can be trusted
// otherwise the database needs to be recreated
let dbFile = FileUtils.getFile(KEY_PROFILEDIR, [FILE_DATABASE], true);
updateDatabase |= !dbFile.exists();
if (!updateDatabase) {
// If the state has changed then we must update the database
let cache = Prefs.getCharPref(PREF_INSTALL_CACHE, null);
updateDatabase |= cache != JSON.stringify(state);
}
// If the database doesn't exist and there are add-ons installed then we
// must update the database however if there are no add-ons then there is
// no need to update the database.
if (!XPIDatabase.dbfileExists)
updateDatabase = state.length > 0;
if (!updateDatabase) {
let bootstrapDescriptors = [this.bootstrappedAddons[b].descriptor
for (b in this.bootstrappedAddons)];
@ -2963,7 +2965,7 @@ var XPIProvider = {
bootstrapDescriptors.splice(pos, 1);
}
});
if (bootstrapDescriptors.length > 0) {
WARN("Bootstrap state is invalid (missing add-ons: " + bootstrapDescriptors.toSource() + ")");
updateDatabase = true;
@ -2977,7 +2979,7 @@ var XPIProvider = {
// If the database needs to be updated then open it and then update it
// from the filesystem
if (updateDatabase || hasPendingChanges) {
let migrateData = XPIDatabase.openConnection(false);
let migrateData = XPIDatabase.openConnection(false, true);
try {
extensionListChanged = this.processFileChanges(state, manifests,
@ -4022,6 +4024,8 @@ var XPIDatabase = {
addonCache: [],
// The nested transaction count
transactionCount: 0,
// The database file
dbfile: FileUtils.getFile(KEY_PROFILEDIR, [FILE_DATABASE], true),
// The statements used by the database
statements: {
@ -4113,6 +4117,11 @@ var XPIDatabase = {
rollbackSavepoint: "ROLLBACK TO SAVEPOINT 'default'"
},
get dbfileExists() {
delete this.dbfileExists;
return this.dbfileExists = this.dbfile.exists();
},
/**
* Begins a new transaction in the database. Transactions may be nested. Data
* written by an inner transaction may be rolled back on its own. Rolling back
@ -4176,6 +4185,7 @@ var XPIDatabase = {
// Attempt to open the database
try {
connection = Services.storage.openUnsharedDatabase(aDBFile);
this.dbfileExists = true;
}
catch (e) {
ERROR("Failed to open database (1st attempt)", e);
@ -4213,12 +4223,17 @@ var XPIDatabase = {
* @return the migration data from the database if it was an old schema or
* null otherwise.
*/
openConnection: function XPIDB_openConnection(aRebuildOnError) {
this.initialized = true;
let dbfile = FileUtils.getFile(KEY_PROFILEDIR, [FILE_DATABASE], true);
openConnection: function XPIDB_openConnection(aRebuildOnError, aForceOpen) {
delete this.connection;
this.connection = this.openDatabaseFile(dbfile);
if (!aForceOpen && !this.dbfileExists) {
this.connection = null;
return {};
}
this.initialized = true;
this.connection = this.openDatabaseFile(this.dbfile);
let migrateData = null;
// If the database was corrupt or missing then the new blank database will
@ -4235,11 +4250,11 @@ var XPIDatabase = {
// Delete the existing database
this.connection.close();
try {
if (dbfile.exists())
dbfile.remove(true);
if (this.dbfileExists)
this.dbfile.remove(true);
// Reopen an empty database
this.connection = this.openDatabaseFile(dbfile);
this.connection = this.openDatabaseFile(this.dbfile);
}
catch (e) {
ERROR("Failed to remove old database", e);
@ -4250,7 +4265,6 @@ var XPIDatabase = {
}
else if (Prefs.getIntPref(PREF_DB_SCHEMA, 0) == 0) {
// Only migrate data from the RDF if we haven't done it before
LOG("Migrating data from extensions.rdf");
migrateData = this.getMigrateDataFromRDF();
}
@ -4350,6 +4364,7 @@ var XPIDatabase = {
// Migrate data from extensions.rdf
let rdffile = FileUtils.getFile(KEY_PROFILEDIR, [FILE_OLD_DATABASE], true);
if (rdffile.exists()) {
LOG("Migrating data from extensions.rdf");
let ds = gRDF.GetDataSourceBlocking(Services.io.newFileURI(rdffile).spec);
let root = Cc["@mozilla.org/rdf/container;1"].
createInstance(Ci.nsIRDFContainer);
@ -4963,6 +4978,9 @@ var XPIDatabase = {
* @return an array of names of install locations
*/
getInstallLocations: function XPIDB_getInstallLocations() {
if (!this.connection)
return [];
let stmt = this.getStatement("getInstallLocations");
return [row.location for each (row in resultRows(stmt))];
@ -4976,6 +4994,9 @@ var XPIDatabase = {
* @return an array of DBAddonInternals
*/
getAddonsInLocation: function XPIDB_getAddonsInLocation(aLocation) {
if (!this.connection)
return [];
let stmt = this.getStatement("getAddonsInLocation");
stmt.params.location = aLocation;
@ -4994,6 +5015,11 @@ var XPIDatabase = {
* A callback to pass the DBAddonInternal to
*/
getAddonInLocation: function XPIDB_getAddonInLocation(aId, aLocation, aCallback) {
if (!this.connection) {
aCallback(null);
return;
}
let stmt = this.getStatement("getAddonInLocation");
stmt.params.id = aId;
@ -5020,6 +5046,11 @@ var XPIDatabase = {
* A callback to pass the DBAddonInternal to
*/
getVisibleAddonForID: function XPIDB_getVisibleAddonForID(aId, aCallback) {
if (!this.connection) {
aCallback(null);
return;
}
let stmt = this.getStatement("getVisibleAddonForID");
stmt.params.id = aId;
@ -5045,6 +5076,11 @@ var XPIDatabase = {
* A callback to pass the array of DBAddonInternals to
*/
getVisibleAddons: function XPIDB_getVisibleAddons(aTypes, aCallback) {
if (!this.connection) {
aCallback([]);
return;
}
let stmt = null;
if (!aTypes || aTypes.length == 0) {
stmt = this.getStatement("getVisibleAddons");
@ -5076,6 +5112,9 @@ var XPIDatabase = {
* @return an array of DBAddonInternals
*/
getAddonsByType: function XPIDB_getAddonsByType(aType) {
if (!this.connection)
return [];
let stmt = this.getStatement("getAddonsByType");
stmt.params.type = aType;
@ -5090,6 +5129,9 @@ var XPIDatabase = {
* @return a DBAddonInternal
*/
getVisibleAddonForInternalName: function XPIDB_getVisibleAddonForInternalName(aInternalName) {
if (!this.connection)
return null;
let stmt = this.getStatement("getVisibleAddonForInternalName");
let addon = null;
@ -5112,6 +5154,11 @@ var XPIDatabase = {
*/
getVisibleAddonsWithPendingOperations:
function XPIDB_getVisibleAddonsWithPendingOperations(aTypes, aCallback) {
if (!this.connection) {
aCallback([]);
return;
}
let stmt = null;
if (!aTypes || aTypes.length == 0) {
stmt = this.getStatement("getVisibleAddonsWithPendingOperations");
@ -5143,6 +5190,9 @@ var XPIDatabase = {
* @return an array of DBAddonInternals
*/
getAddons: function XPIDB_getAddons() {
if (!this.connection)
return [];
let stmt = this.getStatement("getAddons");
return [this.makeAddonFromRow(row) for each (row in resultRows(stmt))];;
@ -5157,6 +5207,10 @@ var XPIDatabase = {
* The file descriptor of the add-on
*/
addAddonMetadata: function XPIDB_addAddonMetadata(aAddon, aDescriptor) {
// If there is no DB yet then forcibly create one
if (!this.connection)
this.openConnection(false, true);
this.beginTransaction();
var self = this;
@ -5430,28 +5484,34 @@ var XPIDatabase = {
let enabledAddons = [];
let text = "[ExtensionDirs]\r\n";
let count = 0;
let stmt;
let stmt = this.getStatement("getActiveAddons");
if (this.connection) {
stmt = this.getStatement("getActiveAddons");
for (let row in resultRows(stmt)) {
text += "Extension" + (count++) + "=" + row.descriptor + "\r\n";
enabledAddons.push(row.id + ":" + row.version);
for (let row in resultRows(stmt)) {
text += "Extension" + (count++) + "=" + row.descriptor + "\r\n";
enabledAddons.push(row.id + ":" + row.version);
}
}
// The selected skin may come from an inactive theme (the default theme
// when a lightweight theme is applied for example)
text += "\r\n[ThemeDirs]\r\n";
if (Prefs.getBoolPref(PREF_EM_DSS_ENABLED)) {
stmt = this.getStatement("getThemes");
}
else {
stmt = this.getStatement("getActiveTheme");
stmt.params.internalName = XPIProvider.selectedSkin;
}
count = 0;
for (let row in resultRows(stmt)) {
text += "Extension" + (count++) + "=" + row.descriptor + "\r\n";
enabledAddons.push(row.id + ":" + row.version);
if (this.connection) {
if (Prefs.getBoolPref(PREF_EM_DSS_ENABLED)) {
stmt = this.getStatement("getThemes");
}
else {
stmt = this.getStatement("getActiveTheme");
stmt.params.internalName = XPIProvider.selectedSkin;
}
count = 0;
for (let row in resultRows(stmt)) {
text += "Extension" + (count++) + "=" + row.descriptor + "\r\n";
enabledAddons.push(row.id + ":" + row.version);
}
}
var fos = FileUtils.openSafeFileOutputStream(addonsList);

Просмотреть файл

@ -125,6 +125,10 @@ function run_test() {
startupManager();
let file = gProfD.clone();
file.append("extensions.sqlite");
do_check_false(file.exists());
run_test_1();
}
@ -167,6 +171,10 @@ function run_test_1() {
}
function check_test_1() {
let file = gProfD.clone();
file.append("extensions.sqlite");
do_check_true(file.exists());
AddonManager.getAllInstalls(function(installs) {
// There should be no active installs now since the install completed and
// doesn't require a restart.

Просмотреть файл

@ -247,13 +247,15 @@ function run_test_1() {
do_check_false(t2.appDisabled);
do_check_eq(t2.pendingOperations, AddonManager.PENDING_NONE);
// After restarting the database won't be open and so can be replaced with
// a bad file
restartManager();
// Shutdown and replace the database with a corrupt file (a directory
// serves this purpose). On startup the add-ons manager won't rebuild
// because there is a file there still.
shutdownManager();
var dbfile = gProfD.clone();
dbfile.append("extensions.sqlite");
dbfile.remove(true);
dbfile.create(AM_Ci.nsIFile.DIRECTORY_TYPE, 0755);
startupManager(false);
// Accessing the add-ons should open and recover the database
AddonManager.getAddonsByIDs(["addon1@tests.mozilla.org",

Просмотреть файл

@ -247,13 +247,15 @@ function run_test_1() {
do_check_false(t2.appDisabled);
do_check_eq(t2.pendingOperations, AddonManager.PENDING_NONE);
// After restarting the database won't be open and so can be replaced with
// a bad file
restartManager();
// Shutdown and replace the database with a corrupt file (a directory
// serves this purpose). On startup the add-ons manager won't rebuild
// because there is a file there still.
shutdownManager();
var dbfile = gProfD.clone();
dbfile.append("extensions.sqlite");
dbfile.remove(true);
dbfile.create(AM_Ci.nsIFile.DIRECTORY_TYPE, 0755);
startupManager(false);
// Accessing the add-ons should open and recover the database
AddonManager.getAddonsByIDs(["addon1@tests.mozilla.org",

Просмотреть файл

@ -132,6 +132,10 @@ function run_test() {
check_startup_changes(AddonManager.STARTUP_CHANGE_DISABLED, []);
check_startup_changes(AddonManager.STARTUP_CHANGE_ENABLED, []);
let file = gProfD.clone();
file.append("extensions.sqlite");
do_check_false(file.exists());
AddonManager.getAddonsByIDs(["addon1@tests.mozilla.org",
"addon2@tests.mozilla.org",
"addon3@tests.mozilla.org",
@ -183,6 +187,10 @@ function run_test_1() {
check_startup_changes(AddonManager.STARTUP_CHANGE_ENABLED, []);
do_check_true(gCachePurged);
let file = gProfD.clone();
file.append("extensions.sqlite");
do_check_true(file.exists());
AddonManager.getAddonsByIDs(["addon1@tests.mozilla.org",
"addon2@tests.mozilla.org",
"addon3@tests.mozilla.org",

Просмотреть файл

@ -161,6 +161,11 @@ AndroidBridge::Init(JNIEnv *jEnv,
jDisableBatteryNotifications = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "disableBatteryNotifications", "()V");
jGetCurrentBatteryInformation = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "getCurrentBatteryInformation", "()[D");
jGetAccessibilityEnabled = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "getAccessibilityEnabled", "()Z");
jHandleGeckoMessage = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "handleGeckoMessage", "(Ljava/lang/String;)Ljava/lang/String;");
jCheckUriVisited = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "checkUriVisited", "(Ljava/lang/String;)V");
jMarkUriVisited = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "markUriVisited", "(Ljava/lang/String;)V");
jEGLContextClass = (jclass) jEnv->NewGlobalRef(jEnv->FindClass("javax/microedition/khronos/egl/EGLContext"));
jEGL10Class = (jclass) jEnv->NewGlobalRef(jEnv->FindClass("javax/microedition/khronos/egl/EGL10"));
jEGLSurfaceImplClass = (jclass) jEnv->NewGlobalRef(jEnv->FindClass("com/google/android/gles_jni/EGLSurfaceImpl"));
@ -670,6 +675,13 @@ AndroidBridge::HideProgressDialogOnce()
}
}
bool
AndroidBridge::GetAccessibilityEnabled()
{
ALOG_BRIDGE("AndroidBridge::GetAccessibilityEnabled");
return mJNIEnv->CallStaticBooleanMethod(mGeckoAppShellClass, jGetAccessibilityEnabled);
}
void
AndroidBridge::PerformHapticFeedback(bool aIsLongPress)
{
@ -839,6 +851,12 @@ AndroidBridge::SetSurfaceView(jobject obj)
mSurfaceView.Init(obj);
}
void
AndroidBridge::SetSoftwareLayerClient(jobject obj)
{
mSoftwareLayerClient.Init(obj);
}
void
AndroidBridge::ShowInputMethodPicker()
{
@ -1002,10 +1020,8 @@ AndroidBridge::CreateShortcut(const nsAString& aTitle, const nsAString& aURI, co
void
AndroidBridge::PostToJavaThread(nsIRunnable* aRunnable, bool aMainThread)
{
__android_log_print(ANDROID_LOG_INFO, "GeckoBridge", "%s", __PRETTY_FUNCTION__);
JNIEnv* env = AndroidBridge::AttachThread(false);
if (!env) {
__android_log_print(ANDROID_LOG_INFO, "GeckoBridge", "no jni env in %s!!", __PRETTY_FUNCTION__);
return;
}
mRunnableQueue.AppendObject(aRunnable);
@ -1016,27 +1032,21 @@ AndroidBridge::PostToJavaThread(nsIRunnable* aRunnable, bool aMainThread)
env->ExceptionDescribe();
env->ExceptionClear();
}
__android_log_print(ANDROID_LOG_INFO, "GeckoBridge", "leaving %s", __PRETTY_FUNCTION__);
}
void
AndroidBridge::ExecuteNextRunnable()
{
__android_log_print(ANDROID_LOG_INFO, "GeckoBridge", "%s", __PRETTY_FUNCTION__);
JNIEnv* env = AndroidBridge::AttachThread(false);
if (!env) {
__android_log_print(ANDROID_LOG_INFO, "GeckoBridge", "no jni env in %s!!", __PRETTY_FUNCTION__);
return;
}
if (mRunnableQueue.Count() > 0) {
nsIRunnable* r = mRunnableQueue[0];
__android_log_print(ANDROID_LOG_INFO, "GeckoBridge", "going to run %p", r);
r->Run();
mRunnableQueue.RemoveObjectAt(0);
}
__android_log_print(ANDROID_LOG_INFO, "GeckoBridge", "leaving %s", __PRETTY_FUNCTION__);
}
void
@ -1269,6 +1279,54 @@ AndroidBridge::GetCurrentBatteryInformation(hal::BatteryInformation* aBatteryInf
mJNIEnv->ReleaseDoubleArrayElements(arr, info, 0);
}
void
AndroidBridge::HandleGeckoMessage(const nsAString &aMessage, nsAString &aRet)
{
ALOG_BRIDGE("%s", __PRETTY_FUNCTION__);
JNIEnv* env = AndroidBridge::AttachThread(false);
if (!env) {
ALOG_BRIDGE("no jni env in %s!!", __PRETTY_FUNCTION__);
return;
}
AutoLocalJNIFrame jniFrame(1);
jstring jMessage = mJNIEnv->NewString(nsPromiseFlatString(aMessage).get(), aMessage.Length());
jstring returnMessage = static_cast<jstring>(env->CallStaticObjectMethod(mGeckoAppShellClass, jHandleGeckoMessage, jMessage));
jthrowable ex = env->ExceptionOccurred();
if (ex) {
env->ExceptionDescribe();
env->ExceptionClear();
}
nsJNIString jniStr(returnMessage);
aRet.Assign(jniStr);
ALOG_BRIDGE("leaving %s", __PRETTY_FUNCTION__);
}
void
AndroidBridge::CheckURIVisited(const nsAString& aURI)
{
AutoLocalJNIFrame jniFrame(1);
jstring jstrURI = mJNIEnv->NewString(nsPromiseFlatString(aURI).get(), aURI.Length());
mJNIEnv->CallStaticVoidMethod(mGeckoAppShellClass, jCheckUriVisited, jstrURI);
}
void
AndroidBridge::MarkURIVisited(const nsAString& aURI)
{
AutoLocalJNIFrame jniFrame(1);
jstring jstrURI = mJNIEnv->NewString(nsPromiseFlatString(aURI).get(), aURI.Length());
mJNIEnv->CallStaticVoidMethod(mGeckoAppShellClass, jMarkUriVisited, jstrURI);
}
void AndroidBridge::EmitGeckoAccessibilityEvent (PRInt32 eventType, const nsAString& role, const nsAString& text, const nsAString& description, bool enabled, bool checked, bool password) {
AutoLocalJNIFrame jniFrame;
jstring jstrRole = mJNIEnv->NewString(nsPromiseFlatString(role).get(), role.Length());
jstring jstrText = mJNIEnv->NewString(nsPromiseFlatString(text).get(), text.Length());
jstring jstrDescription = mJNIEnv->NewString(nsPromiseFlatString(description).get(), description.Length());
mJNIEnv->CallStaticVoidMethod(mGeckoAppShellClass, jEmitGeckoAccessibilityEvent, eventType, jstrRole, jstrText, jstrDescription, enabled, checked, password);
}
void *
AndroidBridge::LockBitmap(jobject bitmap)
{
@ -1379,3 +1437,21 @@ AndroidBridge::UnlockWindow(void* window)
return true;
}
/* Implementation file */
NS_IMPL_ISUPPORTS1(nsAndroidBridge, nsIAndroidBridge)
nsAndroidBridge::nsAndroidBridge()
{
}
nsAndroidBridge::~nsAndroidBridge()
{
}
/* void handleGeckoEvent (in AString message); */
NS_IMETHODIMP nsAndroidBridge::HandleGeckoMessage(const nsAString & message, nsAString &aRet NS_OUTPARAM)
{
AndroidBridge::Bridge()->HandleGeckoMessage(message, aRet);
return NS_OK;
}

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше