mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-01-30 01:59:29 +00:00
Merge from mozilla-central.
This commit is contained in:
commit
ef75e63bd5
@ -1631,6 +1631,9 @@ nsHyperTextAccessible::GetCaretOffset(PRInt32 *aCaretOffset)
|
||||
NS_ENSURE_ARG_POINTER(aCaretOffset);
|
||||
*aCaretOffset = -1;
|
||||
|
||||
if (IsDefunct())
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
// Not focused focusable accessible except document accessible doesn't have
|
||||
// a caret.
|
||||
if (!IsDoc() && !FocusMgr()->IsFocused(this) &&
|
||||
|
@ -151,6 +151,9 @@
|
||||
@BINPATH@/components/dom_system_b2g.xpt
|
||||
#endif
|
||||
@BINPATH@/components/dom_battery.xpt
|
||||
#ifdef MOZ_B2G_BT
|
||||
@BINPATH@/components/dom_bluetooth.xpt
|
||||
#endif
|
||||
@BINPATH@/components/dom_canvas.xpt
|
||||
@BINPATH@/components/dom_core.xpt
|
||||
@BINPATH@/components/dom_css.xpt
|
||||
|
@ -357,6 +357,9 @@ pref("browser.search.order.3", "chrome://browser-region/locale/re
|
||||
// search bar results always open in a new tab
|
||||
pref("browser.search.openintab", false);
|
||||
|
||||
// context menu searches open in the foreground
|
||||
pref("browser.search.context.loadInBackground", false);
|
||||
|
||||
// send ping to the server to update
|
||||
pref("browser.search.update", true);
|
||||
|
||||
|
@ -3555,10 +3555,11 @@ const BrowserSearch = {
|
||||
if (!submission)
|
||||
return;
|
||||
|
||||
let inBackground = Services.prefs.getBoolPref("browser.search.context.loadInBackground");
|
||||
openLinkIn(submission.uri.spec,
|
||||
useNewTab ? "tab" : "current",
|
||||
{ postData: submission.postData,
|
||||
inBackground: false,
|
||||
inBackground: inBackground,
|
||||
relatedToCurrent: true });
|
||||
},
|
||||
|
||||
|
@ -536,7 +536,8 @@
|
||||
if (!this.mBlank) {
|
||||
if (!(aStateFlags & nsIWebProgressListener.STATE_RESTORING)) {
|
||||
this.mTab.setAttribute("busy", "true");
|
||||
this.mTabBrowser.setTabTitleLoading(this.mTab);
|
||||
if (!(this.mBrowser.docShell.loadType & Ci.nsIDocShell.LOAD_CMD_RELOAD))
|
||||
this.mTabBrowser.setTabTitleLoading(this.mTab);
|
||||
}
|
||||
|
||||
if (this.mTab.selected)
|
||||
@ -3565,8 +3566,10 @@
|
||||
|
||||
// these offsets are only used in dragend, but we need to free them here
|
||||
// as well
|
||||
delete draggedTab._dragOffsetX;
|
||||
delete draggedTab._dragOffsetY;
|
||||
if (draggedTab) {
|
||||
delete draggedTab._dragOffsetX;
|
||||
delete draggedTab._dragOffsetY;
|
||||
}
|
||||
]]></handler>
|
||||
|
||||
<handler event="dragend"><![CDATA[
|
||||
@ -3981,24 +3984,18 @@
|
||||
|
||||
<implementation implements="nsIDOMEventListener">
|
||||
<constructor><![CDATA[
|
||||
window.addEventListener("findbaropen", this, false);
|
||||
window.addEventListener("resize", this, false);
|
||||
]]></constructor>
|
||||
|
||||
<destructor><![CDATA[
|
||||
window.removeEventListener("findbaropen", this, false);
|
||||
window.removeEventListener("resize", this, false);
|
||||
MousePosTracker.removeListener(this);
|
||||
]]></destructor>
|
||||
|
||||
<property name="label">
|
||||
<setter><![CDATA[
|
||||
if (!this.label) {
|
||||
if (window.gFindBarInitialized && !window.gFindBar.hidden)
|
||||
this.setAttribute("mirror", "true");
|
||||
else
|
||||
this.removeAttribute("mirror");
|
||||
}
|
||||
if (!this.label)
|
||||
this.removeAttribute("mirror");
|
||||
|
||||
this.style.minWidth = this.getAttribute("type") == "status" &&
|
||||
this.getAttribute("previoustype") == "status"
|
||||
@ -4046,10 +4043,6 @@
|
||||
return;
|
||||
|
||||
switch (event.type) {
|
||||
case "findbaropen":
|
||||
this.setAttribute("mirror", "true");
|
||||
this._calcMouseTargetRect();
|
||||
break;
|
||||
case "resize":
|
||||
this._calcMouseTargetRect();
|
||||
break;
|
||||
@ -4059,7 +4052,7 @@
|
||||
|
||||
<method name="_calcMouseTargetRect">
|
||||
<body><![CDATA[
|
||||
let alignRight = (window.gFindBarInitialized && !window.gFindBar.hidden);
|
||||
let alignRight = false;
|
||||
|
||||
if (getComputedStyle(document.documentElement).direction == "rtl")
|
||||
alighRight = !alignRight;
|
||||
|
@ -15,24 +15,26 @@ function reallyHandleRequest(request, response) {
|
||||
|
||||
// Allow the caller to drive how authentication is processed via the query.
|
||||
// Eg, http://localhost:8888/authenticate.sjs?user=foo&realm=bar
|
||||
var query = request.queryString;
|
||||
// The extra ? allows the user/pass/realm checks to succeed if the name is
|
||||
// at the beginning of the query string.
|
||||
var query = "?" + request.queryString;
|
||||
|
||||
var expected_user = "", expected_pass = "", realm = "mochitest";
|
||||
var proxy_expected_user = "", proxy_expected_pass = "", proxy_realm = "mochi-proxy";
|
||||
var huge = false, plugin = false;
|
||||
var huge = false, plugin = false, anonymous = false;
|
||||
var authHeaderCount = 1;
|
||||
// user=xxx
|
||||
match = /user=([^&]*)/.exec(query);
|
||||
match = /[^_]user=([^&]*)/.exec(query);
|
||||
if (match)
|
||||
expected_user = match[1];
|
||||
|
||||
// pass=xxx
|
||||
match = /pass=([^&]*)/.exec(query);
|
||||
match = /[^_]pass=([^&]*)/.exec(query);
|
||||
if (match)
|
||||
expected_pass = match[1];
|
||||
|
||||
// realm=xxx
|
||||
match = /realm=([^&]*)/.exec(query);
|
||||
match = /[^_]realm=([^&]*)/.exec(query);
|
||||
if (match)
|
||||
realm = match[1];
|
||||
|
||||
@ -66,6 +68,10 @@ function reallyHandleRequest(request, response) {
|
||||
if (match)
|
||||
authHeaderCount = match[1]+0;
|
||||
|
||||
// anonymous=1
|
||||
match = /anonymous=1/.exec(query);
|
||||
if (match)
|
||||
anonymous = true;
|
||||
|
||||
// Look for an authentication header, if any, in the request.
|
||||
//
|
||||
@ -74,8 +80,9 @@ function reallyHandleRequest(request, response) {
|
||||
// This test only supports Basic auth. The value sent by the client is
|
||||
// "username:password", obscured with base64 encoding.
|
||||
|
||||
var actual_user = "", actual_pass = "", authHeader;
|
||||
var actual_user = "", actual_pass = "", authHeader, authPresent = false;
|
||||
if (request.hasHeader("Authorization")) {
|
||||
authPresent = true;
|
||||
authHeader = request.getHeader("Authorization");
|
||||
match = /Basic (.+)/.exec(authHeader);
|
||||
if (match.length != 2)
|
||||
@ -115,16 +122,24 @@ function reallyHandleRequest(request, response) {
|
||||
requestProxyAuth = false;
|
||||
}
|
||||
|
||||
if (requestProxyAuth) {
|
||||
response.setStatusLine("1.0", 407, "Proxy authentication required");
|
||||
for (i = 0; i < authHeaderCount; ++i)
|
||||
response.setHeader("Proxy-Authenticate", "basic realm=\"" + proxy_realm + "\"", true);
|
||||
} else if (requestAuth) {
|
||||
response.setStatusLine("1.0", 401, "Authentication required");
|
||||
for (i = 0; i < authHeaderCount; ++i)
|
||||
response.setHeader("WWW-Authenticate", "basic realm=\"" + realm + "\"", true);
|
||||
if (anonymous) {
|
||||
if (authPresent) {
|
||||
response.setStatusLine("1.0", 400, "Unexpected authorization header found");
|
||||
} else {
|
||||
response.setStatusLine("1.0", 200, "Authorization header not found");
|
||||
}
|
||||
} else {
|
||||
response.setStatusLine("1.0", 200, "OK");
|
||||
if (requestProxyAuth) {
|
||||
response.setStatusLine("1.0", 407, "Proxy authentication required");
|
||||
for (i = 0; i < authHeaderCount; ++i)
|
||||
response.setHeader("Proxy-Authenticate", "basic realm=\"" + proxy_realm + "\"", true);
|
||||
} else if (requestAuth) {
|
||||
response.setStatusLine("1.0", 401, "Authentication required");
|
||||
for (i = 0; i < authHeaderCount; ++i)
|
||||
response.setHeader("WWW-Authenticate", "basic realm=\"" + realm + "\"", true);
|
||||
} else {
|
||||
response.setStatusLine("1.0", 200, "OK");
|
||||
}
|
||||
}
|
||||
|
||||
response.setHeader("Content-Type", "application/xhtml+xml", false);
|
||||
|
@ -28,14 +28,18 @@ function test() {
|
||||
executeSoon(function () {
|
||||
let consoleListener = {
|
||||
observe: function (m) {
|
||||
info("m: " + m + "\n");
|
||||
info("m.message: " + m.message + "\n");
|
||||
if (m.message.indexOf("NS_ERROR_DOM_BAD_URI") > -1) {
|
||||
Services.console.unregisterListener(consoleListener);
|
||||
ok(true, "drop was blocked");
|
||||
executeSoon(finish);
|
||||
}
|
||||
}
|
||||
}
|
||||
Services.console.registerListener(consoleListener);
|
||||
registerCleanupFunction(function () {
|
||||
Services.console.unregisterListener(consoleListener);
|
||||
});
|
||||
|
||||
// The drop handler throws an exception when dragging URIs that inherit
|
||||
// principal, e.g. javascript:
|
||||
|
@ -43,37 +43,41 @@ function testSelectLine() {
|
||||
ok(gDebugger.editor.getText().search(/debugger/) != -1,
|
||||
"The correct script was loaded initially.");
|
||||
|
||||
// getCaretPosition is 0-based.
|
||||
is(gDebugger.editor.getCaretPosition().line, 5,
|
||||
"The correct line is selected.");
|
||||
// Yield control back to the event loop so that the debugger has a
|
||||
// chance to highlight the proper line.
|
||||
executeSoon(function(){
|
||||
// getCaretPosition is 0-based.
|
||||
is(gDebugger.editor.getCaretPosition().line, 5,
|
||||
"The correct line is selected.");
|
||||
|
||||
gDebugger.editor.addEventListener(SourceEditor.EVENTS.TEXT_CHANGED,
|
||||
function onChange() {
|
||||
gDebugger.editor.removeEventListener(SourceEditor.EVENTS.TEXT_CHANGED,
|
||||
onChange);
|
||||
ok(gDebugger.editor.getText().search(/debugger/) == -1,
|
||||
"The second script is no longer displayed.");
|
||||
gDebugger.editor.addEventListener(SourceEditor.EVENTS.TEXT_CHANGED,
|
||||
function onChange() {
|
||||
gDebugger.editor.removeEventListener(SourceEditor.EVENTS.TEXT_CHANGED,
|
||||
onChange);
|
||||
ok(gDebugger.editor.getText().search(/debugger/) == -1,
|
||||
"The second script is no longer displayed.");
|
||||
|
||||
ok(gDebugger.editor.getText().search(/firstCall/) != -1,
|
||||
"The first script is displayed.");
|
||||
ok(gDebugger.editor.getText().search(/firstCall/) != -1,
|
||||
"The first script is displayed.");
|
||||
|
||||
// Yield control back to the event loop so that the debugger has a
|
||||
// chance to highlight the proper line.
|
||||
executeSoon(function(){
|
||||
// getCaretPosition is 0-based.
|
||||
is(gDebugger.editor.getCaretPosition().line, 4,
|
||||
"The correct line is selected.");
|
||||
// Yield control back to the event loop so that the debugger has a
|
||||
// chance to highlight the proper line.
|
||||
executeSoon(function(){
|
||||
// getCaretPosition is 0-based.
|
||||
is(gDebugger.editor.getCaretPosition().line, 4,
|
||||
"The correct line is selected.");
|
||||
|
||||
gDebugger.StackFrames.activeThread.resume(function() {
|
||||
removeTab(gTab);
|
||||
finish();
|
||||
gDebugger.StackFrames.activeThread.resume(function() {
|
||||
removeTab(gTab);
|
||||
finish();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// Click the oldest stack frame.
|
||||
let element = gDebugger.document.getElementById("stackframe-3");
|
||||
EventUtils.synthesizeMouseAtCenter(element, {}, gDebugger);
|
||||
// Click the oldest stack frame.
|
||||
let element = gDebugger.document.getElementById("stackframe-3");
|
||||
EventUtils.synthesizeMouseAtCenter(element, {}, gDebugger);
|
||||
});
|
||||
}}, 0);
|
||||
});
|
||||
|
||||
|
@ -150,6 +150,9 @@
|
||||
@BINPATH@/components/dom_system_b2g.xpt
|
||||
#endif
|
||||
@BINPATH@/components/dom_battery.xpt
|
||||
#ifdef MOZ_B2G_BT
|
||||
@BINPATH@/components/dom_bluetooth.xpt
|
||||
#endif
|
||||
@BINPATH@/components/dom_canvas.xpt
|
||||
@BINPATH@/components/dom_core.xpt
|
||||
@BINPATH@/components/dom_css.xpt
|
||||
@ -398,6 +401,8 @@
|
||||
#endif
|
||||
@BINPATH@/components/TelemetryPing.js
|
||||
@BINPATH@/components/TelemetryPing.manifest
|
||||
@BINPATH@/components/messageWakeupService.js
|
||||
@BINPATH@/components/messageWakeupService.manifest
|
||||
|
||||
; Modules
|
||||
@BINPATH@/modules/*
|
||||
|
@ -1,15 +0,0 @@
|
||||
<Param name="q" value="{searchTerms}"/>
|
||||
<Param name="ie" value="utf-8"/>
|
||||
<Param name="oe" value="utf-8"/>
|
||||
<Param name="aq" value="t"/>
|
||||
<!-- Dynamic parameters -->
|
||||
<Param name="rls" value="{moz:distributionID}:{moz:locale}:{moz:official}"/>
|
||||
#if MOZ_UPDATE_CHANNEL == beta
|
||||
<MozParam name="client" condition="defaultEngine" trueValue="firefox-beta" falseValue="firefox"/>
|
||||
#elif MOZ_UPDATE_CHANNEL == aurora
|
||||
<MozParam name="client" condition="defaultEngine" trueValue="firefox-aurora" falseValue="firefox"/>
|
||||
#elif MOZ_UPDATE_CHANNEL == nightly
|
||||
<MozParam name="client" condition="defaultEngine" trueValue="firefox-nightly" falseValue="firefox"/>
|
||||
#else
|
||||
<MozParam name="client" condition="defaultEngine" trueValue="firefox-a" falseValue="firefox"/>
|
||||
#endif
|
@ -1,3 +1,13 @@
|
||||
#define GOOGLE_PARAMS <Param name="q" value="{searchTerms}"/><Param name="ie" value="utf-8"/><Param name="oe" value="utf-8"/><Param name="aq" value="t"/><Param name="rls" value="{moz:distributionID}:{moz:locale}:{moz:official}"/>
|
||||
#if MOZ_UPDATE_CHANNEL == beta
|
||||
#define GOOGLE_CLIENT_PARAM <MozParam name="client" condition="defaultEngine" trueValue="firefox-beta" falseValue="firefox"/>
|
||||
#elif MOZ_UPDATE_CHANNEL == aurora
|
||||
#define GOOGLE_CLIENT_PARAM <MozParam name="client" condition="defaultEngine" trueValue="firefox-aurora" falseValue="firefox"/>
|
||||
#elif MOZ_UPDATE_CHANNEL == nightly
|
||||
#define GOOGLE_CLIENT_PARAM <MozParam name="client" condition="defaultEngine" trueValue="firefox-nightly" falseValue="firefox"/>
|
||||
#else
|
||||
#define GOOGLE_CLIENT_PARAM <MozParam name="client" condition="defaultEngine" trueValue="firefox-a" falseValue="firefox"/>
|
||||
#endif
|
||||
<SearchPlugin xmlns="http://www.mozilla.org/2006/browser/search/">
|
||||
<ShortName>Google</ShortName>
|
||||
<Description>Google Search</Description>
|
||||
@ -5,16 +15,19 @@
|
||||
<Image width="16" height="16">data:image/png;base64,AAABAAEAEBAAAAEAGABoAwAAFgAAACgAAAAQAAAAIAAAAAEAGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADs9Pt8xetPtu9FsfFNtu%2BTzvb2%2B%2Fne4dFJeBw0egA%2FfAJAfAA8ewBBegAAAAD%2B%2FPtft98Mp%2BwWsfAVsvEbs%2FQeqvF8xO7%2F%2F%2F63yqkxdgM7gwE%2FggM%2BfQA%2BegBDeQDe7PIbotgQufcMufEPtfIPsvAbs%2FQvq%2Bfz%2Bf%2F%2B%2B%2FZKhR05hgBBhQI8hgBAgAI9ewD0%2B%2Fg3pswAtO8Cxf4Kw%2FsJvvYAqupKsNv%2B%2Fv7%2F%2FP5VkSU0iQA7jQA9hgBDgQU%2BfQH%2F%2Ff%2FQ6fM4sM4KsN8AteMCruIqqdbZ7PH8%2Fv%2Fg6Nc%2Fhg05kAA8jAM9iQI%2BhQA%2BgQDQu6b97uv%2F%2F%2F7V8Pqw3eiWz97q8%2Ff%2F%2F%2F%2F7%2FPptpkkqjQE4kwA7kAA5iwI8iAA8hQCOSSKdXjiyflbAkG7u2s%2F%2B%2F%2F39%2F%2F7r8utrqEYtjQE8lgA7kwA7kwA9jwA9igA9hACiWSekVRyeSgiYSBHx6N%2F%2B%2Fv7k7OFRmiYtlAA5lwI7lwI4lAA7kgI9jwE9iwI4iQCoVhWcTxCmb0K%2BooT8%2Fv%2F7%2F%2F%2FJ2r8fdwI1mwA3mQA3mgA8lAE8lAE4jwA9iwE%2BhwGfXifWvqz%2B%2Ff%2F58u%2Fev6Dt4tr%2B%2F%2F2ZuIUsggA7mgM6mAM3lgA5lgA6kQE%2FkwBChwHt4dv%2F%2F%2F728ei1bCi7VAC5XQ7kz7n%2F%2F%2F6bsZkgcB03lQA9lgM7kwA2iQktZToPK4r9%2F%2F%2F9%2F%2F%2FSqYK5UwDKZAS9WALIkFn%2B%2F%2F3%2F%2BP8oKccGGcIRJrERILYFEMwAAuEAAdX%2F%2Ff7%2F%2FP%2B%2BfDvGXQLIZgLEWgLOjlf7%2F%2F%2F%2F%2F%2F9QU90EAPQAAf8DAP0AAfMAAOUDAtr%2F%2F%2F%2F7%2B%2Fu2bCTIYwDPZgDBWQDSr4P%2F%2Fv%2F%2F%2FP5GRuABAPkAA%2FwBAfkDAPAAAesAAN%2F%2F%2B%2Fz%2F%2F%2F64g1C5VwDMYwK8Yg7y5tz8%2Fv%2FV1PYKDOcAAP0DAf4AAf0AAfYEAOwAAuAAAAD%2F%2FPvi28ymXyChTATRrIb8%2F%2F3v8fk6P8MAAdUCAvoAAP0CAP0AAfYAAO4AAACAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAQAA</Image>
|
||||
<Url type="application/x-suggestions+json" method="GET" template="http://suggestqueries.google.com/complete/search?output=firefox&client=firefox&hl={moz:locale}&q={searchTerms}"/>
|
||||
<Url type="text/html" method="GET" template="http://www.google.com/search">
|
||||
#include google-params.inc
|
||||
#expand __GOOGLE_PARAMS__
|
||||
#expand __GOOGLE_CLIENT_PARAM__
|
||||
</Url>
|
||||
<!-- Keyword search URL is the same as the default, but with an additional parameter -->
|
||||
<Url type="application/x-moz-keywordsearch" method="GET" template="http://www.google.com/search">
|
||||
#include google-params.inc
|
||||
#expand __GOOGLE_PARAMS__
|
||||
#expand __GOOGLE_CLIENT_PARAM__
|
||||
<Param name="channel" value="fflb"/>
|
||||
</Url>
|
||||
<!-- Context/Right-click search URL is the same as the default, but with an additional parameter -->
|
||||
<Url type="application/x-moz-contextsearch" method="GET" template="http://www.google.com/search">
|
||||
#include google-params.inc
|
||||
#expand __GOOGLE_PARAMS__
|
||||
#expand __GOOGLE_CLIENT_PARAM__
|
||||
<Param name="channel" value="rcs"/>
|
||||
</Url>
|
||||
<SearchForm>http://www.google.com/</SearchForm>
|
||||
|
@ -41,43 +41,55 @@ package @ANDROID_PACKAGE_NAME@;
|
||||
import java.util.List;
|
||||
|
||||
public interface Actions {
|
||||
public enum SpecialKey {
|
||||
DOWN, UP, LEFT, RIGHT, ENTER, MENU, BACK
|
||||
}
|
||||
|
||||
public interface EventExpecter {
|
||||
/** Blocks until the event has been received. Subsequent calls will return immediately. */
|
||||
public void blockForEvent();
|
||||
/** Polls to see if the event has been received. Once this returns true, subsequent calls will also return true. */
|
||||
public boolean eventReceived();
|
||||
}
|
||||
/** Special keys supported by sendSpecialKey() */
|
||||
public enum SpecialKey {
|
||||
DOWN, UP, LEFT, RIGHT, ENTER, MENU, BACK
|
||||
}
|
||||
|
||||
public interface RepeatedEventExpecter extends EventExpecter {
|
||||
/** Blocks until at least one event has been received, and no events have been received in the last <code>millis</code> milliseconds. */
|
||||
public void blockUntilClear(long millis);
|
||||
}
|
||||
public interface EventExpecter {
|
||||
/** Blocks until the event has been received. Subsequent calls will return immediately. */
|
||||
public void blockForEvent();
|
||||
|
||||
/**
|
||||
* Listens for a gecko event to be sent from the Gecko instance.
|
||||
* The returned object can be used to test if the event has been
|
||||
* received. Note that only one event is listened for.
|
||||
*
|
||||
* @param geckoEvent The geckoEvent JSONObject's type
|
||||
*/
|
||||
EventExpecter expectGeckoEvent(String geckoEvent);
|
||||
/** Polls to see if the event has been received. Once this returns true, subsequent calls will also return true. */
|
||||
public boolean eventReceived();
|
||||
}
|
||||
|
||||
/**
|
||||
* Listens for a paint event. Note that calling expectPaint() will
|
||||
* invalidate the event expecters returned from any previous calls
|
||||
* to expectPaint(); calling any methods on those invalidated objects
|
||||
* will result in undefined behaviour.
|
||||
*/
|
||||
RepeatedEventExpecter expectPaint();
|
||||
public interface RepeatedEventExpecter extends EventExpecter {
|
||||
/** Blocks until at least one event has been received, and no events have been received in the last <code>millis</code> milliseconds. */
|
||||
public void blockUntilClear(long millis);
|
||||
}
|
||||
|
||||
// Send the string kewsToSend to the application
|
||||
void sendKeys(String keysToSend);
|
||||
//Send any of the above keys to the element
|
||||
void sendSpecialKey(SpecialKey button);
|
||||
/**
|
||||
* Listens for a gecko event to be sent from the Gecko instance.
|
||||
* The returned object can be used to test if the event has been
|
||||
* received. Note that only one event is listened for.
|
||||
*
|
||||
* @param geckoEvent The geckoEvent JSONObject's type
|
||||
*/
|
||||
EventExpecter expectGeckoEvent(String geckoEvent);
|
||||
|
||||
void drag(int startingX, int endingX, int startingY, int endingY);
|
||||
/**
|
||||
* Listens for a paint event. Note that calling expectPaint() will
|
||||
* invalidate the event expecters returned from any previous calls
|
||||
* to expectPaint(); calling any methods on those invalidated objects
|
||||
* will result in undefined behaviour.
|
||||
*/
|
||||
RepeatedEventExpecter expectPaint();
|
||||
|
||||
/**
|
||||
* Send a string to the application
|
||||
*
|
||||
* @param keysToSend The string to send
|
||||
*/
|
||||
void sendKeys(String keysToSend);
|
||||
|
||||
/**
|
||||
* Send a special keycode to the element
|
||||
*
|
||||
* @param key The special key to send
|
||||
*/
|
||||
void sendSpecialKey(SpecialKey key);
|
||||
|
||||
void drag(int startingX, int endingX, int startingY, int endingY);
|
||||
}
|
||||
|
@ -40,19 +40,19 @@
|
||||
package @ANDROID_PACKAGE_NAME@;
|
||||
|
||||
public interface Assert {
|
||||
void dumpLog(String message);
|
||||
void setLogFile(String filename);
|
||||
void setTestName(String testName);
|
||||
void dumpLog(String message);
|
||||
void setLogFile(String filename);
|
||||
void setTestName(String testName);
|
||||
|
||||
void finalize();
|
||||
void ok(boolean condition, String name, String diag);
|
||||
void is(Object a, Object b, String name);
|
||||
void isnot(Object a, Object b, String name);
|
||||
void todo(boolean condition, String name, String diag);
|
||||
void todo_is(Object a, Object b, String name);
|
||||
void todo_isnot(Object a, Object b, String name);
|
||||
void info(String name, String message);
|
||||
void finalize();
|
||||
void ok(boolean condition, String name, String diag);
|
||||
void is(Object a, Object b, String name);
|
||||
void isnot(Object a, Object b, String name);
|
||||
void todo(boolean condition, String name, String diag);
|
||||
void todo_is(Object a, Object b, String name);
|
||||
void todo_isnot(Object a, Object b, String name);
|
||||
void info(String name, String message);
|
||||
|
||||
// robocop-specific asserts
|
||||
void ispixel(int actual, int r, int g, int b, String name);
|
||||
// robocop-specific asserts
|
||||
void ispixel(int actual, int r, int g, int b, String name);
|
||||
}
|
||||
|
@ -43,39 +43,39 @@ import java.util.List;
|
||||
import android.app.Activity;
|
||||
|
||||
public interface Driver {
|
||||
/**
|
||||
* Find the first Element using the given method.
|
||||
*
|
||||
* @param activity The activity the element belongs to
|
||||
* @param name The name of the element
|
||||
* @return The first matching element on the current context
|
||||
* @throws RoboCopException If no matching elements are found
|
||||
*/
|
||||
Element findElement(Activity activity, String name);
|
||||
/**
|
||||
* Find the first Element using the given method.
|
||||
*
|
||||
* @param activity The activity the element belongs to
|
||||
* @param name The name of the element
|
||||
* @return The first matching element on the current context
|
||||
* @throws RoboCopException If no matching elements are found
|
||||
*/
|
||||
Element findElement(Activity activity, String name);
|
||||
|
||||
/**
|
||||
* Sets up scroll handling so that data is received from the extension.
|
||||
*/
|
||||
void setupScrollHandling();
|
||||
/**
|
||||
* Sets up scroll handling so that data is received from the extension.
|
||||
*/
|
||||
void setupScrollHandling();
|
||||
|
||||
int getPageHeight();
|
||||
int getScrollHeight();
|
||||
int getHeight();
|
||||
int getGeckoTop();
|
||||
int getGeckoLeft();
|
||||
int getGeckoWidth();
|
||||
int getGeckoHeight();
|
||||
int getPageHeight();
|
||||
int getScrollHeight();
|
||||
int getHeight();
|
||||
int getGeckoTop();
|
||||
int getGeckoLeft();
|
||||
int getGeckoWidth();
|
||||
int getGeckoHeight();
|
||||
|
||||
void startFrameRecording();
|
||||
int stopFrameRecording();
|
||||
void startFrameRecording();
|
||||
int stopFrameRecording();
|
||||
|
||||
void startCheckerboardRecording();
|
||||
float stopCheckerboardRecording();
|
||||
void startCheckerboardRecording();
|
||||
float stopCheckerboardRecording();
|
||||
|
||||
/**
|
||||
* Get a copy of the painted content region.
|
||||
* @return A 2-D array of pixels (indexed by y, then x). The pixels
|
||||
* are in ARGB-8888 format.
|
||||
*/
|
||||
int[][] getPaintedSurface();
|
||||
/**
|
||||
* Get a copy of the painted content region.
|
||||
* @return A 2-D array of pixels (indexed by y, then x). The pixels
|
||||
* are in ARGB-8888 format.
|
||||
*/
|
||||
int[][] getPaintedSurface();
|
||||
}
|
||||
|
@ -39,13 +39,21 @@
|
||||
|
||||
package @ANDROID_PACKAGE_NAME@;
|
||||
|
||||
/**
|
||||
* Element provides access to a specific UI view (android.view.View).
|
||||
* See also Driver.findElement().
|
||||
*/
|
||||
public interface Element {
|
||||
//Click on the element
|
||||
void click();
|
||||
//Returns true if the element is currently displayed
|
||||
boolean isDisplayed();
|
||||
//Returns the text currently displayed on the element.
|
||||
String getText();
|
||||
//Returns view ID.
|
||||
Integer getId();
|
||||
|
||||
/** Click on the element */
|
||||
void click();
|
||||
|
||||
/** Returns true if the element is currently displayed */
|
||||
boolean isDisplayed();
|
||||
|
||||
/** Returns the text currently displayed on the element */
|
||||
String getText();
|
||||
|
||||
/** Returns the view ID */
|
||||
Integer getId();
|
||||
}
|
||||
|
@ -38,202 +38,194 @@
|
||||
package @ANDROID_PACKAGE_NAME@;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Date;
|
||||
import android.os.SystemClock;
|
||||
|
||||
public class FennecMochitestAssert implements Assert {
|
||||
// Objects for reflexive access of fennec classes.
|
||||
private LinkedList<testInfo> mTestList = new LinkedList<testInfo>();
|
||||
|
||||
private LinkedList<testInfo> testList = new LinkedList<testInfo>();
|
||||
// Internal state variables to make logging match up with existing mochitests
|
||||
private int mLineNumber = 0;
|
||||
private int mPassed = 0;
|
||||
private int mFailed = 0;
|
||||
private int mTodo = 0;
|
||||
|
||||
// Used to write the first line of the test file
|
||||
private boolean mLogStarted = false;
|
||||
|
||||
// Internal state variables to make logging match up with existing mochitests
|
||||
private int lineNumber = 0;
|
||||
private int passed = 0;
|
||||
private int failed = 0;
|
||||
private int todo = 0;
|
||||
|
||||
// Used to write the first line of the test file
|
||||
private boolean logStarted = false;
|
||||
// Used to write the test-start/test-end log lines
|
||||
private String mLogTestName = "";
|
||||
|
||||
// Used to write the test-start/test-end log lines
|
||||
private String logTestName = "";
|
||||
// Measure the time it takes to run test case
|
||||
private long mStartTime = 0;
|
||||
|
||||
// Measure the time it takes to run test case
|
||||
private long startTime = 0;
|
||||
|
||||
public FennecMochitestAssert() {
|
||||
}
|
||||
|
||||
// Write information to a logfile and logcat
|
||||
public void dumpLog(String message)
|
||||
{
|
||||
FennecNativeDriver.log(FennecNativeDriver.LogLevel.LOG_LEVEL_INFO, message);
|
||||
}
|
||||
|
||||
// Set the filename used for dumpLog.
|
||||
public void setLogFile(String filename)
|
||||
{
|
||||
FennecNativeDriver.setLogFile(filename);
|
||||
|
||||
String message;
|
||||
if (!logStarted) {
|
||||
dumpLog(Integer.toString(lineNumber++) + " INFO SimpleTest START");
|
||||
logStarted = true;
|
||||
public FennecMochitestAssert() {
|
||||
}
|
||||
|
||||
if (logTestName != "") {
|
||||
long diff = (new Date().getTime()) - startTime;
|
||||
message = Integer.toString(lineNumber++) + " INFO TEST-END | " + logTestName;
|
||||
message += " | finished in " + diff + "ms";
|
||||
dumpLog(message);
|
||||
logTestName = "";
|
||||
}
|
||||
}
|
||||
|
||||
public void setTestName(String testName)
|
||||
{
|
||||
String[] nameParts = testName.split("\\.");
|
||||
logTestName = nameParts[nameParts.length - 1];
|
||||
startTime = new Date().getTime();
|
||||
|
||||
dumpLog(Integer.toString(lineNumber++) + " INFO TEST-START | " + logTestName);
|
||||
}
|
||||
|
||||
class testInfo {
|
||||
public boolean result;
|
||||
public String name;
|
||||
public String diag;
|
||||
public boolean todo;
|
||||
public testInfo(boolean r, String n, String d, boolean t) {
|
||||
result = r;
|
||||
name = n;
|
||||
diag = d;
|
||||
todo = t;
|
||||
/** Write information to a logfile and logcat */
|
||||
public void dumpLog(String message) {
|
||||
FennecNativeDriver.log(FennecNativeDriver.LogLevel.LOG_LEVEL_INFO, message);
|
||||
}
|
||||
|
||||
}
|
||||
/** Set the filename used for dumpLog. */
|
||||
public void setLogFile(String filename) {
|
||||
FennecNativeDriver.setLogFile(filename);
|
||||
|
||||
private void _logMochitestResult(testInfo test, String passString, String failString)
|
||||
{
|
||||
boolean isError = true;
|
||||
String resultString = failString;
|
||||
if (test.result || test.todo) {
|
||||
isError = false;
|
||||
}
|
||||
if (test.result)
|
||||
{
|
||||
resultString = passString;
|
||||
}
|
||||
String diag = test.name;
|
||||
if (test.diag != null) diag += " - " + test.diag;
|
||||
String message;
|
||||
if (!mLogStarted) {
|
||||
dumpLog(Integer.toString(mLineNumber++) + " INFO SimpleTest START");
|
||||
mLogStarted = true;
|
||||
}
|
||||
|
||||
String message = Integer.toString(lineNumber++) + " INFO " + resultString + " | " + logTestName + " | " + diag;
|
||||
dumpLog(message);
|
||||
|
||||
if (test.todo) {
|
||||
todo++;
|
||||
} else if (isError) {
|
||||
failed++;
|
||||
} else {
|
||||
passed++;
|
||||
}
|
||||
if (isError) {
|
||||
junit.framework.Assert.fail(message);
|
||||
}
|
||||
}
|
||||
|
||||
public void finalize()
|
||||
{
|
||||
// It appears that we call finalize during cleanup, this might be an invalid assertion.
|
||||
String message;
|
||||
|
||||
if (logTestName != "") {
|
||||
long diff = (new Date().getTime()) - startTime;
|
||||
message = Integer.toString(lineNumber++) + " INFO TEST-END | " + logTestName;
|
||||
message += " | finished in " + diff + "ms";
|
||||
dumpLog(message);
|
||||
logTestName = "";
|
||||
if (mLogTestName != "") {
|
||||
long diff = SystemClock.uptimeMillis() - mStartTime;
|
||||
message = Integer.toString(mLineNumber++) + " INFO TEST-END | " + mLogTestName;
|
||||
message += " | finished in " + diff + "ms";
|
||||
dumpLog(message);
|
||||
mLogTestName = "";
|
||||
}
|
||||
}
|
||||
|
||||
message = Integer.toString(lineNumber++) + " INFO TEST-START | Shutdown";
|
||||
dumpLog(message);
|
||||
message = Integer.toString(lineNumber++) + " INFO Passed: " + Integer.toString(passed);
|
||||
dumpLog(message);
|
||||
message = Integer.toString(lineNumber++) + " INFO Failed: " + Integer.toString(failed);
|
||||
dumpLog(message);
|
||||
message = Integer.toString(lineNumber++) + " INFO Todo: " + Integer.toString(todo);
|
||||
dumpLog(message);
|
||||
message = Integer.toString(lineNumber++) + " INFO SimpleTest FINISHED";
|
||||
dumpLog(message);
|
||||
}
|
||||
public void setTestName(String testName) {
|
||||
String[] nameParts = testName.split("\\.");
|
||||
mLogTestName = nameParts[nameParts.length - 1];
|
||||
mStartTime = SystemClock.uptimeMillis();
|
||||
|
||||
public void ok(boolean condition, String name, String diag) {
|
||||
testInfo test = new testInfo(condition, name, diag, false);
|
||||
_logMochitestResult(test, "TEST-PASS", "TEST-UNEXPECTED-FAIL");
|
||||
testList.add(test);
|
||||
}
|
||||
|
||||
public void is(Object a, Object b, String name) {
|
||||
boolean pass = a.equals(b);
|
||||
String diag = "got " + a.toString() + ", expected " + b.toString();
|
||||
if(pass) {
|
||||
diag = a.toString() + " should equal " + b.toString();
|
||||
dumpLog(Integer.toString(mLineNumber++) + " INFO TEST-START | " + mLogTestName);
|
||||
}
|
||||
ok(pass, name, diag);
|
||||
}
|
||||
|
||||
public void isnot(Object a, Object b, String name) {
|
||||
boolean pass = !a.equals(b);
|
||||
String diag = "didn't expect " + a.toString() + ", but got it";
|
||||
if(pass) {
|
||||
diag = a.toString() + " should not equal " + b.toString();
|
||||
|
||||
class testInfo {
|
||||
public boolean mResult;
|
||||
public String mName;
|
||||
public String mDiag;
|
||||
public boolean mTodo;
|
||||
public testInfo(boolean r, String n, String d, boolean t) {
|
||||
mResult = r;
|
||||
mName = n;
|
||||
mDiag = d;
|
||||
mTodo = t;
|
||||
}
|
||||
|
||||
}
|
||||
ok(pass, name, diag);
|
||||
}
|
||||
|
||||
public void ispixel(int actual, int r, int g, int b, String name) {
|
||||
// When we read GL pixels the GPU has already processed them and they
|
||||
// are usually off by a little bit. For example a CSS-color pixel of color #64FFF5
|
||||
// was turned into #63FFF7 when it came out of glReadPixels. So in order to compare
|
||||
// against the expected value, we use a little fuzz factor. For the alpha we just
|
||||
// make sure it is always 0xFF.
|
||||
int aAlpha = ((actual >> 24) & 0xFF);
|
||||
int aR = ((actual >> 16) & 0xFF);
|
||||
int aG = ((actual >> 8) & 0xFF);
|
||||
int aB = (actual & 0xFF);
|
||||
boolean pass = (aAlpha == 0xFF) /* alpha */
|
||||
&& (Math.abs(aR - r) < 8) /* red */
|
||||
&& (Math.abs(aG - g) < 8) /* green */
|
||||
&& (Math.abs(aB - b) < 8); /* blue */
|
||||
ok(pass, name, "Color rgba(" + aR + "," + aG + "," + aB + "," + aAlpha + ")" + (pass ? " " : " not") + " close enough to expected rgb(" + r + "," + g + "," + b + ")");
|
||||
}
|
||||
private void _logMochitestResult(testInfo test, String passString, String failString) {
|
||||
boolean isError = true;
|
||||
String resultString = failString;
|
||||
if (test.mResult || test.mTodo) {
|
||||
isError = false;
|
||||
}
|
||||
if (test.mResult)
|
||||
{
|
||||
resultString = passString;
|
||||
}
|
||||
String diag = test.mName;
|
||||
if (test.mDiag != null) diag += " - " + test.mDiag;
|
||||
|
||||
public void todo(boolean condition, String name, String diag) {
|
||||
testInfo test = new testInfo(condition, name, diag, true);
|
||||
_logMochitestResult(test, "TEST-UNEXPECTED-PASS", "TEST-KNOWN-FAIL");
|
||||
testList.add(test);
|
||||
}
|
||||
String message = Integer.toString(mLineNumber++) + " INFO " + resultString + " | " + mLogTestName + " | " + diag;
|
||||
dumpLog(message);
|
||||
|
||||
public void todo_is(Object a, Object b, String name) {
|
||||
boolean pass = a.equals(b);
|
||||
String diag = "got " + a.toString() + ", expected " + b.toString();
|
||||
if(pass) {
|
||||
diag = a.toString() + " should equal " + b.toString();
|
||||
if (test.mTodo) {
|
||||
mTodo++;
|
||||
} else if (isError) {
|
||||
mFailed++;
|
||||
} else {
|
||||
mPassed++;
|
||||
}
|
||||
if (isError) {
|
||||
junit.framework.Assert.fail(message);
|
||||
}
|
||||
}
|
||||
todo(pass, name, diag);
|
||||
}
|
||||
|
||||
public void todo_isnot(Object a, Object b, String name) {
|
||||
boolean pass = !a.equals(b);
|
||||
String diag = "didn't expect " + a.toString() + ", but got it";
|
||||
if(pass) {
|
||||
diag = a.toString() + " should not equal " + b.toString();
|
||||
}
|
||||
todo(pass, name, diag);
|
||||
}
|
||||
|
||||
public void info(String name, String message) {
|
||||
testInfo test = new testInfo(true, name, message, false);
|
||||
_logMochitestResult(test, "TEST-INFO", "INFO FAILED?");
|
||||
}
|
||||
public void finalize() {
|
||||
// It appears that we call finalize during cleanup, this might be an invalid assertion.
|
||||
String message;
|
||||
|
||||
if (mLogTestName != "") {
|
||||
long diff = SystemClock.uptimeMillis() - mStartTime;
|
||||
message = Integer.toString(mLineNumber++) + " INFO TEST-END | " + mLogTestName;
|
||||
message += " | finished in " + diff + "ms";
|
||||
dumpLog(message);
|
||||
mLogTestName = "";
|
||||
}
|
||||
|
||||
message = Integer.toString(mLineNumber++) + " INFO TEST-START | Shutdown";
|
||||
dumpLog(message);
|
||||
message = Integer.toString(mLineNumber++) + " INFO Passed: " + Integer.toString(mPassed);
|
||||
dumpLog(message);
|
||||
message = Integer.toString(mLineNumber++) + " INFO Failed: " + Integer.toString(mFailed);
|
||||
dumpLog(message);
|
||||
message = Integer.toString(mLineNumber++) + " INFO Todo: " + Integer.toString(mTodo);
|
||||
dumpLog(message);
|
||||
message = Integer.toString(mLineNumber++) + " INFO SimpleTest FINISHED";
|
||||
dumpLog(message);
|
||||
}
|
||||
|
||||
public void ok(boolean condition, String name, String diag) {
|
||||
testInfo test = new testInfo(condition, name, diag, false);
|
||||
_logMochitestResult(test, "TEST-PASS", "TEST-UNEXPECTED-FAIL");
|
||||
mTestList.add(test);
|
||||
}
|
||||
|
||||
public void is(Object a, Object b, String name) {
|
||||
boolean pass = a.equals(b);
|
||||
String diag = "got " + a.toString() + ", expected " + b.toString();
|
||||
if (pass) {
|
||||
diag = a.toString() + " should equal " + b.toString();
|
||||
}
|
||||
ok(pass, name, diag);
|
||||
}
|
||||
|
||||
public void isnot(Object a, Object b, String name) {
|
||||
boolean pass = !a.equals(b);
|
||||
String diag = "didn't expect " + a.toString() + ", but got it";
|
||||
if (pass) {
|
||||
diag = a.toString() + " should not equal " + b.toString();
|
||||
}
|
||||
ok(pass, name, diag);
|
||||
}
|
||||
|
||||
public void ispixel(int actual, int r, int g, int b, String name) {
|
||||
// When we read GL pixels the GPU has already processed them and they
|
||||
// are usually off by a little bit. For example a CSS-color pixel of color #64FFF5
|
||||
// was turned into #63FFF7 when it came out of glReadPixels. So in order to compare
|
||||
// against the expected value, we use a little fuzz factor. For the alpha we just
|
||||
// make sure it is always 0xFF.
|
||||
int aAlpha = ((actual >> 24) & 0xFF);
|
||||
int aR = ((actual >> 16) & 0xFF);
|
||||
int aG = ((actual >> 8) & 0xFF);
|
||||
int aB = (actual & 0xFF);
|
||||
boolean pass = (aAlpha == 0xFF) /* alpha */
|
||||
&& (Math.abs(aR - r) < 8) /* red */
|
||||
&& (Math.abs(aG - g) < 8) /* green */
|
||||
&& (Math.abs(aB - b) < 8); /* blue */
|
||||
ok(pass, name, "Color rgba(" + aR + "," + aG + "," + aB + "," + aAlpha + ")" + (pass ? " " : " not") + " close enough to expected rgb(" + r + "," + g + "," + b + ")");
|
||||
}
|
||||
|
||||
public void todo(boolean condition, String name, String diag) {
|
||||
testInfo test = new testInfo(condition, name, diag, true);
|
||||
_logMochitestResult(test, "TEST-UNEXPECTED-PASS", "TEST-KNOWN-FAIL");
|
||||
mTestList.add(test);
|
||||
}
|
||||
|
||||
public void todo_is(Object a, Object b, String name) {
|
||||
boolean pass = a.equals(b);
|
||||
String diag = "got " + a.toString() + ", expected " + b.toString();
|
||||
if (pass) {
|
||||
diag = a.toString() + " should equal " + b.toString();
|
||||
}
|
||||
todo(pass, name, diag);
|
||||
}
|
||||
|
||||
public void todo_isnot(Object a, Object b, String name) {
|
||||
boolean pass = !a.equals(b);
|
||||
String diag = "didn't expect " + a.toString() + ", but got it";
|
||||
if (pass) {
|
||||
diag = a.toString() + " should not equal " + b.toString();
|
||||
}
|
||||
todo(pass, name, diag);
|
||||
}
|
||||
|
||||
public void info(String name, String message) {
|
||||
testInfo test = new testInfo(true, name, message, false);
|
||||
_logMochitestResult(test, "TEST-INFO", "INFO FAILED?");
|
||||
}
|
||||
}
|
||||
|
@ -59,295 +59,294 @@ import org.json.*;
|
||||
import com.jayway.android.robotium.solo.Solo;
|
||||
|
||||
public class FennecNativeActions implements Actions {
|
||||
private Solo solo;
|
||||
private Instrumentation instr;
|
||||
private Activity geckoApp;
|
||||
private Solo mSolo;
|
||||
private Instrumentation mInstr;
|
||||
private Activity mGeckoApp;
|
||||
|
||||
// Objects for reflexive access of fennec classes.
|
||||
private ClassLoader classLoader;
|
||||
private Class gel;
|
||||
private Class ge;
|
||||
private Class gas;
|
||||
private Class drawListener;
|
||||
private Method registerGEL;
|
||||
private Method unregisterGEL;
|
||||
private Method sendGE;
|
||||
private Method getLayerClient;
|
||||
private Method setDrawListener;
|
||||
// Objects for reflexive access of fennec classes.
|
||||
private ClassLoader mClassLoader;
|
||||
private Class mGel;
|
||||
private Class mGe;
|
||||
private Class mGas;
|
||||
private Class mDrawListener;
|
||||
private Method mRegisterGEL;
|
||||
private Method mUnregisterGEL;
|
||||
private Method mSendGE;
|
||||
private Method mGetLayerClient;
|
||||
private Method mSetDrawListener;
|
||||
|
||||
public FennecNativeActions(Activity activity, Solo robocop, Instrumentation instrumentation){
|
||||
this.solo = robocop;
|
||||
this.instr = instrumentation;
|
||||
this.geckoApp = activity;
|
||||
// Set up reflexive access of java classes and methods.
|
||||
try {
|
||||
classLoader = activity.getClassLoader();
|
||||
gel = classLoader.loadClass("org.mozilla.gecko.GeckoEventListener");
|
||||
ge = classLoader.loadClass("org.mozilla.gecko.GeckoEvent");
|
||||
gas = classLoader.loadClass("org.mozilla.gecko.GeckoAppShell");
|
||||
Class [] parameters = new Class[2];
|
||||
parameters[0] = String.class;
|
||||
parameters[1] = gel;
|
||||
registerGEL = gas.getMethod("registerGeckoEventListener", parameters);
|
||||
unregisterGEL = gas.getMethod("unregisterGeckoEventListener", parameters);
|
||||
parameters = new Class[1];
|
||||
parameters[0] = ge;
|
||||
sendGE = gas.getMethod("sendEventToGecko", parameters);
|
||||
|
||||
getLayerClient = activity.getClass().getMethod("getSoftwareLayerClient");
|
||||
Class gslc = classLoader.loadClass("org.mozilla.gecko.gfx.GeckoSoftwareLayerClient");
|
||||
drawListener = classLoader.loadClass("org.mozilla.gecko.gfx.GeckoSoftwareLayerClient$DrawListener");
|
||||
setDrawListener = gslc.getDeclaredMethod("setDrawListener", drawListener);
|
||||
} catch (ClassNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
} catch (SecurityException e) {
|
||||
e.printStackTrace();
|
||||
} catch (NoSuchMethodException e) {
|
||||
e.printStackTrace();
|
||||
} catch (IllegalArgumentException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
class wakeInvocationHandler implements InvocationHandler {
|
||||
private final GeckoEventExpecter mEventExpecter;
|
||||
|
||||
public wakeInvocationHandler(GeckoEventExpecter expecter) {
|
||||
mEventExpecter = expecter;
|
||||
}
|
||||
|
||||
public Object invoke(Object proxy, Method method, Object[] args) {
|
||||
String methodName = method.getName();
|
||||
//Depending on the method, return a completely different type.
|
||||
if(methodName.equals("toString")) {
|
||||
return "wakeInvocationHandler";
|
||||
}
|
||||
if(methodName.equals("equals")) {
|
||||
return this == args[0];
|
||||
}
|
||||
if(methodName.equals("clone")) {
|
||||
return this;
|
||||
}
|
||||
if(methodName.equals("hashCode")) {
|
||||
return 314;
|
||||
}
|
||||
FennecNativeDriver.log(FennecNativeDriver.LogLevel.LOG_LEVEL_DEBUG,
|
||||
"Waking up on "+methodName);
|
||||
mEventExpecter.notifyOfEvent();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
class GeckoEventExpecter implements EventExpecter {
|
||||
private final String mGeckoEvent;
|
||||
private final Object[] mRegistrationParams;
|
||||
private boolean mEventReceived;
|
||||
|
||||
GeckoEventExpecter(String geckoEvent, Object[] registrationParams) {
|
||||
mGeckoEvent = geckoEvent;
|
||||
mRegistrationParams = registrationParams;
|
||||
}
|
||||
|
||||
public synchronized void blockForEvent() {
|
||||
while (! mEventReceived) {
|
||||
public FennecNativeActions(Activity activity, Solo robocop, Instrumentation instrumentation) {
|
||||
mSolo = robocop;
|
||||
mInstr = instrumentation;
|
||||
mGeckoApp = activity;
|
||||
// Set up reflexive access of java classes and methods.
|
||||
try {
|
||||
this.wait();
|
||||
} catch (InterruptedException ie) {
|
||||
ie.printStackTrace();
|
||||
break;
|
||||
mClassLoader = activity.getClassLoader();
|
||||
mGel = mClassLoader.loadClass("org.mozilla.gecko.GeckoEventListener");
|
||||
mGe = mClassLoader.loadClass("org.mozilla.gecko.GeckoEvent");
|
||||
mGas = mClassLoader.loadClass("org.mozilla.gecko.GeckoAppShell");
|
||||
Class [] parameters = new Class[2];
|
||||
parameters[0] = String.class;
|
||||
parameters[1] = mGel;
|
||||
mRegisterGEL = mGas.getMethod("registerGeckoEventListener", parameters);
|
||||
mUnregisterGEL = mGas.getMethod("unregisterGeckoEventListener", parameters);
|
||||
parameters = new Class[1];
|
||||
parameters[0] = mGe;
|
||||
mSendGE = mGas.getMethod("sendEventToGecko", parameters);
|
||||
|
||||
mGetLayerClient = activity.getClass().getMethod("getSoftwareLayerClient");
|
||||
Class gslc = mClassLoader.loadClass("org.mozilla.gecko.gfx.GeckoSoftwareLayerClient");
|
||||
mDrawListener = mClassLoader.loadClass("org.mozilla.gecko.gfx.GeckoSoftwareLayerClient$DrawListener");
|
||||
mSetDrawListener = gslc.getDeclaredMethod("setDrawListener", mDrawListener);
|
||||
} catch (ClassNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
} catch (SecurityException e) {
|
||||
e.printStackTrace();
|
||||
} catch (NoSuchMethodException e) {
|
||||
e.printStackTrace();
|
||||
} catch (IllegalArgumentException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
class wakeInvocationHandler implements InvocationHandler {
|
||||
private final GeckoEventExpecter mEventExpecter;
|
||||
|
||||
public wakeInvocationHandler(GeckoEventExpecter expecter) {
|
||||
mEventExpecter = expecter;
|
||||
}
|
||||
|
||||
public Object invoke(Object proxy, Method method, Object[] args) {
|
||||
String methodName = method.getName();
|
||||
//Depending on the method, return a completely different type.
|
||||
if(methodName.equals("toString")) {
|
||||
return "wakeInvocationHandler";
|
||||
}
|
||||
if(methodName.equals("equals")) {
|
||||
return this == args[0];
|
||||
}
|
||||
if(methodName.equals("clone")) {
|
||||
return this;
|
||||
}
|
||||
if(methodName.equals("hashCode")) {
|
||||
return 314;
|
||||
}
|
||||
FennecNativeDriver.log(FennecNativeDriver.LogLevel.LOG_LEVEL_DEBUG,
|
||||
"Waking up on "+methodName);
|
||||
mEventExpecter.notifyOfEvent();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
FennecNativeDriver.log(FennecNativeDriver.LogLevel.LOG_LEVEL_DEBUG,
|
||||
"unblocked on expecter for " + mGeckoEvent);
|
||||
}
|
||||
|
||||
public synchronized boolean eventReceived() {
|
||||
return mEventReceived;
|
||||
}
|
||||
class GeckoEventExpecter implements EventExpecter {
|
||||
private final String mGeckoEvent;
|
||||
private final Object[] mRegistrationParams;
|
||||
private boolean mEventReceived;
|
||||
|
||||
void notifyOfEvent() {
|
||||
try {
|
||||
unregisterGEL.invoke(null, mRegistrationParams);
|
||||
} catch (IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
} catch (InvocationTargetException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
FennecNativeDriver.log(FennecNativeDriver.LogLevel.LOG_LEVEL_DEBUG,
|
||||
"received event " + mGeckoEvent);
|
||||
synchronized (this) {
|
||||
mEventReceived = true;
|
||||
this.notifyAll();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public EventExpecter expectGeckoEvent(String geckoEvent) {
|
||||
FennecNativeDriver.log(FennecNativeDriver.LogLevel.LOG_LEVEL_DEBUG,
|
||||
"waiting for "+geckoEvent);
|
||||
try {
|
||||
Class [] interfaces = new Class[1];
|
||||
interfaces[0] = gel;
|
||||
Object[] finalParams = new Object[2];
|
||||
finalParams[0] = geckoEvent;
|
||||
|
||||
GeckoEventExpecter expecter = new GeckoEventExpecter(geckoEvent, finalParams);
|
||||
wakeInvocationHandler wIH = new wakeInvocationHandler(expecter);
|
||||
Object proxy = Proxy.newProxyInstance(classLoader, interfaces, wIH);
|
||||
finalParams[1] = proxy;
|
||||
registerGEL.invoke(null, finalParams);
|
||||
|
||||
return expecter;
|
||||
} catch (IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
} catch (InvocationTargetException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
GeckoEventExpecter(String geckoEvent, Object[] registrationParams) {
|
||||
mGeckoEvent = geckoEvent;
|
||||
mRegistrationParams = registrationParams;
|
||||
}
|
||||
|
||||
class DrawListenerProxy implements InvocationHandler {
|
||||
private final PaintExpecter mPaintExpecter;
|
||||
public synchronized void blockForEvent() {
|
||||
while (! mEventReceived) {
|
||||
try {
|
||||
this.wait();
|
||||
} catch (InterruptedException ie) {
|
||||
ie.printStackTrace();
|
||||
break;
|
||||
}
|
||||
}
|
||||
FennecNativeDriver.log(FennecNativeDriver.LogLevel.LOG_LEVEL_DEBUG,
|
||||
"unblocked on expecter for " + mGeckoEvent);
|
||||
}
|
||||
|
||||
DrawListenerProxy(PaintExpecter paintExpecter) {
|
||||
mPaintExpecter = paintExpecter;
|
||||
public synchronized boolean eventReceived() {
|
||||
return mEventReceived;
|
||||
}
|
||||
|
||||
void notifyOfEvent() {
|
||||
try {
|
||||
mUnregisterGEL.invoke(null, mRegistrationParams);
|
||||
} catch (IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
} catch (InvocationTargetException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
FennecNativeDriver.log(FennecNativeDriver.LogLevel.LOG_LEVEL_DEBUG,
|
||||
"received event " + mGeckoEvent);
|
||||
synchronized (this) {
|
||||
mEventReceived = true;
|
||||
this.notifyAll();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Object invoke(Object proxy, Method method, Object[] args) {
|
||||
String methodName = method.getName();
|
||||
if ("drawFinished".equals(methodName)) {
|
||||
|
||||
public EventExpecter expectGeckoEvent(String geckoEvent) {
|
||||
FennecNativeDriver.log(FennecNativeDriver.LogLevel.LOG_LEVEL_DEBUG,
|
||||
"Received drawFinished notification");
|
||||
mPaintExpecter.notifyOfEvent();
|
||||
} else if ("toString".equals(methodName)) {
|
||||
return "DrawListenerProxy";
|
||||
} else if ("equals".equals(methodName)) {
|
||||
return false;
|
||||
} else if ("hashCode".equals(methodName)) {
|
||||
return 0;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
class PaintExpecter implements RepeatedEventExpecter {
|
||||
private Object mLayerClient;
|
||||
private boolean mPaintDone;
|
||||
|
||||
PaintExpecter() throws IllegalAccessException, InvocationTargetException {
|
||||
mLayerClient = getLayerClient.invoke(geckoApp);
|
||||
setDrawListener.invoke(mLayerClient, Proxy.newProxyInstance(classLoader, new Class[] { drawListener }, new DrawListenerProxy(this)));
|
||||
}
|
||||
|
||||
void notifyOfEvent() {
|
||||
synchronized (this) {
|
||||
mPaintDone = true;
|
||||
this.notifyAll();
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void blockForEvent() {
|
||||
while (! mPaintDone) {
|
||||
"waiting for "+geckoEvent);
|
||||
try {
|
||||
this.wait();
|
||||
} catch (InterruptedException ie) {
|
||||
ie.printStackTrace();
|
||||
break;
|
||||
Class [] interfaces = new Class[1];
|
||||
interfaces[0] = mGel;
|
||||
Object[] finalParams = new Object[2];
|
||||
finalParams[0] = geckoEvent;
|
||||
|
||||
GeckoEventExpecter expecter = new GeckoEventExpecter(geckoEvent, finalParams);
|
||||
wakeInvocationHandler wIH = new wakeInvocationHandler(expecter);
|
||||
Object proxy = Proxy.newProxyInstance(mClassLoader, interfaces, wIH);
|
||||
finalParams[1] = proxy;
|
||||
mRegisterGEL.invoke(null, finalParams);
|
||||
|
||||
return expecter;
|
||||
} catch (IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
} catch (InvocationTargetException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
try {
|
||||
setDrawListener.invoke(mLayerClient, (Object)null);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public synchronized boolean eventReceived() {
|
||||
return mPaintDone;
|
||||
class DrawListenerProxy implements InvocationHandler {
|
||||
private final PaintExpecter mPaintExpecter;
|
||||
|
||||
DrawListenerProxy(PaintExpecter paintExpecter) {
|
||||
mPaintExpecter = paintExpecter;
|
||||
}
|
||||
|
||||
public Object invoke(Object proxy, Method method, Object[] args) {
|
||||
String methodName = method.getName();
|
||||
if ("drawFinished".equals(methodName)) {
|
||||
FennecNativeDriver.log(FennecNativeDriver.LogLevel.LOG_LEVEL_DEBUG,
|
||||
"Received drawFinished notification");
|
||||
mPaintExpecter.notifyOfEvent();
|
||||
} else if ("toString".equals(methodName)) {
|
||||
return "DrawListenerProxy";
|
||||
} else if ("equals".equals(methodName)) {
|
||||
return false;
|
||||
} else if ("hashCode".equals(methodName)) {
|
||||
return 0;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void blockUntilClear(long millis) {
|
||||
if (millis <= 0) {
|
||||
throw new IllegalArgumentException("millis must be > 0");
|
||||
}
|
||||
// wait for at least one event
|
||||
while (! mPaintDone) {
|
||||
class PaintExpecter implements RepeatedEventExpecter {
|
||||
private Object mLayerClient;
|
||||
private boolean mPaintDone;
|
||||
|
||||
PaintExpecter() throws IllegalAccessException, InvocationTargetException {
|
||||
mLayerClient = mGetLayerClient.invoke(mGeckoApp);
|
||||
mSetDrawListener.invoke(mLayerClient, Proxy.newProxyInstance(mClassLoader, new Class[] { mDrawListener }, new DrawListenerProxy(this)));
|
||||
}
|
||||
|
||||
void notifyOfEvent() {
|
||||
synchronized (this) {
|
||||
mPaintDone = true;
|
||||
this.notifyAll();
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void blockForEvent() {
|
||||
while (!mPaintDone) {
|
||||
try {
|
||||
this.wait();
|
||||
} catch (InterruptedException ie) {
|
||||
ie.printStackTrace();
|
||||
break;
|
||||
}
|
||||
}
|
||||
try {
|
||||
mSetDrawListener.invoke(mLayerClient, (Object)null);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized boolean eventReceived() {
|
||||
return mPaintDone;
|
||||
}
|
||||
|
||||
public synchronized void blockUntilClear(long millis) {
|
||||
if (millis <= 0) {
|
||||
throw new IllegalArgumentException("millis must be > 0");
|
||||
}
|
||||
// wait for at least one event
|
||||
while (!mPaintDone) {
|
||||
try {
|
||||
this.wait();
|
||||
} catch (InterruptedException ie) {
|
||||
ie.printStackTrace();
|
||||
break;
|
||||
}
|
||||
}
|
||||
// now wait for a period of millis where we don't get an event
|
||||
long startTime = SystemClock.uptimeMillis();
|
||||
while (true) {
|
||||
try {
|
||||
this.wait(millis);
|
||||
} catch (InterruptedException ie) {
|
||||
ie.printStackTrace();
|
||||
break;
|
||||
}
|
||||
long endTime = SystemClock.uptimeMillis();
|
||||
if (endTime - startTime >= millis) {
|
||||
// success
|
||||
break;
|
||||
}
|
||||
// we got a notify() before we could wait long enough, so we need to start over
|
||||
startTime = endTime;
|
||||
}
|
||||
try {
|
||||
mSetDrawListener.invoke(mLayerClient, (Object)null);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public RepeatedEventExpecter expectPaint() {
|
||||
try {
|
||||
this.wait();
|
||||
} catch (InterruptedException ie) {
|
||||
ie.printStackTrace();
|
||||
break;
|
||||
return new PaintExpecter();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
// now wait for a period of millis where we don't get an event
|
||||
long startTime = SystemClock.uptimeMillis();
|
||||
while (true) {
|
||||
try {
|
||||
this.wait(millis);
|
||||
} catch (InterruptedException ie) {
|
||||
ie.printStackTrace();
|
||||
break;
|
||||
}
|
||||
|
||||
public void sendSpecialKey(SpecialKey button) {
|
||||
switch(button) {
|
||||
case DOWN:
|
||||
mInstr.sendCharacterSync(KeyEvent.KEYCODE_DPAD_DOWN);
|
||||
break;
|
||||
case UP:
|
||||
mInstr.sendCharacterSync(KeyEvent.KEYCODE_DPAD_UP);
|
||||
break;
|
||||
case LEFT:
|
||||
mInstr.sendCharacterSync(KeyEvent.KEYCODE_DPAD_LEFT);
|
||||
break;
|
||||
case RIGHT:
|
||||
mInstr.sendCharacterSync(KeyEvent.KEYCODE_DPAD_RIGHT);
|
||||
break;
|
||||
case ENTER:
|
||||
mInstr.sendCharacterSync(KeyEvent.KEYCODE_ENTER);
|
||||
break;
|
||||
case MENU:
|
||||
mInstr.sendCharacterSync(KeyEvent.KEYCODE_MENU);
|
||||
break;
|
||||
case BACK:
|
||||
mInstr.sendCharacterSync(KeyEvent.KEYCODE_BACK);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
long endTime = SystemClock.uptimeMillis();
|
||||
if (endTime - startTime >= millis) {
|
||||
// success
|
||||
break;
|
||||
}
|
||||
// we got a notify() before we could wait long enough, so we need to start over
|
||||
startTime = endTime;
|
||||
}
|
||||
try {
|
||||
setDrawListener.invoke(mLayerClient, (Object)null);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public RepeatedEventExpecter expectPaint() {
|
||||
try {
|
||||
return new PaintExpecter();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
@Override
|
||||
public void sendKeys(String input) {
|
||||
mInstr.sendStringSync(input);
|
||||
}
|
||||
}
|
||||
|
||||
public void sendSpecialKey(SpecialKey button) {
|
||||
switch( button) {
|
||||
case DOWN:
|
||||
instr.sendCharacterSync(KeyEvent.KEYCODE_DPAD_DOWN);
|
||||
break;
|
||||
case UP:
|
||||
instr.sendCharacterSync(KeyEvent.KEYCODE_DPAD_UP);
|
||||
break;
|
||||
case LEFT:
|
||||
instr.sendCharacterSync(KeyEvent.KEYCODE_DPAD_LEFT);
|
||||
break;
|
||||
case RIGHT:
|
||||
instr.sendCharacterSync(KeyEvent.KEYCODE_DPAD_RIGHT);
|
||||
break;
|
||||
case ENTER:
|
||||
instr.sendCharacterSync(KeyEvent.KEYCODE_ENTER);
|
||||
break;
|
||||
case MENU:
|
||||
instr.sendCharacterSync(KeyEvent.KEYCODE_MENU);
|
||||
break;
|
||||
case BACK:
|
||||
instr.sendCharacterSync(KeyEvent.KEYCODE_BACK);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
public void drag(int startingX, int endingX, int startingY, int endingY) {
|
||||
mSolo.drag(startingX, endingX, startingY, endingY, 10);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendKeys(String input) {
|
||||
instr.sendStringSync(input);
|
||||
}
|
||||
|
||||
|
||||
public void drag(int startingX, int endingX, int startingY, int endingY) {
|
||||
solo.drag(startingX, endingX, startingY, endingY, 10);
|
||||
}
|
||||
}
|
||||
|
@ -46,8 +46,6 @@ import java.io.FileReader;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.nio.IntBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
@ -68,396 +66,405 @@ import org.json.*;
|
||||
import com.jayway.android.robotium.solo.Solo;
|
||||
|
||||
public class FennecNativeDriver implements Driver {
|
||||
// Map of IDs to element names.
|
||||
private HashMap locators = null;
|
||||
private Activity activity;
|
||||
private Solo solo;
|
||||
// Map of IDs to element names.
|
||||
private HashMap mLocators = null;
|
||||
private Activity mActivity;
|
||||
private Solo mSolo;
|
||||
|
||||
private static String mLogFile = null;
|
||||
private static LogLevel mLogLevel = LogLevel.LOG_LEVEL_INFO;
|
||||
private static String mLogFile = null;
|
||||
private static LogLevel mLogLevel = LogLevel.LOG_LEVEL_INFO;
|
||||
|
||||
// Objects for reflexive access of fennec classes.
|
||||
private ClassLoader classLoader;
|
||||
private Class gel;
|
||||
private Class ge;
|
||||
private Class gas;
|
||||
private Method registerGEL;
|
||||
private Method unregisterGEL;
|
||||
private Method sendGE;
|
||||
private Method _startFrameRecording;
|
||||
private Method _stopFrameRecording;
|
||||
private Method _startCheckerboardRecording;
|
||||
private Method _stopCheckerboardRecording;
|
||||
private Method _getPixels;
|
||||
// Objects for reflexive access of fennec classes.
|
||||
private ClassLoader mClassLoader;
|
||||
private Class mGel;
|
||||
private Class mGe;
|
||||
private Class mGas;
|
||||
private Method mRegisterGEL;
|
||||
private Method mUnregisterGEL;
|
||||
private Method mSendGE;
|
||||
private Method _startFrameRecording;
|
||||
private Method _stopFrameRecording;
|
||||
private Method _startCheckerboardRecording;
|
||||
private Method _stopCheckerboardRecording;
|
||||
private Method _getPixels;
|
||||
|
||||
public enum LogLevel {
|
||||
LOG_LEVEL_DEBUG(1),
|
||||
LOG_LEVEL_INFO(2),
|
||||
LOG_LEVEL_WARN(3),
|
||||
LOG_LEVEL_ERROR(4);
|
||||
public enum LogLevel {
|
||||
LOG_LEVEL_DEBUG(1),
|
||||
LOG_LEVEL_INFO(2),
|
||||
LOG_LEVEL_WARN(3),
|
||||
LOG_LEVEL_ERROR(4);
|
||||
|
||||
private int mValue;
|
||||
LogLevel(int value) {
|
||||
mValue = value;
|
||||
}
|
||||
public boolean isEnabled(LogLevel configuredLevel) {
|
||||
return mValue >= configuredLevel.getValue();
|
||||
}
|
||||
private int getValue() {
|
||||
return mValue;
|
||||
}
|
||||
}
|
||||
|
||||
public FennecNativeDriver(Activity activity, Solo robocop){
|
||||
this.activity = activity;
|
||||
this.solo = robocop;
|
||||
|
||||
// Set up table of fennec_ids.
|
||||
locators = convertTextToTable(getFile("/mnt/sdcard/fennec_ids.txt"));
|
||||
|
||||
// Set up reflexive access of java classes and methods.
|
||||
try {
|
||||
classLoader = activity.getClassLoader();
|
||||
gel = classLoader.loadClass("org.mozilla.gecko.GeckoEventListener");
|
||||
ge = classLoader.loadClass("org.mozilla.gecko.GeckoEvent");
|
||||
gas = classLoader.loadClass("org.mozilla.gecko.GeckoAppShell");
|
||||
Class [] parameters = new Class[2];
|
||||
parameters[0] = String.class;
|
||||
parameters[1] = gel;
|
||||
registerGEL = gas.getMethod("registerGeckoEventListener", parameters);
|
||||
unregisterGEL = gas.getMethod("unregisterGeckoEventListener", parameters);
|
||||
parameters = new Class[1];
|
||||
parameters[0] = ge;
|
||||
sendGE = gas.getMethod("sendEventToGecko", parameters);
|
||||
|
||||
Class gfx = classLoader.loadClass("org.mozilla.gecko.gfx.PanningPerfAPI");
|
||||
_startFrameRecording = gfx.getDeclaredMethod("startFrameTimeRecording");
|
||||
_stopFrameRecording = gfx.getDeclaredMethod("stopFrameTimeRecording");
|
||||
_startCheckerboardRecording = gfx.getDeclaredMethod("startCheckerboardRecording");
|
||||
_stopCheckerboardRecording = gfx.getDeclaredMethod("stopCheckerboardRecording");
|
||||
|
||||
Class layerView = classLoader.loadClass("org.mozilla.gecko.gfx.LayerView");
|
||||
_getPixels = layerView.getDeclaredMethod("getPixels");
|
||||
} catch (ClassNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
} catch (SecurityException e) {
|
||||
e.printStackTrace();
|
||||
} catch (NoSuchMethodException e) {
|
||||
e.printStackTrace();
|
||||
} catch (IllegalArgumentException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
//Information on the location of the Gecko Frame.
|
||||
private boolean geckoInfo = false;
|
||||
private int geckoTop = 100;
|
||||
private int geckoLeft = 0;
|
||||
private int geckoHeight= 700;
|
||||
private int geckoWidth = 1024;
|
||||
|
||||
private void getGeckoInfo() {
|
||||
View geckoLayout = activity.findViewById(Integer.decode((String)locators.get("gecko_layout")));
|
||||
if (geckoLayout != null) {
|
||||
int[] pos = new int[2];
|
||||
geckoLayout.getLocationOnScreen(pos);
|
||||
geckoTop = pos[1];
|
||||
geckoLeft = pos[0];
|
||||
geckoWidth = geckoLayout.getWidth();
|
||||
geckoHeight = geckoLayout.getHeight();
|
||||
geckoInfo = true;
|
||||
} else {
|
||||
throw new RoboCopException("Unable to find view gecko_layout");
|
||||
}
|
||||
}
|
||||
|
||||
public int getGeckoTop() {
|
||||
if(!geckoInfo) {
|
||||
getGeckoInfo();
|
||||
}
|
||||
return geckoTop;
|
||||
}
|
||||
|
||||
public int getGeckoLeft() {
|
||||
if(!geckoInfo) {
|
||||
getGeckoInfo();
|
||||
}
|
||||
return geckoLeft;
|
||||
}
|
||||
|
||||
public int getGeckoHeight() {
|
||||
if(!geckoInfo) {
|
||||
getGeckoInfo();
|
||||
}
|
||||
return geckoHeight;
|
||||
}
|
||||
public int getGeckoWidth() {
|
||||
if(!geckoInfo) {
|
||||
getGeckoInfo();
|
||||
}
|
||||
return geckoWidth;
|
||||
}
|
||||
|
||||
public Element findElement(Activity activity, String name) {
|
||||
if (name == null)
|
||||
throw new IllegalArgumentException("Can not findElements when passed a null");
|
||||
if (locators.containsKey(name)){
|
||||
return new FennecNativeElement(Integer.decode((String)locators.get(name)), activity, solo);
|
||||
}
|
||||
throw new RoboCopException("Element does not exist in the list");
|
||||
}
|
||||
|
||||
public void startFrameRecording() {
|
||||
try {
|
||||
Object [] params = null;
|
||||
_startFrameRecording.invoke(null, params);
|
||||
} catch (IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
} catch (InvocationTargetException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public int stopFrameRecording() {
|
||||
Class [] parameters = new Class[1];
|
||||
parameters[0] = null;
|
||||
List frames;
|
||||
|
||||
try {
|
||||
Object [] params = null;
|
||||
frames = (List)_stopFrameRecording.invoke(null, params);
|
||||
Object [] framearray = frames.toArray();
|
||||
Long last = new Long(0);
|
||||
Long threshold = new Long(17);
|
||||
int numDelays = 0;
|
||||
for (int i=0; i < framearray.length; i++) {
|
||||
Long val = (Long)framearray[i];
|
||||
if ((val - last) > threshold) {
|
||||
numDelays++;
|
||||
private int mValue;
|
||||
LogLevel(int value) {
|
||||
mValue = value;
|
||||
}
|
||||
last = val;
|
||||
}
|
||||
return numDelays;
|
||||
} catch (IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
} catch (InvocationTargetException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public void startCheckerboardRecording() {
|
||||
try {
|
||||
Object [] params = null;
|
||||
_startCheckerboardRecording.invoke(null, params);
|
||||
} catch (IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
} catch (InvocationTargetException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public float stopCheckerboardRecording() {
|
||||
Class [] parameters = new Class[1];
|
||||
parameters[0] = null;
|
||||
List checkerboard;
|
||||
|
||||
try {
|
||||
Object [] params = null;
|
||||
checkerboard = (List)_stopCheckerboardRecording.invoke(null, params);
|
||||
Object [] amountarray = checkerboard.toArray();
|
||||
double completeness = 0;
|
||||
for (Object obj : amountarray) {
|
||||
float val = (Float)obj;
|
||||
completeness += (1.0 - (double)val) / (double)amountarray.length;
|
||||
}
|
||||
return (float)completeness;
|
||||
} catch (IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
} catch (InvocationTargetException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
private GLSurfaceView getSurfaceView() {
|
||||
for (View v : solo.getCurrentViews()) {
|
||||
if (v instanceof GLSurfaceView) {
|
||||
return (GLSurfaceView)v;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public int[][] getPaintedSurface() {
|
||||
GLSurfaceView view = getSurfaceView();
|
||||
if (view == null) {
|
||||
return null;
|
||||
}
|
||||
IntBuffer pixelBuffer;
|
||||
try {
|
||||
pixelBuffer = (IntBuffer)_getPixels.invoke(view);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
|
||||
// now we need to (1) flip the image, because GL likes to do things up-side-down,
|
||||
// and (2) rearrange the bits from AGBR-8888 to ARGB-8888.
|
||||
int w = view.getWidth();
|
||||
int h = view.getHeight();
|
||||
pixelBuffer.position(0);
|
||||
int[][] pixels = new int[h][w];
|
||||
for (int y = h - 1; y >= 0; y--) {
|
||||
for (int x = 0; x < w; x++) {
|
||||
int agbr = pixelBuffer.get();
|
||||
pixels[y][x] = (agbr & 0xFF00FF00) | ((agbr >> 16) & 0x000000FF) | ((agbr << 16) & 0x00FF0000);
|
||||
}
|
||||
}
|
||||
return pixels;
|
||||
}
|
||||
|
||||
class scrollHandler implements InvocationHandler {
|
||||
public scrollHandler(){};
|
||||
public Object invoke(Object proxy, Method method, Object[] args) {
|
||||
try{
|
||||
//Disect the JSON object into the appropriate variables
|
||||
JSONObject jo = ((JSONObject)args[1]);
|
||||
scrollHeight = jo.getInt("y");
|
||||
height = jo.getInt("cheight");
|
||||
//We don't want a height of 0. That means it's a bad response.
|
||||
if( height > 0) {
|
||||
pageHeight = jo.getInt("height");
|
||||
public boolean isEnabled(LogLevel configuredLevel) {
|
||||
return mValue >= configuredLevel.getValue();
|
||||
}
|
||||
private int getValue() {
|
||||
return mValue;
|
||||
}
|
||||
|
||||
} catch( Throwable e) {
|
||||
FennecNativeDriver.log(FennecNativeDriver.LogLevel.LOG_LEVEL_WARN,
|
||||
"WARNING: ScrollReceived, but read wrong!");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
public int getScrollHeight() {
|
||||
return scrollHeight;
|
||||
}
|
||||
public int getPageHeight() {
|
||||
return pageHeight;
|
||||
}
|
||||
public int getHeight() {
|
||||
return height;
|
||||
}
|
||||
|
||||
public int height=0;
|
||||
public int scrollHeight=0;
|
||||
public int pageHeight=10;
|
||||
public void setupScrollHandling() {
|
||||
//Setup scrollHandler to catch "robocop:scroll" events.
|
||||
try {
|
||||
Class [] interfaces = new Class[1];
|
||||
interfaces[0] = gel;
|
||||
Object[] finalParams = new Object[2];
|
||||
finalParams[0] = "robocop:scroll";
|
||||
finalParams[1] = Proxy.newProxyInstance(classLoader, interfaces, new scrollHandler());
|
||||
registerGEL.invoke(null, finalParams);
|
||||
} catch (IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
} catch (InvocationTargetException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
}
|
||||
public FennecNativeDriver(Activity activity, Solo robocop) {
|
||||
mActivity = activity;
|
||||
mSolo = robocop;
|
||||
|
||||
//Takes a filename, loads the file,
|
||||
// and returns a string version of the entire file.
|
||||
public static String getFile(String filename)
|
||||
{
|
||||
StringBuilder text = new StringBuilder();
|
||||
// Set up table of fennec_ids.
|
||||
mLocators = convertTextToTable(getFile("/mnt/sdcard/fennec_ids.txt"));
|
||||
|
||||
BufferedReader br = null;
|
||||
try {
|
||||
br = new BufferedReader(new FileReader(filename));
|
||||
String line;
|
||||
|
||||
while ((line = br.readLine()) != null) {
|
||||
text.append(line);
|
||||
text.append('\n');
|
||||
}
|
||||
} catch(IOException e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
try {
|
||||
br.close();
|
||||
} catch (IOException e) {
|
||||
}
|
||||
}
|
||||
return text.toString();
|
||||
}
|
||||
|
||||
// Takes a string of "key=value" pairs split by \n and creates a hash table.
|
||||
public static HashMap convertTextToTable(String data)
|
||||
{
|
||||
HashMap retVal = new HashMap();
|
||||
|
||||
String[] lines = data.split("\n");
|
||||
for (int i = 0; i < lines.length; i++) {
|
||||
String[] parts = lines[i].split("=");
|
||||
retVal.put(parts[0].trim(), parts[1].trim());
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
// Set the filename used for logging. If the file already exists, delete it
|
||||
// as a safe-guard against accidentally appending to an old log file.
|
||||
public static void setLogFile(String filename) {
|
||||
mLogFile = filename;
|
||||
File file = new File(mLogFile);
|
||||
if (file.exists()) {
|
||||
file.delete();
|
||||
}
|
||||
}
|
||||
|
||||
public static void setLogLevel(LogLevel level) {
|
||||
mLogLevel = level;
|
||||
}
|
||||
|
||||
public static void log(LogLevel level, String message) {
|
||||
if (mLogFile == null) {
|
||||
assert(false);
|
||||
}
|
||||
|
||||
if (level.isEnabled(mLogLevel)) {
|
||||
File file = new File(mLogFile);
|
||||
BufferedWriter bw = null;
|
||||
|
||||
try {
|
||||
bw = new BufferedWriter(new FileWriter(mLogFile, true));
|
||||
bw.write(message);
|
||||
bw.newLine();
|
||||
} catch(IOException e) {
|
||||
Log.e("Robocop", "exception with file writer on: " + mLogFile);
|
||||
} finally {
|
||||
// Set up reflexive access of java classes and methods.
|
||||
try {
|
||||
if (bw != null) {
|
||||
bw.flush();
|
||||
bw.close();
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
mClassLoader = activity.getClassLoader();
|
||||
mGel = mClassLoader.loadClass("org.mozilla.gecko.GeckoEventListener");
|
||||
mGe = mClassLoader.loadClass("org.mozilla.gecko.GeckoEvent");
|
||||
mGas = mClassLoader.loadClass("org.mozilla.gecko.GeckoAppShell");
|
||||
Class [] parameters = new Class[2];
|
||||
parameters[0] = String.class;
|
||||
parameters[1] = mGel;
|
||||
mRegisterGEL = mGas.getMethod("registerGeckoEventListener", parameters);
|
||||
mUnregisterGEL = mGas.getMethod("unregisterGeckoEventListener", parameters);
|
||||
parameters = new Class[1];
|
||||
parameters[0] = mGe;
|
||||
mSendGE = mGas.getMethod("sendEventToGecko", parameters);
|
||||
|
||||
Class gfx = mClassLoader.loadClass("org.mozilla.gecko.gfx.PanningPerfAPI");
|
||||
_startFrameRecording = gfx.getDeclaredMethod("startFrameTimeRecording");
|
||||
_stopFrameRecording = gfx.getDeclaredMethod("stopFrameTimeRecording");
|
||||
_startCheckerboardRecording = gfx.getDeclaredMethod("startCheckerboardRecording");
|
||||
_stopCheckerboardRecording = gfx.getDeclaredMethod("stopCheckerboardRecording");
|
||||
|
||||
Class layerView = mClassLoader.loadClass("org.mozilla.gecko.gfx.LayerView");
|
||||
_getPixels = layerView.getDeclaredMethod("getPixels");
|
||||
} catch (ClassNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
} catch (SecurityException e) {
|
||||
e.printStackTrace();
|
||||
} catch (NoSuchMethodException e) {
|
||||
e.printStackTrace();
|
||||
} catch (IllegalArgumentException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
if (level == LogLevel.LOG_LEVEL_INFO) {
|
||||
Log.i("Robocop", message);
|
||||
} else if (level == LogLevel.LOG_LEVEL_DEBUG) {
|
||||
Log.d("Robocop", message);
|
||||
} else if (level == LogLevel.LOG_LEVEL_WARN) {
|
||||
Log.w("Robocop", message);
|
||||
} else if (level == LogLevel.LOG_LEVEL_ERROR) {
|
||||
Log.e("Robocop", message);
|
||||
//Information on the location of the Gecko Frame.
|
||||
private boolean mGeckoInfo = false;
|
||||
private int mGeckoTop = 100;
|
||||
private int mGeckoLeft = 0;
|
||||
private int mGeckoHeight= 700;
|
||||
private int mGeckoWidth = 1024;
|
||||
|
||||
private void getGeckoInfo() {
|
||||
View geckoLayout = mActivity.findViewById(Integer.decode((String)mLocators.get("gecko_layout")));
|
||||
if (geckoLayout != null) {
|
||||
int[] pos = new int[2];
|
||||
geckoLayout.getLocationOnScreen(pos);
|
||||
mGeckoTop = pos[1];
|
||||
mGeckoLeft = pos[0];
|
||||
mGeckoWidth = geckoLayout.getWidth();
|
||||
mGeckoHeight = geckoLayout.getHeight();
|
||||
mGeckoInfo = true;
|
||||
} else {
|
||||
throw new RoboCopException("Unable to find view gecko_layout");
|
||||
}
|
||||
}
|
||||
|
||||
public int getGeckoTop() {
|
||||
if (!mGeckoInfo) {
|
||||
getGeckoInfo();
|
||||
}
|
||||
return mGeckoTop;
|
||||
}
|
||||
|
||||
public int getGeckoLeft() {
|
||||
if (!mGeckoInfo) {
|
||||
getGeckoInfo();
|
||||
}
|
||||
return mGeckoLeft;
|
||||
}
|
||||
|
||||
public int getGeckoHeight() {
|
||||
if (!mGeckoInfo) {
|
||||
getGeckoInfo();
|
||||
}
|
||||
return mGeckoHeight;
|
||||
}
|
||||
|
||||
public int getGeckoWidth() {
|
||||
if (!mGeckoInfo) {
|
||||
getGeckoInfo();
|
||||
}
|
||||
return mGeckoWidth;
|
||||
}
|
||||
|
||||
public Element findElement(Activity activity, String name) {
|
||||
if (name == null) {
|
||||
throw new IllegalArgumentException("Can not findElements when passed a null");
|
||||
}
|
||||
if (mLocators.containsKey(name)) {
|
||||
return new FennecNativeElement(Integer.decode((String)mLocators.get(name)), activity, mSolo);
|
||||
}
|
||||
throw new RoboCopException("Element does not exist in the list");
|
||||
}
|
||||
|
||||
public void startFrameRecording() {
|
||||
try {
|
||||
Object [] params = null;
|
||||
_startFrameRecording.invoke(null, params);
|
||||
} catch (IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
} catch (InvocationTargetException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public int stopFrameRecording() {
|
||||
Class [] parameters = new Class[1];
|
||||
parameters[0] = null;
|
||||
List frames;
|
||||
|
||||
try {
|
||||
Object [] params = null;
|
||||
frames = (List)_stopFrameRecording.invoke(null, params);
|
||||
Object [] framearray = frames.toArray();
|
||||
Long last = new Long(0);
|
||||
Long threshold = new Long(17);
|
||||
int numDelays = 0;
|
||||
for (int i=0; i < framearray.length; i++) {
|
||||
Long val = (Long)framearray[i];
|
||||
if ((val - last) > threshold) {
|
||||
numDelays++;
|
||||
}
|
||||
last = val;
|
||||
}
|
||||
return numDelays;
|
||||
} catch (IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
} catch (InvocationTargetException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public void startCheckerboardRecording() {
|
||||
try {
|
||||
Object [] params = null;
|
||||
_startCheckerboardRecording.invoke(null, params);
|
||||
} catch (IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
} catch (InvocationTargetException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public float stopCheckerboardRecording() {
|
||||
Class [] parameters = new Class[1];
|
||||
parameters[0] = null;
|
||||
List checkerboard;
|
||||
|
||||
try {
|
||||
Object [] params = null;
|
||||
checkerboard = (List)_stopCheckerboardRecording.invoke(null, params);
|
||||
Object [] amountarray = checkerboard.toArray();
|
||||
double completeness = 0;
|
||||
for (Object obj : amountarray) {
|
||||
float val = (Float)obj;
|
||||
completeness += (1.0 - (double)val) / (double)amountarray.length;
|
||||
}
|
||||
return (float)completeness;
|
||||
} catch (IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
} catch (InvocationTargetException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
private GLSurfaceView getSurfaceView() {
|
||||
for (View v : mSolo.getCurrentViews()) {
|
||||
if (v instanceof GLSurfaceView) {
|
||||
return (GLSurfaceView)v;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public int[][] getPaintedSurface() {
|
||||
GLSurfaceView view = getSurfaceView();
|
||||
if (view == null) {
|
||||
return null;
|
||||
}
|
||||
IntBuffer pixelBuffer;
|
||||
try {
|
||||
pixelBuffer = (IntBuffer)_getPixels.invoke(view);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
|
||||
// now we need to (1) flip the image, because GL likes to do things up-side-down,
|
||||
// and (2) rearrange the bits from AGBR-8888 to ARGB-8888.
|
||||
int w = view.getWidth();
|
||||
int h = view.getHeight();
|
||||
pixelBuffer.position(0);
|
||||
int[][] pixels = new int[h][w];
|
||||
for (int y = h - 1; y >= 0; y--) {
|
||||
for (int x = 0; x < w; x++) {
|
||||
int agbr = pixelBuffer.get();
|
||||
pixels[y][x] = (agbr & 0xFF00FF00) | ((agbr >> 16) & 0x000000FF) | ((agbr << 16) & 0x00FF0000);
|
||||
}
|
||||
}
|
||||
return pixels;
|
||||
}
|
||||
|
||||
public int mHeight=0;
|
||||
public int mScrollHeight=0;
|
||||
public int mPageHeight=10;
|
||||
|
||||
class scrollHandler implements InvocationHandler {
|
||||
public scrollHandler(){};
|
||||
public Object invoke(Object proxy, Method method, Object[] args) {
|
||||
try {
|
||||
// Disect the JSON object into the appropriate variables
|
||||
JSONObject jo = ((JSONObject)args[1]);
|
||||
mScrollHeight = jo.getInt("y");
|
||||
mHeight = jo.getInt("cheight");
|
||||
// We don't want a height of 0. That means it's a bad response.
|
||||
if (mHeight > 0) {
|
||||
mPageHeight = jo.getInt("height");
|
||||
}
|
||||
|
||||
} catch( Throwable e) {
|
||||
FennecNativeDriver.log(FennecNativeDriver.LogLevel.LOG_LEVEL_WARN,
|
||||
"WARNING: ScrollReceived, but read wrong!");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public int getScrollHeight() {
|
||||
return mScrollHeight;
|
||||
}
|
||||
public int getPageHeight() {
|
||||
return mPageHeight;
|
||||
}
|
||||
public int getHeight() {
|
||||
return mHeight;
|
||||
}
|
||||
|
||||
public void setupScrollHandling() {
|
||||
//Setup scrollHandler to catch "robocop:scroll" events.
|
||||
try {
|
||||
Class [] interfaces = new Class[1];
|
||||
interfaces[0] = mGel;
|
||||
Object[] finalParams = new Object[2];
|
||||
finalParams[0] = "robocop:scroll";
|
||||
finalParams[1] = Proxy.newProxyInstance(mClassLoader, interfaces, new scrollHandler());
|
||||
mRegisterGEL.invoke(null, finalParams);
|
||||
} catch (IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
} catch (InvocationTargetException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes a filename, loads the file, and returns a string version of the entire file.
|
||||
*/
|
||||
public static String getFile(String filename)
|
||||
{
|
||||
StringBuilder text = new StringBuilder();
|
||||
|
||||
BufferedReader br = null;
|
||||
try {
|
||||
br = new BufferedReader(new FileReader(filename));
|
||||
String line;
|
||||
|
||||
while ((line = br.readLine()) != null) {
|
||||
text.append(line);
|
||||
text.append('\n');
|
||||
}
|
||||
} catch(IOException e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
try {
|
||||
br.close();
|
||||
} catch (IOException e) {
|
||||
}
|
||||
}
|
||||
return text.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes a string of "key=value" pairs split by \n and creates a hash table.
|
||||
*/
|
||||
public static HashMap convertTextToTable(String data)
|
||||
{
|
||||
HashMap retVal = new HashMap();
|
||||
|
||||
String[] lines = data.split("\n");
|
||||
for (int i = 0; i < lines.length; i++) {
|
||||
String[] parts = lines[i].split("=");
|
||||
retVal.put(parts[0].trim(), parts[1].trim());
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the filename used for logging. If the file already exists, delete it
|
||||
* as a safe-guard against accidentally appending to an old log file.
|
||||
*/
|
||||
public static void setLogFile(String filename) {
|
||||
mLogFile = filename;
|
||||
File file = new File(mLogFile);
|
||||
if (file.exists()) {
|
||||
file.delete();
|
||||
}
|
||||
}
|
||||
|
||||
public static void setLogLevel(LogLevel level) {
|
||||
mLogLevel = level;
|
||||
}
|
||||
|
||||
public static void log(LogLevel level, String message) {
|
||||
if (mLogFile == null) {
|
||||
assert(false);
|
||||
}
|
||||
|
||||
if (level.isEnabled(mLogLevel)) {
|
||||
File file = new File(mLogFile);
|
||||
BufferedWriter bw = null;
|
||||
|
||||
try {
|
||||
bw = new BufferedWriter(new FileWriter(mLogFile, true));
|
||||
bw.write(message);
|
||||
bw.newLine();
|
||||
} catch(IOException e) {
|
||||
Log.e("Robocop", "exception with file writer on: " + mLogFile);
|
||||
} finally {
|
||||
try {
|
||||
if (bw != null) {
|
||||
bw.flush();
|
||||
bw.close();
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (level == LogLevel.LOG_LEVEL_INFO) {
|
||||
Log.i("Robocop", message);
|
||||
} else if (level == LogLevel.LOG_LEVEL_DEBUG) {
|
||||
Log.d("Robocop", message);
|
||||
} else if (level == LogLevel.LOG_LEVEL_WARN) {
|
||||
Log.w("Robocop", message);
|
||||
} else if (level == LogLevel.LOG_LEVEL_ERROR) {
|
||||
Log.e("Robocop", message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -42,7 +42,6 @@ package @ANDROID_PACKAGE_NAME@;
|
||||
import java.util.List;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Button;
|
||||
@ -55,110 +54,110 @@ import com.jayway.android.robotium.solo.Solo;
|
||||
import java.util.concurrent.SynchronousQueue;
|
||||
|
||||
public class FennecNativeElement implements Element {
|
||||
private final Activity mActivity;
|
||||
private Integer id;
|
||||
private Solo robocop;
|
||||
private final Activity mActivity;
|
||||
private Integer mId;
|
||||
private Solo mSolo;
|
||||
|
||||
public FennecNativeElement(Integer id, Activity activity, Solo solo){
|
||||
this.id = id;
|
||||
mActivity = activity;
|
||||
robocop = solo;
|
||||
}
|
||||
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void click() {
|
||||
final SynchronousQueue syncQueue = new SynchronousQueue();
|
||||
mActivity.runOnUiThread(
|
||||
new Runnable() {
|
||||
public void run() {
|
||||
View view = (View)mActivity.findViewById(id);
|
||||
if(view != null) {
|
||||
if (!view.performClick()) {
|
||||
FennecNativeDriver.log(FennecNativeDriver.LogLevel.LOG_LEVEL_WARN,
|
||||
"Robocop called click on an element with no listener");
|
||||
}
|
||||
} else {
|
||||
throw new RoboCopException("click: unable to find view "+id);
|
||||
}
|
||||
syncQueue.offer(new Object());
|
||||
}
|
||||
});
|
||||
try {
|
||||
syncQueue.take();
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
public FennecNativeElement(Integer id, Activity activity, Solo solo) {
|
||||
mId = id;
|
||||
mActivity = activity;
|
||||
mSolo = solo;
|
||||
}
|
||||
}
|
||||
|
||||
private Object text;
|
||||
public Integer getId() {
|
||||
return mId;
|
||||
}
|
||||
|
||||
public String getText() {
|
||||
final SynchronousQueue syncQueue = new SynchronousQueue();
|
||||
mActivity.runOnUiThread(
|
||||
new Runnable() {
|
||||
public void run() {
|
||||
View v = mActivity.findViewById(id);
|
||||
if(v instanceof EditText) {
|
||||
EditText et = (EditText)v;
|
||||
text = et.getEditableText();
|
||||
}else if(v instanceof TextSwitcher) {
|
||||
TextSwitcher ts = (TextSwitcher)v;
|
||||
ts.getNextView();
|
||||
text = ((TextView)ts.getCurrentView()).getText();
|
||||
}else if(v instanceof ViewGroup) {
|
||||
ViewGroup vg = (ViewGroup)v;
|
||||
for(int i = 0; i < vg.getChildCount(); i++) {
|
||||
if(vg.getChildAt(i) instanceof TextView) {
|
||||
text = ((TextView)vg.getChildAt(i)).getText();
|
||||
public void click() {
|
||||
final SynchronousQueue syncQueue = new SynchronousQueue();
|
||||
mActivity.runOnUiThread(
|
||||
new Runnable() {
|
||||
public void run() {
|
||||
View view = (View)mActivity.findViewById(mId);
|
||||
if(view != null) {
|
||||
if (!view.performClick()) {
|
||||
FennecNativeDriver.log(FennecNativeDriver.LogLevel.LOG_LEVEL_WARN,
|
||||
"Robocop called click on an element with no listener");
|
||||
}
|
||||
} else {
|
||||
throw new RoboCopException("click: unable to find view "+mId);
|
||||
}
|
||||
syncQueue.offer(new Object());
|
||||
}
|
||||
} //end of for
|
||||
} else if(v instanceof TextView) {
|
||||
text = ((TextView)v).getText();
|
||||
} else if(v == null) {
|
||||
throw new RoboCopException("getText: unable to find view "+id);
|
||||
} else {
|
||||
throw new RoboCopException("getText: unhandled type for view "+id);
|
||||
}
|
||||
syncQueue.offer(new Object());
|
||||
} // end of run() method definition
|
||||
} // end of anonymous Runnable object instantiation
|
||||
);
|
||||
try {
|
||||
//Wait for the UiThread code to finish running
|
||||
syncQueue.take();
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
});
|
||||
try {
|
||||
syncQueue.take();
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
if(text == null) {
|
||||
throw new RoboCopException("getText: Text is null for view "+id);
|
||||
}
|
||||
return text.toString();
|
||||
}
|
||||
|
||||
private boolean displayed;
|
||||
private Object mText;
|
||||
|
||||
public boolean isDisplayed() {
|
||||
final SynchronousQueue syncQueue = new SynchronousQueue();
|
||||
displayed = false;
|
||||
mActivity.runOnUiThread(
|
||||
new Runnable() {
|
||||
public void run() {
|
||||
View view = (View)mActivity.findViewById(id);
|
||||
if(view != null) {
|
||||
displayed = true;
|
||||
}
|
||||
syncQueue.offer(new Object());
|
||||
}
|
||||
});
|
||||
try {
|
||||
syncQueue.take();
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
public String getText() {
|
||||
final SynchronousQueue syncQueue = new SynchronousQueue();
|
||||
mActivity.runOnUiThread(
|
||||
new Runnable() {
|
||||
public void run() {
|
||||
View v = mActivity.findViewById(mId);
|
||||
if (v instanceof EditText) {
|
||||
EditText et = (EditText)v;
|
||||
mText = et.getEditableText();
|
||||
} else if (v instanceof TextSwitcher) {
|
||||
TextSwitcher ts = (TextSwitcher)v;
|
||||
ts.getNextView();
|
||||
mText = ((TextView)ts.getCurrentView()).getText();
|
||||
} else if (v instanceof ViewGroup) {
|
||||
ViewGroup vg = (ViewGroup)v;
|
||||
for (int i = 0; i < vg.getChildCount(); i++) {
|
||||
if (vg.getChildAt(i) instanceof TextView) {
|
||||
mText = ((TextView)vg.getChildAt(i)).getText();
|
||||
}
|
||||
}
|
||||
} else if (v instanceof TextView) {
|
||||
mText = ((TextView)v).getText();
|
||||
} else if (v == null) {
|
||||
throw new RoboCopException("getText: unable to find view "+mId);
|
||||
} else {
|
||||
throw new RoboCopException("getText: unhandled type for view "+mId);
|
||||
}
|
||||
syncQueue.offer(new Object());
|
||||
} // end of run() method definition
|
||||
} // end of anonymous Runnable object instantiation
|
||||
);
|
||||
try {
|
||||
// Wait for the UiThread code to finish running
|
||||
syncQueue.take();
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
if (mText == null) {
|
||||
throw new RoboCopException("getText: Text is null for view "+mId);
|
||||
}
|
||||
return mText.toString();
|
||||
}
|
||||
|
||||
private boolean mDisplayed;
|
||||
|
||||
public boolean isDisplayed() {
|
||||
final SynchronousQueue syncQueue = new SynchronousQueue();
|
||||
mDisplayed = false;
|
||||
mActivity.runOnUiThread(
|
||||
new Runnable() {
|
||||
public void run() {
|
||||
View view = (View)mActivity.findViewById(mId);
|
||||
if (view != null) {
|
||||
mDisplayed = true;
|
||||
}
|
||||
syncQueue.offer(new Object());
|
||||
}
|
||||
});
|
||||
try {
|
||||
syncQueue.take();
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return mDisplayed;
|
||||
}
|
||||
return displayed;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -39,52 +39,40 @@ package @ANDROID_PACKAGE_NAME@;
|
||||
|
||||
|
||||
public class FennecTalosAssert implements Assert {
|
||||
|
||||
public FennecTalosAssert() {
|
||||
}
|
||||
|
||||
public FennecTalosAssert() { }
|
||||
|
||||
// Write information to a logfile and logcat
|
||||
public void dumpLog(String message)
|
||||
{
|
||||
FennecNativeDriver.log(FennecNativeDriver.LogLevel.LOG_LEVEL_INFO, message);
|
||||
}
|
||||
/**
|
||||
* Write information to a logfile and logcat
|
||||
*/
|
||||
public void dumpLog(String message) {
|
||||
FennecNativeDriver.log(FennecNativeDriver.LogLevel.LOG_LEVEL_INFO, message);
|
||||
}
|
||||
|
||||
// Set the filename used for dumpLog.
|
||||
public void setLogFile(String filename)
|
||||
{
|
||||
FennecNativeDriver.setLogFile(filename);
|
||||
}
|
||||
/**
|
||||
* Set the filename used for dumpLog.
|
||||
*/
|
||||
public void setLogFile(String filename) {
|
||||
FennecNativeDriver.setLogFile(filename);
|
||||
}
|
||||
|
||||
public void setTestName(String testName)
|
||||
{
|
||||
}
|
||||
public void setTestName(String testName) { }
|
||||
|
||||
public void finalize() { }
|
||||
|
||||
public void finalize()
|
||||
{
|
||||
}
|
||||
public void ok(boolean condition, String name, String diag) { }
|
||||
|
||||
public void ok(boolean condition, String name, String diag) {
|
||||
}
|
||||
public void is(Object a, Object b, String name) { }
|
||||
|
||||
public void isnot(Object a, Object b, String name) { }
|
||||
|
||||
public void is(Object a, Object b, String name) {
|
||||
}
|
||||
|
||||
public void isnot(Object a, Object b, String name) {
|
||||
}
|
||||
public void ispixel(int actual, int r, int g, int b, String name) { }
|
||||
|
||||
public void ispixel(int actual, int r, int g, int b, String name) {
|
||||
}
|
||||
public void todo(boolean condition, String name, String diag) { }
|
||||
|
||||
public void todo(boolean condition, String name, String diag) {
|
||||
}
|
||||
public void todo_is(Object a, Object b, String name) { }
|
||||
|
||||
public void todo_isnot(Object a, Object b, String name) { }
|
||||
|
||||
public void todo_is(Object a, Object b, String name) {
|
||||
}
|
||||
|
||||
public void todo_isnot(Object a, Object b, String name) {
|
||||
}
|
||||
|
||||
public void info(String name, String message) {
|
||||
}
|
||||
public void info(String name, String message) { }
|
||||
}
|
||||
|
@ -40,20 +40,20 @@
|
||||
package @ANDROID_PACKAGE_NAME@;
|
||||
|
||||
public class RoboCopException extends RuntimeException {
|
||||
|
||||
public RoboCopException(){
|
||||
super();
|
||||
}
|
||||
|
||||
public RoboCopException(String message){
|
||||
super(message);
|
||||
}
|
||||
|
||||
public RoboCopException(Throwable cause){
|
||||
super(cause);
|
||||
}
|
||||
|
||||
public RoboCopException(String message, Throwable cause){
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
public RoboCopException() {
|
||||
super();
|
||||
}
|
||||
|
||||
public RoboCopException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public RoboCopException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
public RoboCopException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
||||
|
@ -293,6 +293,7 @@ MOZ_NATIVE_NSPR = @MOZ_NATIVE_NSPR@
|
||||
MOZ_NATIVE_NSS = @MOZ_NATIVE_NSS@
|
||||
|
||||
MOZ_B2G_RIL = @MOZ_B2G_RIL@
|
||||
MOZ_B2G_BT = @MOZ_B2G_BT@
|
||||
|
||||
BUILD_CTYPES = @BUILD_CTYPES@
|
||||
|
||||
|
22
configure.in
22
configure.in
@ -225,7 +225,14 @@ if test -n "$L10NBASEDIR"; then
|
||||
if test "$L10NBASEDIR" = "yes" -o "$L10NBASEDIR" = "no"; then
|
||||
AC_MSG_ERROR([--with-l10n-base must specify a path])
|
||||
elif test -d "$L10NBASEDIR"; then
|
||||
L10NBASEDIR=`cd "$L10NBASEDIR" && pwd`
|
||||
case "$host_os" in
|
||||
mingw*)
|
||||
L10NBASEDIR=`cd "$L10NBASEDIR" && pwd -W`
|
||||
;;
|
||||
*)
|
||||
L10NBASEDIR=`cd "$L10NBASEDIR" && pwd`
|
||||
;;
|
||||
esac
|
||||
else
|
||||
AC_MSG_ERROR([Invalid value --with-l10n-base, $L10NBASEDIR doesn't exist])
|
||||
fi
|
||||
@ -4920,6 +4927,7 @@ cairo-gonk)
|
||||
MOZ_PDF_PRINTING=1
|
||||
MOZ_B2G_RIL=1
|
||||
MOZ_TOUCH=1
|
||||
MOZ_B2G_BT=1
|
||||
;;
|
||||
|
||||
esac
|
||||
@ -7590,6 +7598,18 @@ if test -n "$MOZ_B2G_RIL"; then
|
||||
fi
|
||||
AC_SUBST(MOZ_B2G_RIL)
|
||||
|
||||
dnl ========================================================
|
||||
dnl = Enable Bluetooth Interface for B2G (Gonk usually)
|
||||
dnl ========================================================
|
||||
MOZ_ARG_ENABLE_BOOL(b2g-bt,
|
||||
[ --enable-b2g-bt Set compile flags necessary for compiling Bluetooth API for B2G ],
|
||||
MOZ_B2G_BT=1,
|
||||
MOZ_B2G_BT= )
|
||||
if test -n "$MOZ_B2G_BT"; then
|
||||
AC_DEFINE(MOZ_B2G_BT)
|
||||
fi
|
||||
AC_SUBST(MOZ_B2G_BT)
|
||||
|
||||
dnl ========================================================
|
||||
dnl = Support for demangling undefined symbols
|
||||
dnl ========================================================
|
||||
|
@ -1,74 +0,0 @@
|
||||
/* ***** 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.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is the Mozilla Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Alon Zakai <azakai@mozilla.com>
|
||||
*
|
||||
* 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 "nsISupports.idl"
|
||||
|
||||
/**
|
||||
* This service lets other components be woken up when particular
|
||||
* messageManager messages arrive. By using this wakeup service,
|
||||
* those components do not need to be started until they are
|
||||
* needed.
|
||||
*
|
||||
* The parentprocessmessagemanager is used for this, so messages
|
||||
* send from childprocessmessagemanagers will be heard.
|
||||
*
|
||||
* Components can request wakeups using the .manifest files, or
|
||||
* by someone else calling requestWakeup. For .manifest files,
|
||||
* the line should look something like
|
||||
*
|
||||
* category wakeup-request nsComponent @mozilla.org/myservice;1,
|
||||
* nsIMyInterface,getService,myMessage1,myMessage2[,..]
|
||||
*
|
||||
* Currently we require services to expose wrappedJSObject, but
|
||||
* that will be cleaned up in bug 593407, at which point the
|
||||
* service that will be woken up must implement
|
||||
* nsIFrameMessageListener.
|
||||
*/
|
||||
[scriptable, uuid(968e31b6-b859-42f3-8140-014378fe1783)]
|
||||
interface nsIMessageWakeupService : nsISupports
|
||||
{
|
||||
/**
|
||||
* Requests that the wakeup service wake us up when a particular
|
||||
* message arrives. At that time the service will be woken up
|
||||
* and subscribed to receive further messages of that name as
|
||||
* well.
|
||||
*/
|
||||
boolean requestWakeup(in AString aMessageName,
|
||||
in AString aCid,
|
||||
in AString aIid,
|
||||
in AString aMethod);
|
||||
};
|
||||
|
@ -46,7 +46,7 @@ function MessageWakeupService() { };
|
||||
MessageWakeupService.prototype =
|
||||
{
|
||||
classID: Components.ID("{f9798742-4f7b-4188-86ba-48b116412b29}"),
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIMessageWakeupService, Ci.nsISupports, Ci.nsIObserver]),
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver]),
|
||||
|
||||
messagesData: [],
|
||||
|
||||
|
@ -136,6 +136,10 @@ public:
|
||||
}
|
||||
|
||||
PRInt64 SizeOf() const;
|
||||
bool HasMappedAttrs() const
|
||||
{
|
||||
return MappedAttrCount();
|
||||
}
|
||||
|
||||
private:
|
||||
nsAttrAndChildArray(const nsAttrAndChildArray& aOther) MOZ_DELETE;
|
||||
|
@ -54,6 +54,8 @@
|
||||
|
||||
namespace css = mozilla::css;
|
||||
|
||||
using mozilla::SVGAttrValueWrapper;
|
||||
|
||||
#define MISC_STR_PTR(_cont) \
|
||||
reinterpret_cast<void*>((_cont)->mStringBits & NS_ATTRVALUE_POINTERVALUE_MASK)
|
||||
|
||||
@ -76,6 +78,12 @@ nsAttrValue::nsAttrValue(const nsAString& aValue)
|
||||
SetTo(aValue);
|
||||
}
|
||||
|
||||
nsAttrValue::nsAttrValue(nsIAtom* aValue)
|
||||
: mBits(0)
|
||||
{
|
||||
SetTo(aValue);
|
||||
}
|
||||
|
||||
nsAttrValue::nsAttrValue(css::StyleRule* aValue, const nsAString* aSerialized)
|
||||
: mBits(0)
|
||||
{
|
||||
@ -260,7 +268,13 @@ nsAttrValue::SetTo(const nsAttrValue& aOther)
|
||||
}
|
||||
default:
|
||||
{
|
||||
NS_NOTREACHED("unknown type stored in MiscContainer");
|
||||
if (IsSVGType(otherCont->mType)) {
|
||||
// All SVG types are just pointers to classes and will therefore have
|
||||
// the same size so it doesn't really matter which one we assign
|
||||
cont->mSVGAngle = otherCont->mSVGAngle;
|
||||
} else {
|
||||
NS_NOTREACHED("unknown type stored in MiscContainer");
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -290,6 +304,16 @@ nsAttrValue::SetTo(const nsAString& aValue)
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsAttrValue::SetTo(nsIAtom* aValue)
|
||||
{
|
||||
ResetIfSet();
|
||||
if (aValue) {
|
||||
NS_ADDREF(aValue);
|
||||
SetPtrValueAndType(aValue, eAtomBase);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsAttrValue::SetTo(PRInt16 aInt)
|
||||
{
|
||||
@ -297,6 +321,24 @@ nsAttrValue::SetTo(PRInt16 aInt)
|
||||
SetIntValueAndType(aInt, eInteger, nsnull);
|
||||
}
|
||||
|
||||
void
|
||||
nsAttrValue::SetTo(PRInt32 aInt, const nsAString* aSerialized)
|
||||
{
|
||||
ResetIfSet();
|
||||
SetIntValueAndType(aInt, eInteger, aSerialized);
|
||||
}
|
||||
|
||||
void
|
||||
nsAttrValue::SetTo(double aValue, const nsAString* aSerialized)
|
||||
{
|
||||
if (EnsureEmptyMiscContainer()) {
|
||||
MiscContainer* cont = GetMiscContainer();
|
||||
cont->mDoubleValue = aValue;
|
||||
cont->mType = eDoubleValue;
|
||||
SetMiscAtomOrString(aSerialized);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsAttrValue::SetTo(css::StyleRule* aValue, const nsAString* aSerialized)
|
||||
{
|
||||
@ -331,6 +373,115 @@ nsAttrValue::SetToSerialized(const nsAttrValue& aOther)
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsAttrValue::SetTo(const nsSVGAngle& aValue, const nsAString* aSerialized)
|
||||
{
|
||||
SetSVGType(eSVGAngle, &aValue, aSerialized);
|
||||
}
|
||||
|
||||
void
|
||||
nsAttrValue::SetTo(const nsSVGIntegerPair& aValue, const nsAString* aSerialized)
|
||||
{
|
||||
SetSVGType(eSVGIntegerPair, &aValue, aSerialized);
|
||||
}
|
||||
|
||||
void
|
||||
nsAttrValue::SetTo(const nsSVGLength2& aValue, const nsAString* aSerialized)
|
||||
{
|
||||
SetSVGType(eSVGLength, &aValue, aSerialized);
|
||||
}
|
||||
|
||||
void
|
||||
nsAttrValue::SetTo(const mozilla::SVGLengthList& aValue,
|
||||
const nsAString* aSerialized)
|
||||
{
|
||||
// While an empty string will parse as a length list, there's no need to store
|
||||
// it (and SetMiscAtomOrString will assert if we try)
|
||||
if (aSerialized && aSerialized->IsEmpty()) {
|
||||
aSerialized = nsnull;
|
||||
}
|
||||
SetSVGType(eSVGLengthList, &aValue, aSerialized);
|
||||
}
|
||||
|
||||
void
|
||||
nsAttrValue::SetTo(const mozilla::SVGNumberList& aValue,
|
||||
const nsAString* aSerialized)
|
||||
{
|
||||
// While an empty string will parse as a number list, there's no need to store
|
||||
// it (and SetMiscAtomOrString will assert if we try)
|
||||
if (aSerialized && aSerialized->IsEmpty()) {
|
||||
aSerialized = nsnull;
|
||||
}
|
||||
SetSVGType(eSVGNumberList, &aValue, aSerialized);
|
||||
}
|
||||
|
||||
void
|
||||
nsAttrValue::SetTo(const nsSVGNumberPair& aValue, const nsAString* aSerialized)
|
||||
{
|
||||
SetSVGType(eSVGNumberPair, &aValue, aSerialized);
|
||||
}
|
||||
|
||||
void
|
||||
nsAttrValue::SetTo(const mozilla::SVGPathData& aValue,
|
||||
const nsAString* aSerialized)
|
||||
{
|
||||
// While an empty string will parse as path data, there's no need to store it
|
||||
// (and SetMiscAtomOrString will assert if we try)
|
||||
if (aSerialized && aSerialized->IsEmpty()) {
|
||||
aSerialized = nsnull;
|
||||
}
|
||||
SetSVGType(eSVGPathData, &aValue, aSerialized);
|
||||
}
|
||||
|
||||
void
|
||||
nsAttrValue::SetTo(const mozilla::SVGPointList& aValue,
|
||||
const nsAString* aSerialized)
|
||||
{
|
||||
// While an empty string will parse as a point list, there's no need to store
|
||||
// it (and SetMiscAtomOrString will assert if we try)
|
||||
if (aSerialized && aSerialized->IsEmpty()) {
|
||||
aSerialized = nsnull;
|
||||
}
|
||||
SetSVGType(eSVGPointList, &aValue, aSerialized);
|
||||
}
|
||||
|
||||
void
|
||||
nsAttrValue::SetTo(const mozilla::SVGAnimatedPreserveAspectRatio& aValue,
|
||||
const nsAString* aSerialized)
|
||||
{
|
||||
SetSVGType(eSVGPreserveAspectRatio, &aValue, aSerialized);
|
||||
}
|
||||
|
||||
void
|
||||
nsAttrValue::SetTo(const mozilla::SVGStringList& aValue,
|
||||
const nsAString* aSerialized)
|
||||
{
|
||||
// While an empty string will parse as a string list, there's no need to store
|
||||
// it (and SetMiscAtomOrString will assert if we try)
|
||||
if (aSerialized && aSerialized->IsEmpty()) {
|
||||
aSerialized = nsnull;
|
||||
}
|
||||
SetSVGType(eSVGStringList, &aValue, aSerialized);
|
||||
}
|
||||
|
||||
void
|
||||
nsAttrValue::SetTo(const mozilla::SVGTransformList& aValue,
|
||||
const nsAString* aSerialized)
|
||||
{
|
||||
// While an empty string will parse as a transform list, there's no need to
|
||||
// store it (and SetMiscAtomOrString will assert if we try)
|
||||
if (aSerialized && aSerialized->IsEmpty()) {
|
||||
aSerialized = nsnull;
|
||||
}
|
||||
SetSVGType(eSVGTransformList, &aValue, aSerialized);
|
||||
}
|
||||
|
||||
void
|
||||
nsAttrValue::SetTo(const nsSVGViewBox& aValue, const nsAString* aSerialized)
|
||||
{
|
||||
SetSVGType(eSVGViewBox, &aValue, aSerialized);
|
||||
}
|
||||
|
||||
void
|
||||
nsAttrValue::SwapValueWith(nsAttrValue& aOther)
|
||||
{
|
||||
@ -428,6 +579,73 @@ nsAttrValue::ToString(nsAString& aResult) const
|
||||
aResult.AppendFloat(GetDoubleValue());
|
||||
break;
|
||||
}
|
||||
case eSVGAngle:
|
||||
{
|
||||
SVGAttrValueWrapper::ToString(GetMiscContainer()->mSVGAngle, aResult);
|
||||
break;
|
||||
}
|
||||
case eSVGIntegerPair:
|
||||
{
|
||||
SVGAttrValueWrapper::ToString(GetMiscContainer()->mSVGIntegerPair,
|
||||
aResult);
|
||||
break;
|
||||
}
|
||||
case eSVGLength:
|
||||
{
|
||||
SVGAttrValueWrapper::ToString(GetMiscContainer()->mSVGLength, aResult);
|
||||
break;
|
||||
}
|
||||
case eSVGLengthList:
|
||||
{
|
||||
SVGAttrValueWrapper::ToString(GetMiscContainer()->mSVGLengthList,
|
||||
aResult);
|
||||
break;
|
||||
}
|
||||
case eSVGNumberList:
|
||||
{
|
||||
SVGAttrValueWrapper::ToString(GetMiscContainer()->mSVGNumberList,
|
||||
aResult);
|
||||
break;
|
||||
}
|
||||
case eSVGNumberPair:
|
||||
{
|
||||
SVGAttrValueWrapper::ToString(GetMiscContainer()->mSVGNumberPair,
|
||||
aResult);
|
||||
break;
|
||||
}
|
||||
case eSVGPathData:
|
||||
{
|
||||
SVGAttrValueWrapper::ToString(GetMiscContainer()->mSVGPathData, aResult);
|
||||
break;
|
||||
}
|
||||
case eSVGPointList:
|
||||
{
|
||||
SVGAttrValueWrapper::ToString(GetMiscContainer()->mSVGPointList, aResult);
|
||||
break;
|
||||
}
|
||||
case eSVGPreserveAspectRatio:
|
||||
{
|
||||
SVGAttrValueWrapper::ToString(GetMiscContainer()->mSVGPreserveAspectRatio,
|
||||
aResult);
|
||||
break;
|
||||
}
|
||||
case eSVGStringList:
|
||||
{
|
||||
SVGAttrValueWrapper::ToString(GetMiscContainer()->mSVGStringList,
|
||||
aResult);
|
||||
break;
|
||||
}
|
||||
case eSVGTransformList:
|
||||
{
|
||||
SVGAttrValueWrapper::ToString(GetMiscContainer()->mSVGTransformList,
|
||||
aResult);
|
||||
break;
|
||||
}
|
||||
case eSVGViewBox:
|
||||
{
|
||||
SVGAttrValueWrapper::ToString(GetMiscContainer()->mSVGViewBox, aResult);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
aResult.Truncate();
|
||||
@ -614,6 +832,10 @@ nsAttrValue::HashValue() const
|
||||
}
|
||||
default:
|
||||
{
|
||||
if (IsSVGType(cont->mType)) {
|
||||
// All SVG types are just pointers to classes so we can treat them alike
|
||||
return NS_PTR_TO_INT32(cont->mSVGAngle);
|
||||
}
|
||||
NS_NOTREACHED("unknown type stored in MiscContainer");
|
||||
return 0;
|
||||
}
|
||||
@ -706,6 +928,16 @@ nsAttrValue::Equals(const nsAttrValue& aOther) const
|
||||
}
|
||||
default:
|
||||
{
|
||||
if (IsSVGType(thisCont->mType)) {
|
||||
// Currently this method is never called for nsAttrValue objects that
|
||||
// point to SVG data types.
|
||||
// If that changes then we probably want to add methods to the
|
||||
// corresponding SVG types to compare their base values.
|
||||
// As a shortcut, however, we can begin by comparing the pointers.
|
||||
NS_ABORT_IF_FALSE(false, "Comparing nsAttrValues that point to SVG "
|
||||
"data");
|
||||
return false;
|
||||
}
|
||||
NS_NOTREACHED("unknown type stored in MiscContainer");
|
||||
return false;
|
||||
}
|
||||
@ -1351,6 +1583,22 @@ nsAttrValue::ResetMiscAtomOrString()
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsAttrValue::SetSVGType(ValueType aType, const void* aValue,
|
||||
const nsAString* aSerialized) {
|
||||
NS_ABORT_IF_FALSE(IsSVGType(aType), "Not an SVG type");
|
||||
if (EnsureEmptyMiscContainer()) {
|
||||
MiscContainer* cont = GetMiscContainer();
|
||||
// All SVG types are just pointers to classes so just setting any of them
|
||||
// will do. We'll lose type-safety but the signature of the calling
|
||||
// function should ensure we don't get anything unexpected, and once we
|
||||
// stick aValue in a union we lose type information anyway.
|
||||
cont->mSVGAngle = static_cast<const nsSVGAngle*>(aValue);
|
||||
cont->mType = aType;
|
||||
SetMiscAtomOrString(aSerialized);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
nsAttrValue::EnsureEmptyMiscContainer()
|
||||
{
|
||||
|
@ -51,6 +51,7 @@
|
||||
#include "nsCaseTreatment.h"
|
||||
#include "nsMargin.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "SVGAttrValueWrapper.h"
|
||||
|
||||
typedef PRUptrdiff PtrBits;
|
||||
class nsAString;
|
||||
@ -102,6 +103,7 @@ public:
|
||||
nsAttrValue();
|
||||
nsAttrValue(const nsAttrValue& aOther);
|
||||
explicit nsAttrValue(const nsAString& aValue);
|
||||
explicit nsAttrValue(nsIAtom* aValue);
|
||||
nsAttrValue(mozilla::css::StyleRule* aValue, const nsAString* aSerialized);
|
||||
explicit nsAttrValue(const nsIntMargin& aValue);
|
||||
~nsAttrValue();
|
||||
@ -123,9 +125,23 @@ public:
|
||||
// Values below here won't matter, they'll be always stored in the 'misc'
|
||||
// struct.
|
||||
eCSSStyleRule = 0x10
|
||||
,eAtomArray = 0x11
|
||||
,eAtomArray = 0x11
|
||||
,eDoubleValue = 0x12
|
||||
,eIntMarginValue = 0x13
|
||||
,eSVGTypesBegin = 0x14
|
||||
,eSVGAngle = eSVGTypesBegin
|
||||
,eSVGIntegerPair = 0x15
|
||||
,eSVGLength = 0x16
|
||||
,eSVGLengthList = 0x17
|
||||
,eSVGNumberList = 0x18
|
||||
,eSVGNumberPair = 0x19
|
||||
,eSVGPathData = 0x20
|
||||
,eSVGPointList = 0x21
|
||||
,eSVGPreserveAspectRatio = 0x22
|
||||
,eSVGStringList = 0x23
|
||||
,eSVGTransformList = 0x24
|
||||
,eSVGViewBox = 0x25
|
||||
,eSVGTypesEnd = 0x34
|
||||
};
|
||||
|
||||
ValueType Type() const;
|
||||
@ -134,9 +150,29 @@ public:
|
||||
|
||||
void SetTo(const nsAttrValue& aOther);
|
||||
void SetTo(const nsAString& aValue);
|
||||
void SetTo(nsIAtom* aValue);
|
||||
void SetTo(PRInt16 aInt);
|
||||
void SetTo(PRInt32 aInt, const nsAString* aSerialized);
|
||||
void SetTo(double aValue, const nsAString* aSerialized);
|
||||
void SetTo(mozilla::css::StyleRule* aValue, const nsAString* aSerialized);
|
||||
void SetTo(const nsIntMargin& aValue);
|
||||
void SetTo(const nsSVGAngle& aValue, const nsAString* aSerialized);
|
||||
void SetTo(const nsSVGIntegerPair& aValue, const nsAString* aSerialized);
|
||||
void SetTo(const nsSVGLength2& aValue, const nsAString* aSerialized);
|
||||
void SetTo(const mozilla::SVGLengthList& aValue,
|
||||
const nsAString* aSerialized);
|
||||
void SetTo(const mozilla::SVGNumberList& aValue,
|
||||
const nsAString* aSerialized);
|
||||
void SetTo(const nsSVGNumberPair& aValue, const nsAString* aSerialized);
|
||||
void SetTo(const mozilla::SVGPathData& aValue, const nsAString* aSerialized);
|
||||
void SetTo(const mozilla::SVGPointList& aValue, const nsAString* aSerialized);
|
||||
void SetTo(const mozilla::SVGAnimatedPreserveAspectRatio& aValue,
|
||||
const nsAString* aSerialized);
|
||||
void SetTo(const mozilla::SVGStringList& aValue,
|
||||
const nsAString* aSerialized);
|
||||
void SetTo(const mozilla::SVGTransformList& aValue,
|
||||
const nsAString* aSerialized);
|
||||
void SetTo(const nsSVGViewBox& aValue, const nsAString* aSerialized);
|
||||
|
||||
/**
|
||||
* Sets this object with the string or atom representation of aValue.
|
||||
@ -368,10 +404,23 @@ private:
|
||||
AtomArray* mAtomArray;
|
||||
double mDoubleValue;
|
||||
nsIntMargin* mIntMargin;
|
||||
const nsSVGAngle* mSVGAngle;
|
||||
const nsSVGIntegerPair* mSVGIntegerPair;
|
||||
const nsSVGLength2* mSVGLength;
|
||||
const mozilla::SVGLengthList* mSVGLengthList;
|
||||
const mozilla::SVGNumberList* mSVGNumberList;
|
||||
const nsSVGNumberPair* mSVGNumberPair;
|
||||
const mozilla::SVGPathData* mSVGPathData;
|
||||
const mozilla::SVGPointList* mSVGPointList;
|
||||
const mozilla::SVGAnimatedPreserveAspectRatio* mSVGPreserveAspectRatio;
|
||||
const mozilla::SVGStringList* mSVGStringList;
|
||||
const mozilla::SVGTransformList* mSVGTransformList;
|
||||
const nsSVGViewBox* mSVGViewBox;
|
||||
};
|
||||
};
|
||||
|
||||
inline ValueBaseType BaseType() const;
|
||||
inline bool IsSVGType(ValueType aType) const;
|
||||
|
||||
/**
|
||||
* Get the index of an EnumTable in the sEnumTableArray.
|
||||
@ -388,6 +437,8 @@ private:
|
||||
void SetColorValue(nscolor aColor, const nsAString& aString);
|
||||
void SetMiscAtomOrString(const nsAString* aValue);
|
||||
void ResetMiscAtomOrString();
|
||||
void SetSVGType(ValueType aType, const void* aValue,
|
||||
const nsAString* aSerialized);
|
||||
inline void ResetIfSet();
|
||||
|
||||
inline void* GetPtr() const;
|
||||
@ -502,6 +553,12 @@ nsAttrValue::BaseType() const
|
||||
return static_cast<ValueBaseType>(mBits & NS_ATTRVALUE_BASETYPE_MASK);
|
||||
}
|
||||
|
||||
inline bool
|
||||
nsAttrValue::IsSVGType(ValueType aType) const
|
||||
{
|
||||
return aType >= eSVGTypesBegin && aType <= eSVGTypesEnd;
|
||||
}
|
||||
|
||||
inline void
|
||||
nsAttrValue::SetPtrValueAndType(void* aValue, ValueBaseType aType)
|
||||
{
|
||||
|
@ -89,6 +89,7 @@ nsEventSource::nsEventSource() :
|
||||
mErrorLoadOnRedirect(false),
|
||||
mGoingToDispatchAllMessages(false),
|
||||
mWithCredentials(false),
|
||||
mWaitingForOnStopRequest(false),
|
||||
mLastConvertionResult(NS_OK),
|
||||
mReadyState(nsIEventSource::CONNECTING),
|
||||
mScriptLine(0),
|
||||
@ -108,13 +109,19 @@ nsEventSource::~nsEventSource()
|
||||
NS_IMPL_CYCLE_COLLECTION_CLASS(nsEventSource)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(nsEventSource)
|
||||
if (tmp->IsBlack()) {
|
||||
bool isBlack = tmp->IsBlack();
|
||||
if (isBlack || tmp->mWaitingForOnStopRequest) {
|
||||
if (tmp->mListenerManager) {
|
||||
tmp->mListenerManager->UnmarkGrayJSListeners();
|
||||
NS_UNMARK_LISTENER_WRAPPER(Open)
|
||||
NS_UNMARK_LISTENER_WRAPPER(Message)
|
||||
NS_UNMARK_LISTENER_WRAPPER(Error)
|
||||
}
|
||||
if (!isBlack) {
|
||||
xpc_UnmarkGrayObject(tmp->PreservingWrapper() ?
|
||||
tmp->GetWrapperPreserveColor() :
|
||||
tmp->GetExpandoObjectPreserveColor());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END
|
||||
@ -599,6 +606,8 @@ nsEventSource::OnStopRequest(nsIRequest *aRequest,
|
||||
nsISupports *aContext,
|
||||
nsresult aStatusCode)
|
||||
{
|
||||
mWaitingForOnStopRequest = false;
|
||||
|
||||
if (mReadyState == nsIEventSource::CLOSED) {
|
||||
return NS_ERROR_ABORT;
|
||||
}
|
||||
@ -949,7 +958,11 @@ nsEventSource::InitChannelAndRequestEventSource()
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Start reading from the channel
|
||||
return mHttpChannel->AsyncOpen(listener, nsnull);
|
||||
rv = mHttpChannel->AsyncOpen(listener, nsnull);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
mWaitingForOnStopRequest = true;
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -216,6 +216,7 @@ protected:
|
||||
bool mErrorLoadOnRedirect;
|
||||
bool mGoingToDispatchAllMessages;
|
||||
bool mWithCredentials;
|
||||
bool mWaitingForOnStopRequest;
|
||||
|
||||
// used while reading the input streams
|
||||
nsCOMPtr<nsIUnicodeDecoder> mUnicodeDecoder;
|
||||
|
@ -439,7 +439,8 @@ nsWebSocket::~nsWebSocket()
|
||||
NS_IMPL_CYCLE_COLLECTION_CLASS(nsWebSocket)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(nsWebSocket)
|
||||
if (tmp->IsBlack()) {
|
||||
bool isBlack = tmp->IsBlack();
|
||||
if (isBlack|| tmp->mKeepingAlive) {
|
||||
if (tmp->mListenerManager) {
|
||||
tmp->mListenerManager->UnmarkGrayJSListeners();
|
||||
NS_UNMARK_LISTENER_WRAPPER(Open)
|
||||
@ -447,6 +448,11 @@ NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(nsWebSocket)
|
||||
NS_UNMARK_LISTENER_WRAPPER(Message)
|
||||
NS_UNMARK_LISTENER_WRAPPER(Close)
|
||||
}
|
||||
if (!isBlack) {
|
||||
xpc_UnmarkGrayObject(tmp->PreservingWrapper() ?
|
||||
tmp->GetWrapperPreserveColor() :
|
||||
tmp->GetExpandoObjectPreserveColor());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END
|
||||
|
@ -445,8 +445,8 @@ nsXMLHttpRequest::nsXMLHttpRequest()
|
||||
mProgressSinceLastProgressEvent(false),
|
||||
mUploadProgress(0), mUploadProgressMax(0),
|
||||
mRequestSentTime(0), mTimeoutMilliseconds(0),
|
||||
mErrorLoad(false), mProgressTimerIsActive(false),
|
||||
mProgressEventWasDelayed(false),
|
||||
mErrorLoad(false), mWaitingForOnStopRequest(false),
|
||||
mProgressTimerIsActive(false), mProgressEventWasDelayed(false),
|
||||
mIsHtml(false),
|
||||
mWarnAboutMultipartHtml(false),
|
||||
mWarnAboutSyncHtml(false),
|
||||
@ -602,7 +602,8 @@ nsXMLHttpRequest::SetRequestObserver(nsIRequestObserver* aObserver)
|
||||
NS_IMPL_CYCLE_COLLECTION_CLASS(nsXMLHttpRequest)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(nsXMLHttpRequest)
|
||||
if (tmp->IsBlack()) {
|
||||
bool isBlack = tmp->IsBlack();
|
||||
if (isBlack || tmp->mWaitingForOnStopRequest) {
|
||||
if (tmp->mListenerManager) {
|
||||
tmp->mListenerManager->UnmarkGrayJSListeners();
|
||||
NS_UNMARK_LISTENER_WRAPPER(Load)
|
||||
@ -614,6 +615,11 @@ NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(nsXMLHttpRequest)
|
||||
NS_UNMARK_LISTENER_WRAPPER(UploadProgress)
|
||||
NS_UNMARK_LISTENER_WRAPPER(Readystatechange)
|
||||
}
|
||||
if (!isBlack) {
|
||||
xpc_UnmarkGrayObject(tmp->PreservingWrapper() ?
|
||||
tmp->GetWrapperPreserveColor() :
|
||||
tmp->GetExpandoObjectPreserveColor());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END
|
||||
@ -2140,6 +2146,8 @@ nsXMLHttpRequest::OnStopRequest(nsIRequest *request, nsISupports *ctxt, nsresult
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
mWaitingForOnStopRequest = false;
|
||||
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
// If we're loading a multipart stream of XML documents, we'll get
|
||||
@ -2774,6 +2782,9 @@ nsXMLHttpRequest::Send(nsIVariant *aBody)
|
||||
return rv;
|
||||
}
|
||||
|
||||
// Either AsyncOpen was called, or CORS will open the channel later.
|
||||
mWaitingForOnStopRequest = true;
|
||||
|
||||
// If we're synchronous, spin an event loop here and wait
|
||||
if (!(mState & XML_HTTP_REQUEST_ASYNC)) {
|
||||
mState |= XML_HTTP_REQUEST_SYNCLOOPING;
|
||||
|
@ -365,7 +365,7 @@ protected:
|
||||
void HandleTimeoutCallback();
|
||||
|
||||
bool mErrorLoad;
|
||||
|
||||
bool mWaitingForOnStopRequest;
|
||||
bool mProgressTimerIsActive;
|
||||
bool mProgressEventWasDelayed;
|
||||
bool mIsHtml;
|
||||
|
@ -49,7 +49,7 @@ function attr_modified(ev) {
|
||||
e_prev = e_new;
|
||||
if (!recursive) {
|
||||
recursive = true;
|
||||
e_new = "width: 0pt;";
|
||||
e_new = "width: 0px;";
|
||||
testDiv.style.width = "0";
|
||||
} else {
|
||||
recursive = false;
|
||||
|
@ -2388,6 +2388,7 @@ public:
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIWEBGLEXTENSION
|
||||
virtual ~WebGLExtension() {}
|
||||
};
|
||||
|
||||
inline const WebGLRectangleObject *WebGLContext::FramebufferRectangleObject() const {
|
||||
|
@ -42,7 +42,7 @@
|
||||
#include "nsIConstraintValidation.h"
|
||||
|
||||
|
||||
class nsDOMValidityState : public nsIDOMValidityState
|
||||
class nsDOMValidityState MOZ_FINAL : public nsIDOMValidityState
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
@ -185,7 +185,7 @@ static const nsAttrValue::EnumTable* kInputDefaultAutocomplete = &kInputAutocomp
|
||||
{0xb5, 0x13, 0x7b, 0x36, 0x93, 0x43, 0xe3, 0xa0} \
|
||||
}
|
||||
|
||||
class nsHTMLInputElementState : public nsISupports
|
||||
class nsHTMLInputElementState MOZ_FINAL : public nsISupports
|
||||
{
|
||||
public:
|
||||
NS_DECLARE_STATIC_IID_ACCESSOR(NS_INPUT_ELEMENT_STATE_IID)
|
||||
|
@ -57,7 +57,7 @@ class nsIRadioGroupContainer;
|
||||
class nsIRadioGroupVisitor;
|
||||
class nsIRadioVisitor;
|
||||
|
||||
class UploadLastDir : public nsIObserver, public nsSupportsWeakReference {
|
||||
class UploadLastDir MOZ_FINAL : public nsIObserver, public nsSupportsWeakReference {
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIOBSERVER
|
||||
|
@ -243,10 +243,10 @@ public:
|
||||
* to an nsIChannel, which holds a reference to this listener.
|
||||
* We break the reference cycle in OnStartRequest by clearing mElement.
|
||||
*/
|
||||
class nsHTMLMediaElement::MediaLoadListener : public nsIStreamListener,
|
||||
public nsIChannelEventSink,
|
||||
public nsIInterfaceRequestor,
|
||||
public nsIObserver
|
||||
class nsHTMLMediaElement::MediaLoadListener MOZ_FINAL : public nsIStreamListener,
|
||||
public nsIChannelEventSink,
|
||||
public nsIInterfaceRequestor,
|
||||
public nsIObserver
|
||||
{
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIREQUESTOBSERVER
|
||||
|
@ -37,8 +37,9 @@
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
#include "nsIDOMMediaError.h"
|
||||
#include "nsISupports.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
|
||||
class nsMediaError : public nsIDOMMediaError
|
||||
class nsMediaError MOZ_FINAL : public nsIDOMMediaError
|
||||
{
|
||||
public:
|
||||
nsMediaError(PRUint16 aCode);
|
||||
|
@ -45,7 +45,7 @@
|
||||
|
||||
// Implements media TimeRanges:
|
||||
// http://www.whatwg.org/specs/web-apps/current-work/multipage/video.html#timeranges
|
||||
class nsTimeRanges : public nsIDOMTimeRanges {
|
||||
class nsTimeRanges MOZ_FINAL : public nsIDOMTimeRanges {
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIDOMTIMERANGES
|
||||
|
@ -216,6 +216,7 @@ nsresult nsBuiltinDecoder::Load(MediaResource* aResource,
|
||||
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
|
||||
mDecoderStateMachine->SetSeekable(mSeekable);
|
||||
mDecoderStateMachine->SetDuration(mDuration);
|
||||
mDecoderStateMachine->SetVolume(mInitialVolume);
|
||||
|
||||
if (mFrameBufferLength > 0) {
|
||||
// The valid mFrameBufferLength value was specified earlier
|
||||
|
@ -156,8 +156,14 @@ DOMSVGLength::SetValue(float aUserUnitValue)
|
||||
// unit as it is.
|
||||
|
||||
if (HasOwner()) {
|
||||
if (InternalItem().SetFromUserUnitValue(aUserUnitValue, Element(), Axis())) {
|
||||
Element()->DidChangeLengthList(mAttrEnum, true);
|
||||
if (InternalItem().GetValueInUserUnits(Element(), Axis()) ==
|
||||
aUserUnitValue) {
|
||||
return NS_OK;
|
||||
}
|
||||
nsAttrValue emptyOrOldValue = Element()->WillChangeLengthList(mAttrEnum);
|
||||
if (InternalItem().SetFromUserUnitValue(aUserUnitValue, Element(), Axis()))
|
||||
{
|
||||
Element()->DidChangeLengthList(mAttrEnum, emptyOrOldValue);
|
||||
if (mList->mAList->IsAnimating()) {
|
||||
Element()->AnimationNeedsResample();
|
||||
}
|
||||
@ -195,8 +201,12 @@ DOMSVGLength::SetValueInSpecifiedUnits(float aValue)
|
||||
}
|
||||
|
||||
if (HasOwner()) {
|
||||
if (InternalItem().GetValueInCurrentUnits() == aValue) {
|
||||
return NS_OK;
|
||||
}
|
||||
nsAttrValue emptyOrOldValue = Element()->WillChangeLengthList(mAttrEnum);
|
||||
InternalItem().SetValueInCurrentUnits(aValue);
|
||||
Element()->DidChangeLengthList(mAttrEnum, true);
|
||||
Element()->DidChangeLengthList(mAttrEnum, emptyOrOldValue);
|
||||
if (mList->mAList->IsAnimating()) {
|
||||
Element()->AnimationNeedsResample();
|
||||
}
|
||||
@ -218,8 +228,12 @@ DOMSVGLength::SetValueAsString(const nsAString& aValue)
|
||||
return NS_ERROR_DOM_SYNTAX_ERR;
|
||||
}
|
||||
if (HasOwner()) {
|
||||
if (InternalItem() == value) {
|
||||
return NS_OK;
|
||||
}
|
||||
nsAttrValue emptyOrOldValue = Element()->WillChangeLengthList(mAttrEnum);
|
||||
InternalItem() = value;
|
||||
Element()->DidChangeLengthList(mAttrEnum, true);
|
||||
Element()->DidChangeLengthList(mAttrEnum, emptyOrOldValue);
|
||||
if (mList->mAList->IsAnimating()) {
|
||||
Element()->AnimationNeedsResample();
|
||||
}
|
||||
@ -259,8 +273,13 @@ DOMSVGLength::NewValueSpecifiedUnits(PRUint16 aUnit, float aValue)
|
||||
return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
|
||||
}
|
||||
if (HasOwner()) {
|
||||
if (InternalItem().GetUnit() == aUnit &&
|
||||
InternalItem().GetValueInCurrentUnits() == aValue) {
|
||||
return NS_OK;
|
||||
}
|
||||
nsAttrValue emptyOrOldValue = Element()->WillChangeLengthList(mAttrEnum);
|
||||
InternalItem().SetValueAndUnit(aValue, PRUint8(aUnit));
|
||||
Element()->DidChangeLengthList(mAttrEnum, true);
|
||||
Element()->DidChangeLengthList(mAttrEnum, emptyOrOldValue);
|
||||
if (mList->mAList->IsAnimating()) {
|
||||
Element()->AnimationNeedsResample();
|
||||
}
|
||||
@ -282,7 +301,12 @@ DOMSVGLength::ConvertToSpecifiedUnits(PRUint16 aUnit)
|
||||
return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
|
||||
}
|
||||
if (HasOwner()) {
|
||||
if (InternalItem().GetUnit() == aUnit) {
|
||||
return NS_OK;
|
||||
}
|
||||
nsAttrValue emptyOrOldValue = Element()->WillChangeLengthList(mAttrEnum);
|
||||
if (InternalItem().ConvertToUnit(PRUint8(aUnit), Element(), Axis())) {
|
||||
Element()->DidChangeLengthList(mAttrEnum, emptyOrOldValue);
|
||||
return NS_OK;
|
||||
}
|
||||
} else {
|
||||
|
@ -171,6 +171,7 @@ DOMSVGLengthList::Clear()
|
||||
}
|
||||
|
||||
if (Length() > 0) {
|
||||
nsAttrValue emptyOrOldValue = Element()->WillChangeLengthList(AttrEnum());
|
||||
// Notify any existing DOM items of removal *before* truncating the lists
|
||||
// so that they can find their SVGLength internal counterparts and copy
|
||||
// their values. This also notifies the animVal list:
|
||||
@ -178,7 +179,7 @@ DOMSVGLengthList::Clear()
|
||||
|
||||
mItems.Clear();
|
||||
InternalList().Clear();
|
||||
Element()->DidChangeLengthList(AttrEnum(), true);
|
||||
Element()->DidChangeLengthList(AttrEnum(), emptyOrOldValue);
|
||||
if (mAList->IsAnimating()) {
|
||||
Element()->AnimationNeedsResample();
|
||||
}
|
||||
@ -256,6 +257,7 @@ DOMSVGLengthList::InsertItemBefore(nsIDOMSVGLength *newItem,
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
nsAttrValue emptyOrOldValue = Element()->WillChangeLengthList(AttrEnum());
|
||||
// Now that we know we're inserting, keep animVal list in sync as necessary.
|
||||
MaybeInsertNullInAnimValListAt(index);
|
||||
|
||||
@ -269,7 +271,7 @@ DOMSVGLengthList::InsertItemBefore(nsIDOMSVGLength *newItem,
|
||||
|
||||
UpdateListIndicesFromIndex(mItems, index + 1);
|
||||
|
||||
Element()->DidChangeLengthList(AttrEnum(), true);
|
||||
Element()->DidChangeLengthList(AttrEnum(), emptyOrOldValue);
|
||||
if (mAList->IsAnimating()) {
|
||||
Element()->AnimationNeedsResample();
|
||||
}
|
||||
@ -298,6 +300,7 @@ DOMSVGLengthList::ReplaceItem(nsIDOMSVGLength *newItem,
|
||||
domItem = domItem->Copy(); // must do this before changing anything!
|
||||
}
|
||||
|
||||
nsAttrValue emptyOrOldValue = Element()->WillChangeLengthList(AttrEnum());
|
||||
if (mItems[index]) {
|
||||
// Notify any existing DOM item of removal *before* modifying the lists so
|
||||
// that the DOM item can copy the *old* value at its index:
|
||||
@ -311,7 +314,7 @@ DOMSVGLengthList::ReplaceItem(nsIDOMSVGLength *newItem,
|
||||
// would end up reading bad data from InternalList()!
|
||||
domItem->InsertingIntoList(this, AttrEnum(), index, IsAnimValList());
|
||||
|
||||
Element()->DidChangeLengthList(AttrEnum(), true);
|
||||
Element()->DidChangeLengthList(AttrEnum(), emptyOrOldValue);
|
||||
if (mAList->IsAnimating()) {
|
||||
Element()->AnimationNeedsResample();
|
||||
}
|
||||
@ -332,6 +335,7 @@ DOMSVGLengthList::RemoveItem(PRUint32 index,
|
||||
return NS_ERROR_DOM_INDEX_SIZE_ERR;
|
||||
}
|
||||
|
||||
nsAttrValue emptyOrOldValue = Element()->WillChangeLengthList(AttrEnum());
|
||||
// Now that we know we're removing, keep animVal list in sync as necessary.
|
||||
// Do this *before* touching InternalList() so the removed item can get its
|
||||
// internal value.
|
||||
@ -350,7 +354,7 @@ DOMSVGLengthList::RemoveItem(PRUint32 index,
|
||||
|
||||
UpdateListIndicesFromIndex(mItems, index);
|
||||
|
||||
Element()->DidChangeLengthList(AttrEnum(), true);
|
||||
Element()->DidChangeLengthList(AttrEnum(), emptyOrOldValue);
|
||||
if (mAList->IsAnimating()) {
|
||||
Element()->AnimationNeedsResample();
|
||||
}
|
||||
|
@ -123,8 +123,12 @@ DOMSVGNumber::SetValue(float aValue)
|
||||
NS_ENSURE_FINITE(aValue, NS_ERROR_ILLEGAL_VALUE);
|
||||
|
||||
if (HasOwner()) {
|
||||
if (InternalItem() == aValue) {
|
||||
return NS_OK;
|
||||
}
|
||||
nsAttrValue emptyOrOldValue = Element()->WillChangeNumberList(mAttrEnum);
|
||||
InternalItem() = aValue;
|
||||
Element()->DidChangeNumberList(mAttrEnum, true);
|
||||
Element()->DidChangeNumberList(mAttrEnum, emptyOrOldValue);
|
||||
if (mList->mAList->IsAnimating()) {
|
||||
Element()->AnimationNeedsResample();
|
||||
}
|
||||
|
@ -171,6 +171,7 @@ DOMSVGNumberList::Clear()
|
||||
}
|
||||
|
||||
if (Length() > 0) {
|
||||
nsAttrValue emptyOrOldValue = Element()->WillChangeNumberList(AttrEnum());
|
||||
// Notify any existing DOM items of removal *before* truncating the lists
|
||||
// so that they can find their SVGNumber internal counterparts and copy
|
||||
// their values. This also notifies the animVal list:
|
||||
@ -178,7 +179,7 @@ DOMSVGNumberList::Clear()
|
||||
|
||||
mItems.Clear();
|
||||
InternalList().Clear();
|
||||
Element()->DidChangeNumberList(AttrEnum(), true);
|
||||
Element()->DidChangeNumberList(AttrEnum(), emptyOrOldValue);
|
||||
if (mAList->IsAnimating()) {
|
||||
Element()->AnimationNeedsResample();
|
||||
}
|
||||
@ -256,6 +257,7 @@ DOMSVGNumberList::InsertItemBefore(nsIDOMSVGNumber *newItem,
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
nsAttrValue emptyOrOldValue = Element()->WillChangeNumberList(AttrEnum());
|
||||
// Now that we know we're inserting, keep animVal list in sync as necessary.
|
||||
MaybeInsertNullInAnimValListAt(index);
|
||||
|
||||
@ -269,7 +271,7 @@ DOMSVGNumberList::InsertItemBefore(nsIDOMSVGNumber *newItem,
|
||||
|
||||
UpdateListIndicesFromIndex(mItems, index + 1);
|
||||
|
||||
Element()->DidChangeNumberList(AttrEnum(), true);
|
||||
Element()->DidChangeNumberList(AttrEnum(), emptyOrOldValue);
|
||||
if (mAList->IsAnimating()) {
|
||||
Element()->AnimationNeedsResample();
|
||||
}
|
||||
@ -298,6 +300,7 @@ DOMSVGNumberList::ReplaceItem(nsIDOMSVGNumber *newItem,
|
||||
domItem = domItem->Clone(); // must do this before changing anything!
|
||||
}
|
||||
|
||||
nsAttrValue emptyOrOldValue = Element()->WillChangeNumberList(AttrEnum());
|
||||
if (mItems[index]) {
|
||||
// Notify any existing DOM item of removal *before* modifying the lists so
|
||||
// that the DOM item can copy the *old* value at its index:
|
||||
@ -311,7 +314,7 @@ DOMSVGNumberList::ReplaceItem(nsIDOMSVGNumber *newItem,
|
||||
// would end up reading bad data from InternalList()!
|
||||
domItem->InsertingIntoList(this, AttrEnum(), index, IsAnimValList());
|
||||
|
||||
Element()->DidChangeNumberList(AttrEnum(), true);
|
||||
Element()->DidChangeNumberList(AttrEnum(), emptyOrOldValue);
|
||||
if (mAList->IsAnimating()) {
|
||||
Element()->AnimationNeedsResample();
|
||||
}
|
||||
@ -340,6 +343,7 @@ DOMSVGNumberList::RemoveItem(PRUint32 index,
|
||||
// We have to return the removed item, so make sure it exists:
|
||||
EnsureItemAt(index);
|
||||
|
||||
nsAttrValue emptyOrOldValue = Element()->WillChangeNumberList(AttrEnum());
|
||||
// Notify the DOM item of removal *before* modifying the lists so that the
|
||||
// DOM item can copy its *old* value:
|
||||
mItems[index]->RemovingFromList();
|
||||
@ -350,7 +354,7 @@ DOMSVGNumberList::RemoveItem(PRUint32 index,
|
||||
|
||||
UpdateListIndicesFromIndex(mItems, index);
|
||||
|
||||
Element()->DidChangeNumberList(AttrEnum(), true);
|
||||
Element()->DidChangeNumberList(AttrEnum(), emptyOrOldValue);
|
||||
if (mAList->IsAnimating()) {
|
||||
Element()->AnimationNeedsResample();
|
||||
}
|
||||
|
@ -245,9 +245,13 @@ DOMSVGPathSeg::IndexIsValid()
|
||||
} \
|
||||
NS_ENSURE_FINITE(float(a##propName), NS_ERROR_ILLEGAL_VALUE); \
|
||||
if (HasOwner()) { \
|
||||
if (InternalItem()[1+index] == float(a##propName)) { \
|
||||
return NS_OK; \
|
||||
} \
|
||||
NS_ABORT_IF_FALSE(IsInList(), "Will/DidChangePathSegList() is wrong"); \
|
||||
nsAttrValue emptyOrOldValue = Element()->WillChangePathSegList(); \
|
||||
InternalItem()[1+index] = float(a##propName); \
|
||||
NS_ABORT_IF_FALSE(IsInList(), "DidChangePathSegList() is wrong"); \
|
||||
Element()->DidChangePathSegList(true); \
|
||||
Element()->DidChangePathSegList(emptyOrOldValue); \
|
||||
if (mList->AttrIsAnimating()) { \
|
||||
Element()->AnimationNeedsResample(); \
|
||||
} \
|
||||
|
@ -269,6 +269,7 @@ DOMSVGPathSegList::Clear()
|
||||
}
|
||||
|
||||
if (Length() > 0) {
|
||||
nsAttrValue emptyOrOldValue = Element()->WillChangePathSegList();
|
||||
// DOM list items that are to be removed must be removed before we change
|
||||
// the internal list, otherwise they wouldn't be able to copy their
|
||||
// internal counterparts' values!
|
||||
@ -285,7 +286,7 @@ DOMSVGPathSegList::Clear()
|
||||
}
|
||||
|
||||
InternalList().Clear();
|
||||
Element()->DidChangePathSegList(true);
|
||||
Element()->DidChangePathSegList(emptyOrOldValue);
|
||||
if (AttrIsAnimating()) {
|
||||
Element()->AnimationNeedsResample();
|
||||
}
|
||||
@ -371,6 +372,7 @@ DOMSVGPathSegList::InsertItemBefore(nsIDOMSVGPathSeg *aNewItem,
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
nsAttrValue emptyOrOldValue = Element()->WillChangePathSegList();
|
||||
// Now that we know we're inserting, keep animVal list in sync as necessary.
|
||||
MaybeInsertNullInAnimValListAt(aIndex, internalIndex, argCount);
|
||||
|
||||
@ -387,7 +389,7 @@ DOMSVGPathSegList::InsertItemBefore(nsIDOMSVGPathSeg *aNewItem,
|
||||
|
||||
UpdateListIndicesFromIndex(aIndex + 1, argCount + 1);
|
||||
|
||||
Element()->DidChangePathSegList(true);
|
||||
Element()->DidChangePathSegList(emptyOrOldValue);
|
||||
if (AttrIsAnimating()) {
|
||||
Element()->AnimationNeedsResample();
|
||||
}
|
||||
@ -416,6 +418,7 @@ DOMSVGPathSegList::ReplaceItem(nsIDOMSVGPathSeg *aNewItem,
|
||||
domItem = domItem->Clone(); // must do this before changing anything!
|
||||
}
|
||||
|
||||
nsAttrValue emptyOrOldValue = Element()->WillChangePathSegList();
|
||||
if (ItemAt(aIndex)) {
|
||||
// Notify any existing DOM item of removal *before* modifying the lists so
|
||||
// that the DOM item can copy the *old* value at its index:
|
||||
@ -451,7 +454,7 @@ DOMSVGPathSegList::ReplaceItem(nsIDOMSVGPathSeg *aNewItem,
|
||||
}
|
||||
}
|
||||
|
||||
Element()->DidChangePathSegList(true);
|
||||
Element()->DidChangePathSegList(emptyOrOldValue);
|
||||
if (AttrIsAnimating()) {
|
||||
Element()->AnimationNeedsResample();
|
||||
}
|
||||
@ -474,6 +477,7 @@ DOMSVGPathSegList::RemoveItem(PRUint32 aIndex,
|
||||
// We have to return the removed item, so make sure it exists:
|
||||
EnsureItemAt(aIndex);
|
||||
|
||||
nsAttrValue emptyOrOldValue = Element()->WillChangePathSegList();
|
||||
// Notify the DOM item of removal *before* modifying the lists so that the
|
||||
// DOM item can copy its *old* value:
|
||||
ItemAt(aIndex)->RemovingFromList();
|
||||
@ -493,7 +497,7 @@ DOMSVGPathSegList::RemoveItem(PRUint32 aIndex,
|
||||
|
||||
UpdateListIndicesFromIndex(aIndex, -(argCount + 1));
|
||||
|
||||
Element()->DidChangePathSegList(true);
|
||||
Element()->DidChangePathSegList(emptyOrOldValue);
|
||||
if (AttrIsAnimating()) {
|
||||
Element()->AnimationNeedsResample();
|
||||
}
|
||||
|
@ -98,8 +98,12 @@ DOMSVGPoint::SetX(float aX)
|
||||
NS_ENSURE_FINITE(aX, NS_ERROR_ILLEGAL_VALUE);
|
||||
|
||||
if (HasOwner()) {
|
||||
if (InternalItem().mX == aX) {
|
||||
return NS_OK;
|
||||
}
|
||||
nsAttrValue emptyOrOldValue = Element()->WillChangePointList();
|
||||
InternalItem().mX = aX;
|
||||
Element()->DidChangePointList(true);
|
||||
Element()->DidChangePointList(emptyOrOldValue);
|
||||
if (mList->AttrIsAnimating()) {
|
||||
Element()->AnimationNeedsResample();
|
||||
}
|
||||
@ -129,8 +133,12 @@ DOMSVGPoint::SetY(float aY)
|
||||
NS_ENSURE_FINITE(aY, NS_ERROR_ILLEGAL_VALUE);
|
||||
|
||||
if (HasOwner()) {
|
||||
if (InternalItem().mY == aY) {
|
||||
return NS_OK;
|
||||
}
|
||||
nsAttrValue emptyOrOldValue = Element()->WillChangePointList();
|
||||
InternalItem().mY = aY;
|
||||
Element()->DidChangePointList(true);
|
||||
Element()->DidChangePointList(emptyOrOldValue);
|
||||
if (mList->AttrIsAnimating()) {
|
||||
Element()->AnimationNeedsResample();
|
||||
}
|
||||
|
@ -213,6 +213,7 @@ DOMSVGPointList::Clear()
|
||||
}
|
||||
|
||||
if (Length() > 0) {
|
||||
nsAttrValue emptyOrOldValue = Element()->WillChangePointList();
|
||||
// DOM list items that are to be removed must be removed before we change
|
||||
// the internal list, otherwise they wouldn't be able to copy their
|
||||
// internal counterparts' values!
|
||||
@ -229,7 +230,7 @@ DOMSVGPointList::Clear()
|
||||
}
|
||||
|
||||
InternalList().Clear();
|
||||
Element()->DidChangePointList(true);
|
||||
Element()->DidChangePointList(emptyOrOldValue);
|
||||
if (AttrIsAnimating()) {
|
||||
Element()->AnimationNeedsResample();
|
||||
}
|
||||
@ -307,6 +308,7 @@ DOMSVGPointList::InsertItemBefore(nsIDOMSVGPoint *aNewItem,
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
nsAttrValue emptyOrOldValue = Element()->WillChangePointList();
|
||||
// Now that we know we're inserting, keep animVal list in sync as necessary.
|
||||
MaybeInsertNullInAnimValListAt(aIndex);
|
||||
|
||||
@ -320,7 +322,7 @@ DOMSVGPointList::InsertItemBefore(nsIDOMSVGPoint *aNewItem,
|
||||
|
||||
UpdateListIndicesFromIndex(mItems, aIndex + 1);
|
||||
|
||||
Element()->DidChangePointList(true);
|
||||
Element()->DidChangePointList(emptyOrOldValue);
|
||||
if (AttrIsAnimating()) {
|
||||
Element()->AnimationNeedsResample();
|
||||
}
|
||||
@ -349,6 +351,7 @@ DOMSVGPointList::ReplaceItem(nsIDOMSVGPoint *aNewItem,
|
||||
domItem = domItem->Clone(); // must do this before changing anything!
|
||||
}
|
||||
|
||||
nsAttrValue emptyOrOldValue = Element()->WillChangePointList();
|
||||
if (mItems[aIndex]) {
|
||||
// Notify any existing DOM item of removal *before* modifying the lists so
|
||||
// that the DOM item can copy the *old* value at its index:
|
||||
@ -362,7 +365,7 @@ DOMSVGPointList::ReplaceItem(nsIDOMSVGPoint *aNewItem,
|
||||
// would end up reading bad data from InternalList()!
|
||||
domItem->InsertingIntoList(this, aIndex, IsAnimValList());
|
||||
|
||||
Element()->DidChangePointList(true);
|
||||
Element()->DidChangePointList(emptyOrOldValue);
|
||||
if (AttrIsAnimating()) {
|
||||
Element()->AnimationNeedsResample();
|
||||
}
|
||||
@ -383,6 +386,7 @@ DOMSVGPointList::RemoveItem(PRUint32 aIndex,
|
||||
return NS_ERROR_DOM_INDEX_SIZE_ERR;
|
||||
}
|
||||
|
||||
nsAttrValue emptyOrOldValue = Element()->WillChangePointList();
|
||||
// Now that we know we're removing, keep animVal list in sync as necessary.
|
||||
// Do this *before* touching InternalList() so the removed item can get its
|
||||
// internal value.
|
||||
@ -401,7 +405,7 @@ DOMSVGPointList::RemoveItem(PRUint32 aIndex,
|
||||
|
||||
UpdateListIndicesFromIndex(mItems, aIndex);
|
||||
|
||||
Element()->DidChangePointList(true);
|
||||
Element()->DidChangePointList(emptyOrOldValue);
|
||||
if (AttrIsAnimating()) {
|
||||
Element()->AnimationNeedsResample();
|
||||
}
|
||||
|
@ -109,9 +109,12 @@ NS_IMETHODIMP
|
||||
DOMSVGStringList::Clear()
|
||||
{
|
||||
if (InternalList().IsExplicitlySet()) {
|
||||
nsAttrValue emptyOrOldValue =
|
||||
mElement->WillChangeStringList(mIsConditionalProcessingAttribute,
|
||||
mAttrEnum);
|
||||
InternalList().Clear();
|
||||
mElement->DidChangeStringList(mIsConditionalProcessingAttribute,
|
||||
mAttrEnum);
|
||||
mAttrEnum, emptyOrOldValue);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
@ -151,9 +154,13 @@ DOMSVGStringList::InsertItemBefore(const nsAString & newItem,
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
nsAttrValue emptyOrOldValue =
|
||||
mElement->WillChangeStringList(mIsConditionalProcessingAttribute,
|
||||
mAttrEnum);
|
||||
InternalList().InsertItem(index, newItem);
|
||||
|
||||
mElement->DidChangeStringList(mIsConditionalProcessingAttribute, mAttrEnum);
|
||||
mElement->DidChangeStringList(mIsConditionalProcessingAttribute, mAttrEnum,
|
||||
emptyOrOldValue);
|
||||
_retval = newItem;
|
||||
return NS_OK;
|
||||
}
|
||||
@ -171,9 +178,13 @@ DOMSVGStringList::ReplaceItem(const nsAString & newItem,
|
||||
}
|
||||
|
||||
_retval = InternalList()[index];
|
||||
nsAttrValue emptyOrOldValue =
|
||||
mElement->WillChangeStringList(mIsConditionalProcessingAttribute,
|
||||
mAttrEnum);
|
||||
InternalList().ReplaceItem(index, newItem);
|
||||
|
||||
mElement->DidChangeStringList(mIsConditionalProcessingAttribute, mAttrEnum);
|
||||
mElement->DidChangeStringList(mIsConditionalProcessingAttribute, mAttrEnum,
|
||||
emptyOrOldValue);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -185,9 +196,13 @@ DOMSVGStringList::RemoveItem(PRUint32 index,
|
||||
return NS_ERROR_DOM_INDEX_SIZE_ERR;
|
||||
}
|
||||
|
||||
nsAttrValue emptyOrOldValue =
|
||||
mElement->WillChangeStringList(mIsConditionalProcessingAttribute,
|
||||
mAttrEnum);
|
||||
InternalList().RemoveItem(index);
|
||||
|
||||
mElement->DidChangeStringList(mIsConditionalProcessingAttribute, mAttrEnum);
|
||||
mElement->DidChangeStringList(mIsConditionalProcessingAttribute, mAttrEnum,
|
||||
emptyOrOldValue);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -111,8 +111,6 @@ private:
|
||||
|
||||
~DOMSVGStringList();
|
||||
|
||||
void DidChangeStringList(PRUint8 aAttrEnum, bool aDoSetAttr);
|
||||
|
||||
SVGStringList &InternalList();
|
||||
|
||||
// Strong ref to our element to keep it alive.
|
||||
|
@ -48,13 +48,18 @@ using namespace mozilla;
|
||||
|
||||
NS_IMPL_ISUPPORTS1(DOMSVGTests, nsIDOMSVGTests)
|
||||
|
||||
DOMSVGTests::StringListInfo DOMSVGTests::sStringListInfo[3] =
|
||||
nsIAtom** DOMSVGTests::sStringListNames[3] =
|
||||
{
|
||||
{ &nsGkAtoms::requiredFeatures, false },
|
||||
{ &nsGkAtoms::requiredExtensions, false },
|
||||
{ &nsGkAtoms::systemLanguage, true }
|
||||
&nsGkAtoms::requiredFeatures,
|
||||
&nsGkAtoms::requiredExtensions,
|
||||
&nsGkAtoms::systemLanguage,
|
||||
};
|
||||
|
||||
DOMSVGTests::DOMSVGTests()
|
||||
{
|
||||
mStringListAttributes[LANGUAGE].SetIsCommaSeparated(true);
|
||||
}
|
||||
|
||||
/* readonly attribute nsIDOMSVGStringList requiredFeatures; */
|
||||
NS_IMETHODIMP
|
||||
DOMSVGTests::GetRequiredFeatures(nsIDOMSVGStringList * *aRequiredFeatures)
|
||||
@ -96,8 +101,8 @@ DOMSVGTests::HasExtension(const nsAString & extension, bool *_retval)
|
||||
bool
|
||||
DOMSVGTests::IsConditionalProcessingAttribute(const nsIAtom* aAttribute) const
|
||||
{
|
||||
for (PRUint32 i = 0; i < ArrayLength(sStringListInfo); i++) {
|
||||
if (aAttribute == *sStringListInfo[i].mName) {
|
||||
for (PRUint32 i = 0; i < ArrayLength(sStringListNames); i++) {
|
||||
if (aAttribute == *sStringListNames[i]) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -222,10 +227,9 @@ DOMSVGTests::ParseConditionalProcessingAttribute(nsIAtom* aAttribute,
|
||||
const nsAString& aValue,
|
||||
nsAttrValue& aResult)
|
||||
{
|
||||
for (PRUint32 i = 0; i < ArrayLength(sStringListInfo); i++) {
|
||||
if (aAttribute == *sStringListInfo[i].mName) {
|
||||
nsresult rv = mStringListAttributes[i].SetValue(
|
||||
aValue, sStringListInfo[i].mIsCommaSeparated);
|
||||
for (PRUint32 i = 0; i < ArrayLength(sStringListNames); i++) {
|
||||
if (aAttribute == *sStringListNames[i]) {
|
||||
nsresult rv = mStringListAttributes[i].SetValue(aValue);
|
||||
if (NS_FAILED(rv)) {
|
||||
mStringListAttributes[i].Clear();
|
||||
}
|
||||
@ -236,20 +240,11 @@ DOMSVGTests::ParseConditionalProcessingAttribute(nsIAtom* aAttribute,
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
DOMSVGTests::GetValue(PRUint8 aAttrEnum, nsAString& aValue) const
|
||||
{
|
||||
NS_ABORT_IF_FALSE(aAttrEnum >= 0 && aAttrEnum < ArrayLength(sStringListInfo),
|
||||
"aAttrEnum out of range");
|
||||
mStringListAttributes[aAttrEnum].GetValue(
|
||||
aValue, sStringListInfo[aAttrEnum].mIsCommaSeparated);
|
||||
}
|
||||
|
||||
void
|
||||
DOMSVGTests::UnsetAttr(const nsIAtom* aAttribute)
|
||||
{
|
||||
for (PRUint32 i = 0; i < ArrayLength(sStringListInfo); i++) {
|
||||
if (aAttribute == *sStringListInfo[i].mName) {
|
||||
for (PRUint32 i = 0; i < ArrayLength(sStringListNames); i++) {
|
||||
if (aAttribute == *sStringListNames[i]) {
|
||||
mStringListAttributes[i].Clear();
|
||||
MaybeInvalidate();
|
||||
return;
|
||||
@ -257,22 +252,18 @@ DOMSVGTests::UnsetAttr(const nsIAtom* aAttribute)
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
DOMSVGTests::DidChangeStringList(PRUint8 aAttrEnum)
|
||||
nsIAtom*
|
||||
DOMSVGTests::GetAttrName(PRUint8 aAttrEnum) const
|
||||
{
|
||||
NS_ASSERTION(aAttrEnum < ArrayLength(sStringListInfo), "aAttrEnum out of range");
|
||||
return *sStringListNames[aAttrEnum];
|
||||
}
|
||||
|
||||
nsCOMPtr<nsSVGElement> element = do_QueryInterface(this);
|
||||
|
||||
nsAutoString serializedValue;
|
||||
GetValue(aAttrEnum, serializedValue);
|
||||
|
||||
nsAttrValue attrValue(serializedValue);
|
||||
element->SetParsedAttr(kNameSpaceID_None,
|
||||
*sStringListInfo[aAttrEnum].mName,
|
||||
nsnull, attrValue, true);
|
||||
|
||||
MaybeInvalidate();
|
||||
void
|
||||
DOMSVGTests::GetAttrValue(PRUint8 aAttrEnum, nsAttrValue& aValue) const
|
||||
{
|
||||
NS_ABORT_IF_FALSE(aAttrEnum >= 0 && aAttrEnum < ArrayLength(sStringListNames),
|
||||
"aAttrEnum out of range");
|
||||
aValue.SetTo(mStringListAttributes[aAttrEnum], nsnull);
|
||||
}
|
||||
|
||||
void
|
||||
@ -281,7 +272,7 @@ DOMSVGTests::MaybeInvalidate()
|
||||
nsCOMPtr<nsSVGElement> element = do_QueryInterface(this);
|
||||
|
||||
nsIContent* parent = element->GetFlattenedTreeParent();
|
||||
|
||||
|
||||
if (parent &&
|
||||
parent->NodeInfo()->Equals(nsGkAtoms::svgSwitch, kNameSpaceID_SVG)) {
|
||||
static_cast<nsSVGSwitchElement*>(parent)->MaybeInvalidate();
|
||||
|
@ -59,6 +59,8 @@ public:
|
||||
friend class mozilla::DOMSVGStringList;
|
||||
typedef mozilla::SVGStringList SVGStringList;
|
||||
|
||||
DOMSVGTests();
|
||||
|
||||
/**
|
||||
* Compare the language name(s) in a systemLanguage attribute to the
|
||||
* user's language preferences, as defined in
|
||||
@ -103,30 +105,20 @@ public:
|
||||
const nsAString& aValue,
|
||||
nsAttrValue& aResult);
|
||||
|
||||
/**
|
||||
* Serialises the conditional processing attribute.
|
||||
*/
|
||||
void GetValue(PRUint8 aAttrEnum, nsAString& aValue) const;
|
||||
|
||||
/**
|
||||
* Unsets a conditional processing attribute.
|
||||
*/
|
||||
void UnsetAttr(const nsIAtom* aAttribute);
|
||||
|
||||
void DidChangeStringList(PRUint8 aAttrEnum);
|
||||
nsIAtom* GetAttrName(PRUint8 aAttrEnum) const;
|
||||
void GetAttrValue(PRUint8 aAttrEnum, nsAttrValue &aValue) const;
|
||||
|
||||
void MaybeInvalidate();
|
||||
|
||||
private:
|
||||
|
||||
struct StringListInfo {
|
||||
nsIAtom** mName;
|
||||
bool mIsCommaSeparated;
|
||||
};
|
||||
|
||||
enum { FEATURES, EXTENSIONS, LANGUAGE };
|
||||
SVGStringList mStringListAttributes[3];
|
||||
static StringListInfo sStringListInfo[3];
|
||||
static nsIAtom** sStringListNames[3];
|
||||
};
|
||||
|
||||
#endif // MOZILLA_DOMSVGTESTS_H__
|
||||
|
@ -173,9 +173,7 @@ DOMSVGTransform::SetMatrix(nsIDOMSVGMatrix *matrix)
|
||||
if (!domMatrix)
|
||||
return NS_ERROR_DOM_SVG_WRONG_TYPE_ERR;
|
||||
|
||||
Transform().SetMatrix(domMatrix->Matrix());
|
||||
NotifyElementOfChange();
|
||||
|
||||
SetMatrix(domMatrix->Matrix());
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -188,8 +186,14 @@ DOMSVGTransform::SetTranslate(float tx, float ty)
|
||||
}
|
||||
NS_ENSURE_FINITE2(tx, ty, NS_ERROR_ILLEGAL_VALUE);
|
||||
|
||||
if (Transform().Type() == nsIDOMSVGTransform::SVG_TRANSFORM_TRANSLATE &&
|
||||
Matrix().x0 == tx && Matrix().y0 == ty) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsAttrValue emptyOrOldValue = NotifyElementWillChange();
|
||||
Transform().SetTranslate(tx, ty);
|
||||
NotifyElementOfChange();
|
||||
NotifyElementDidChange(emptyOrOldValue);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
@ -203,8 +207,14 @@ DOMSVGTransform::SetScale(float sx, float sy)
|
||||
}
|
||||
NS_ENSURE_FINITE2(sx, sy, NS_ERROR_ILLEGAL_VALUE);
|
||||
|
||||
if (Transform().Type() == nsIDOMSVGTransform::SVG_TRANSFORM_SCALE &&
|
||||
Matrix().xx == sx && Matrix().yy == sy) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsAttrValue emptyOrOldValue = NotifyElementWillChange();
|
||||
Transform().SetScale(sx, sy);
|
||||
NotifyElementOfChange();
|
||||
NotifyElementDidChange(emptyOrOldValue);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
@ -218,8 +228,17 @@ DOMSVGTransform::SetRotate(float angle, float cx, float cy)
|
||||
}
|
||||
NS_ENSURE_FINITE3(angle, cx, cy, NS_ERROR_ILLEGAL_VALUE);
|
||||
|
||||
if (Transform().Type() == nsIDOMSVGTransform::SVG_TRANSFORM_ROTATE) {
|
||||
float currentCx, currentCy;
|
||||
Transform().GetRotationOrigin(currentCx, currentCy);
|
||||
if (Transform().Angle() == angle && currentCx == cx && currentCy == cy) {
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
nsAttrValue emptyOrOldValue = NotifyElementWillChange();
|
||||
Transform().SetRotate(angle, cx, cy);
|
||||
NotifyElementOfChange();
|
||||
NotifyElementDidChange(emptyOrOldValue);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
@ -233,10 +252,16 @@ DOMSVGTransform::SetSkewX(float angle)
|
||||
}
|
||||
NS_ENSURE_FINITE(angle, NS_ERROR_ILLEGAL_VALUE);
|
||||
|
||||
if (Transform().Type() == nsIDOMSVGTransform::SVG_TRANSFORM_SKEWX &&
|
||||
Transform().Angle() == angle) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsAttrValue emptyOrOldValue = NotifyElementWillChange();
|
||||
nsresult rv = Transform().SetSkewX(angle);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
NotifyElementOfChange();
|
||||
NotifyElementDidChange(emptyOrOldValue);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
@ -250,10 +275,16 @@ DOMSVGTransform::SetSkewY(float angle)
|
||||
}
|
||||
NS_ENSURE_FINITE(angle, NS_ERROR_ILLEGAL_VALUE);
|
||||
|
||||
if (Transform().Type() == nsIDOMSVGTransform::SVG_TRANSFORM_SKEWY &&
|
||||
Transform().Angle() == angle) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsAttrValue emptyOrOldValue = NotifyElementWillChange();
|
||||
nsresult rv = Transform().SetSkewY(angle);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
NotifyElementOfChange();
|
||||
NotifyElementDidChange(emptyOrOldValue);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
@ -324,8 +355,15 @@ DOMSVGTransform::SetMatrix(const gfxMatrix& aMatrix)
|
||||
{
|
||||
NS_ABORT_IF_FALSE(!mIsAnimValItem,
|
||||
"Attempting to modify read-only transform");
|
||||
|
||||
if (Transform().Type() == nsIDOMSVGTransform::SVG_TRANSFORM_MATRIX &&
|
||||
SVGTransform::MatricesEqual(Matrix(), aMatrix)) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsAttrValue emptyOrOldValue = NotifyElementWillChange();
|
||||
Transform().SetMatrix(aMatrix);
|
||||
NotifyElementOfChange();
|
||||
NotifyElementDidChange(emptyOrOldValue);
|
||||
}
|
||||
|
||||
void
|
||||
@ -341,10 +379,10 @@ DOMSVGTransform::ClearMatrixTearoff(DOMSVGMatrix* aMatrix)
|
||||
// Implementation helpers
|
||||
|
||||
void
|
||||
DOMSVGTransform::NotifyElementOfChange()
|
||||
DOMSVGTransform::NotifyElementDidChange(const nsAttrValue& aEmptyOrOldValue)
|
||||
{
|
||||
if (HasOwner()) {
|
||||
Element()->DidChangeTransformList(true);
|
||||
Element()->DidChangeTransformList(aEmptyOrOldValue);
|
||||
if (mList->mAList->IsAnimating()) {
|
||||
Element()->AnimationNeedsResample();
|
||||
}
|
||||
|
@ -206,7 +206,8 @@ private:
|
||||
SVGTransform& Transform() {
|
||||
return HasOwner() ? InternalItem() : *mTransform;
|
||||
}
|
||||
void NotifyElementOfChange();
|
||||
inline nsAttrValue NotifyElementWillChange();
|
||||
void NotifyElementDidChange(const nsAttrValue& aEmptyOrOldValue);
|
||||
|
||||
nsRefPtr<DOMSVGTransformList> mList;
|
||||
|
||||
@ -235,6 +236,16 @@ private:
|
||||
|
||||
NS_DEFINE_STATIC_IID_ACCESSOR(DOMSVGTransform, MOZILLA_DOMSVGTRANSFORM_IID)
|
||||
|
||||
nsAttrValue
|
||||
DOMSVGTransform::NotifyElementWillChange()
|
||||
{
|
||||
nsAttrValue result;
|
||||
if (HasOwner()) {
|
||||
result = Element()->WillChangeTransformList();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#undef MOZ_SVG_LIST_INDEX_BIT_COUNT
|
||||
|
@ -184,6 +184,7 @@ DOMSVGTransformList::Clear()
|
||||
}
|
||||
|
||||
if (Length() > 0) {
|
||||
nsAttrValue emptyOrOldValue = Element()->WillChangeTransformList();
|
||||
// Notify any existing DOM items of removal *before* truncating the lists
|
||||
// so that they can find their SVGTransform internal counterparts and copy
|
||||
// their values. This also notifies the animVal list:
|
||||
@ -191,7 +192,7 @@ DOMSVGTransformList::Clear()
|
||||
|
||||
mItems.Clear();
|
||||
InternalList().Clear();
|
||||
Element()->DidChangeTransformList(true);
|
||||
Element()->DidChangeTransformList(emptyOrOldValue);
|
||||
if (mAList->IsAnimating()) {
|
||||
Element()->AnimationNeedsResample();
|
||||
}
|
||||
@ -272,6 +273,7 @@ DOMSVGTransformList::InsertItemBefore(nsIDOMSVGTransform *newItem,
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
nsAttrValue emptyOrOldValue = Element()->WillChangeTransformList();
|
||||
// Now that we know we're inserting, keep animVal list in sync as necessary.
|
||||
MaybeInsertNullInAnimValListAt(index);
|
||||
|
||||
@ -285,7 +287,7 @@ DOMSVGTransformList::InsertItemBefore(nsIDOMSVGTransform *newItem,
|
||||
|
||||
UpdateListIndicesFromIndex(mItems, index + 1);
|
||||
|
||||
Element()->DidChangeTransformList(true);
|
||||
Element()->DidChangeTransformList(emptyOrOldValue);
|
||||
if (mAList->IsAnimating()) {
|
||||
Element()->AnimationNeedsResample();
|
||||
}
|
||||
@ -316,6 +318,7 @@ DOMSVGTransformList::ReplaceItem(nsIDOMSVGTransform *newItem,
|
||||
domItem = domItem->Clone(); // must do this before changing anything!
|
||||
}
|
||||
|
||||
nsAttrValue emptyOrOldValue = Element()->WillChangeTransformList();
|
||||
if (mItems[index]) {
|
||||
// Notify any existing DOM item of removal *before* modifying the lists so
|
||||
// that the DOM item can copy the *old* value at its index:
|
||||
@ -329,7 +332,7 @@ DOMSVGTransformList::ReplaceItem(nsIDOMSVGTransform *newItem,
|
||||
// would end up reading bad data from InternalList()!
|
||||
domItem->InsertingIntoList(this, index, IsAnimValList());
|
||||
|
||||
Element()->DidChangeTransformList(true);
|
||||
Element()->DidChangeTransformList(emptyOrOldValue);
|
||||
if (mAList->IsAnimating()) {
|
||||
Element()->AnimationNeedsResample();
|
||||
}
|
||||
@ -350,6 +353,7 @@ DOMSVGTransformList::RemoveItem(PRUint32 index, nsIDOMSVGTransform **_retval)
|
||||
return NS_ERROR_DOM_INDEX_SIZE_ERR;
|
||||
}
|
||||
|
||||
nsAttrValue emptyOrOldValue = Element()->WillChangeTransformList();
|
||||
// Now that we know we're removing, keep animVal list in sync as necessary.
|
||||
// Do this *before* touching InternalList() so the removed item can get its
|
||||
// internal value.
|
||||
@ -368,7 +372,7 @@ DOMSVGTransformList::RemoveItem(PRUint32 index, nsIDOMSVGTransform **_retval)
|
||||
|
||||
UpdateListIndicesFromIndex(mItems, index);
|
||||
|
||||
Element()->DidChangeTransformList(true);
|
||||
Element()->DidChangeTransformList(emptyOrOldValue);
|
||||
if (mAList->IsAnimating()) {
|
||||
Element()->AnimationNeedsResample();
|
||||
}
|
||||
|
@ -146,6 +146,7 @@ CPPSRCS = \
|
||||
nsSVGAnimationElement.cpp \
|
||||
nsSVGMpathElement.cpp \
|
||||
nsSVGSetElement.cpp \
|
||||
SVGAttrValueWrapper.cpp \
|
||||
SVGIntegerPairSMILType.cpp \
|
||||
SVGLengthListSMILType.cpp \
|
||||
SVGMotionSMILType.cpp \
|
||||
@ -169,6 +170,7 @@ FORCE_STATIC_LIB = 1
|
||||
EXPORTS = \
|
||||
nsSVGFeatures.h \
|
||||
nsSVGRect.h \
|
||||
SVGAttrValueWrapper.h \
|
||||
$(NULL)
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
@ -250,7 +250,8 @@ SVGAnimatedPreserveAspectRatio::SetBaseValueString(
|
||||
}
|
||||
|
||||
void
|
||||
SVGAnimatedPreserveAspectRatio::GetBaseValueString(nsAString & aValueAsString)
|
||||
SVGAnimatedPreserveAspectRatio::GetBaseValueString(
|
||||
nsAString& aValueAsString) const
|
||||
{
|
||||
nsAutoString tmpString;
|
||||
|
||||
@ -276,12 +277,17 @@ nsresult
|
||||
SVGAnimatedPreserveAspectRatio::SetBaseAlign(PRUint16 aAlign,
|
||||
nsSVGElement *aSVGElement)
|
||||
{
|
||||
if (mIsBaseSet && mBaseVal.GetAlign() == aAlign) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsAttrValue emptyOrOldValue = aSVGElement->WillChangePreserveAspectRatio();
|
||||
nsresult rv = mBaseVal.SetAlign(aAlign);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
mIsBaseSet = true;
|
||||
|
||||
mAnimVal.mAlign = mBaseVal.mAlign;
|
||||
aSVGElement->DidChangePreserveAspectRatio(true);
|
||||
aSVGElement->DidChangePreserveAspectRatio(emptyOrOldValue);
|
||||
if (mIsAnimated) {
|
||||
aSVGElement->AnimationNeedsResample();
|
||||
}
|
||||
@ -293,12 +299,17 @@ nsresult
|
||||
SVGAnimatedPreserveAspectRatio::SetBaseMeetOrSlice(PRUint16 aMeetOrSlice,
|
||||
nsSVGElement *aSVGElement)
|
||||
{
|
||||
if (mIsBaseSet && mBaseVal.GetMeetOrSlice() == aMeetOrSlice) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsAttrValue emptyOrOldValue = aSVGElement->WillChangePreserveAspectRatio();
|
||||
nsresult rv = mBaseVal.SetMeetOrSlice(aMeetOrSlice);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
mIsBaseSet = true;
|
||||
|
||||
mAnimVal.mMeetOrSlice = mBaseVal.mMeetOrSlice;
|
||||
aSVGElement->DidChangePreserveAspectRatio(true);
|
||||
aSVGElement->DidChangePreserveAspectRatio(emptyOrOldValue);
|
||||
if (mIsAnimated) {
|
||||
aSVGElement->AnimationNeedsResample();
|
||||
}
|
||||
|
@ -118,7 +118,7 @@ public:
|
||||
|
||||
nsresult SetBaseValueString(const nsAString& aValue,
|
||||
nsSVGElement *aSVGElement);
|
||||
void GetBaseValueString(nsAString& aValue);
|
||||
void GetBaseValueString(nsAString& aValue) const;
|
||||
|
||||
nsresult SetBaseAlign(PRUint16 aAlign, nsSVGElement *aSVGElement);
|
||||
nsresult SetBaseMeetOrSlice(PRUint16 aMeetOrSlice, nsSVGElement *aSVGElement);
|
||||
|
133
content/svg/content/src/SVGAttrValueWrapper.cpp
Normal file
133
content/svg/content/src/SVGAttrValueWrapper.cpp
Normal file
@ -0,0 +1,133 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* vim: sw=2 ts=2 et lcs=trail\:.,tab\:>~ :
|
||||
* ***** 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 the Mozilla SVG project.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Mozilla Japan.
|
||||
* 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 "SVGAttrValueWrapper.h"
|
||||
#include "nsSVGAngle.h"
|
||||
#include "nsSVGIntegerPair.h"
|
||||
#include "nsSVGLength2.h"
|
||||
#include "nsSVGNumberPair.h"
|
||||
#include "nsSVGViewBox.h"
|
||||
#include "SVGAnimatedPreserveAspectRatio.h"
|
||||
#include "SVGLengthList.h"
|
||||
#include "SVGNumberList.h"
|
||||
#include "SVGPathData.h"
|
||||
#include "SVGPointList.h"
|
||||
#include "SVGStringList.h"
|
||||
#include "SVGTransformList.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
/*static*/ void
|
||||
SVGAttrValueWrapper::ToString(const nsSVGAngle* aAngle, nsAString& aResult)
|
||||
{
|
||||
aAngle->GetBaseValueString(aResult);
|
||||
}
|
||||
|
||||
/*static*/ void
|
||||
SVGAttrValueWrapper::ToString(const nsSVGIntegerPair* aIntegerPair,
|
||||
nsAString& aResult)
|
||||
{
|
||||
aIntegerPair->GetBaseValueString(aResult);
|
||||
}
|
||||
|
||||
/*static*/ void
|
||||
SVGAttrValueWrapper::ToString(const nsSVGLength2* aLength, nsAString& aResult)
|
||||
{
|
||||
aLength->GetBaseValueString(aResult);
|
||||
}
|
||||
|
||||
/*static*/ void
|
||||
SVGAttrValueWrapper::ToString(const SVGLengthList* aLengthList,
|
||||
nsAString& aResult)
|
||||
{
|
||||
aLengthList->GetValueAsString(aResult);
|
||||
}
|
||||
|
||||
/*static*/ void
|
||||
SVGAttrValueWrapper::ToString(const SVGNumberList* aNumberList,
|
||||
nsAString& aResult)
|
||||
{
|
||||
aNumberList->GetValueAsString(aResult);
|
||||
}
|
||||
|
||||
/*static*/ void
|
||||
SVGAttrValueWrapper::ToString(const nsSVGNumberPair* aNumberPair,
|
||||
nsAString& aResult)
|
||||
{
|
||||
aNumberPair->GetBaseValueString(aResult);
|
||||
}
|
||||
|
||||
/*static*/ void
|
||||
SVGAttrValueWrapper::ToString(const SVGPathData* aPathData, nsAString& aResult)
|
||||
{
|
||||
aPathData->GetValueAsString(aResult);
|
||||
}
|
||||
|
||||
/*static*/ void
|
||||
SVGAttrValueWrapper::ToString(const SVGPointList* aPointList,
|
||||
nsAString& aResult)
|
||||
{
|
||||
aPointList->GetValueAsString(aResult);
|
||||
}
|
||||
|
||||
/*static*/ void
|
||||
SVGAttrValueWrapper::ToString(
|
||||
const SVGAnimatedPreserveAspectRatio* aPreserveAspectRatio,
|
||||
nsAString& aResult)
|
||||
{
|
||||
aPreserveAspectRatio->GetBaseValueString(aResult);
|
||||
}
|
||||
|
||||
/*static*/ void
|
||||
SVGAttrValueWrapper::ToString(const SVGStringList* aStringList,
|
||||
nsAString& aResult)
|
||||
{
|
||||
aStringList->GetValue(aResult);
|
||||
}
|
||||
|
||||
/*static*/ void
|
||||
SVGAttrValueWrapper::ToString(const SVGTransformList* aTransformList,
|
||||
nsAString& aResult)
|
||||
{
|
||||
aTransformList->GetValueAsString(aResult);
|
||||
}
|
||||
|
||||
/*static*/ void
|
||||
SVGAttrValueWrapper::ToString(const nsSVGViewBox* aViewBox, nsAString& aResult)
|
||||
{
|
||||
aViewBox->GetBaseValueString(aResult);
|
||||
}
|
94
content/svg/content/src/SVGAttrValueWrapper.h
Normal file
94
content/svg/content/src/SVGAttrValueWrapper.h
Normal file
@ -0,0 +1,94 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* vim: sw=2 ts=2 et lcs=trail\:.,tab\:>~ :
|
||||
* ***** 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 the Mozilla SVG project.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Mozilla Japan.
|
||||
* 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 ***** */
|
||||
|
||||
#ifndef MOZILLA_SVGATTRVALUEWRAPPER_H__
|
||||
#define MOZILLA_SVGATTRVALUEWRAPPER_H__
|
||||
|
||||
/**
|
||||
* Utility wrapper for handling SVG types used inside nsAttrValue so that these
|
||||
* types don't need to be exported outside the SVG module.
|
||||
*/
|
||||
|
||||
#include "nsString.h"
|
||||
|
||||
class nsSVGAngle;
|
||||
class nsSVGIntegerPair;
|
||||
class nsSVGLength2;
|
||||
class nsSVGNumberPair;
|
||||
class nsSVGViewBox;
|
||||
|
||||
namespace mozilla {
|
||||
class SVGLengthList;
|
||||
class SVGNumberList;
|
||||
class SVGPathData;
|
||||
class SVGPointList;
|
||||
class SVGAnimatedPreserveAspectRatio;
|
||||
class SVGStringList;
|
||||
class SVGTransformList;
|
||||
}
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class SVGAttrValueWrapper
|
||||
{
|
||||
public:
|
||||
static void ToString(const nsSVGAngle* aAngle, nsAString& aResult);
|
||||
static void ToString(const nsSVGIntegerPair* aIntegerPair,
|
||||
nsAString& aResult);
|
||||
static void ToString(const nsSVGLength2* aLength, nsAString& aResult);
|
||||
static void ToString(const mozilla::SVGLengthList* aLengthList,
|
||||
nsAString& aResult);
|
||||
static void ToString(const mozilla::SVGNumberList* aNumberList,
|
||||
nsAString& aResult);
|
||||
static void ToString(const nsSVGNumberPair* aNumberPair, nsAString& aResult);
|
||||
static void ToString(const mozilla::SVGPathData* aPathData,
|
||||
nsAString& aResult);
|
||||
static void ToString(const mozilla::SVGPointList* aPointList,
|
||||
nsAString& aResult);
|
||||
static void ToString(
|
||||
const mozilla::SVGAnimatedPreserveAspectRatio* aPreserveAspectRatio,
|
||||
nsAString& aResult);
|
||||
static void ToString(const mozilla::SVGStringList* aStringList,
|
||||
nsAString& aResult);
|
||||
static void ToString(const mozilla::SVGTransformList* aTransformList,
|
||||
nsAString& aResult);
|
||||
static void ToString(const nsSVGViewBox* aViewBox, nsAString& aResult);
|
||||
};
|
||||
|
||||
} /* namespace mozilla */
|
||||
|
||||
#endif // MOZILLA_SVGATTRVALUEWRAPPER_H__
|
@ -62,14 +62,14 @@ SVGStringList::CopyFrom(const SVGStringList& rhs)
|
||||
}
|
||||
|
||||
void
|
||||
SVGStringList::GetValue(nsAString& aValue, bool aIsCommaSeparated) const
|
||||
SVGStringList::GetValue(nsAString& aValue) const
|
||||
{
|
||||
aValue.Truncate();
|
||||
PRUint32 last = mStrings.Length() - 1;
|
||||
for (PRUint32 i = 0; i < mStrings.Length(); ++i) {
|
||||
aValue.Append(mStrings[i]);
|
||||
if (i != last) {
|
||||
if (aIsCommaSeparated) {
|
||||
if (mIsCommaSeparated) {
|
||||
aValue.Append(',');
|
||||
}
|
||||
aValue.Append(' ');
|
||||
@ -78,11 +78,11 @@ SVGStringList::GetValue(nsAString& aValue, bool aIsCommaSeparated) const
|
||||
}
|
||||
|
||||
nsresult
|
||||
SVGStringList::SetValue(const nsAString& aValue, bool aIsCommaSeparated)
|
||||
SVGStringList::SetValue(const nsAString& aValue)
|
||||
{
|
||||
SVGStringList temp;
|
||||
|
||||
if (aIsCommaSeparated) {
|
||||
if (mIsCommaSeparated) {
|
||||
nsCharSeparatedTokenizerTemplate<IsSVGWhitespace>
|
||||
tokenizer(aValue, ',');
|
||||
|
||||
|
@ -54,10 +54,13 @@ class SVGStringList
|
||||
|
||||
public:
|
||||
|
||||
SVGStringList() : mIsSet(false) {}
|
||||
SVGStringList() : mIsSet(false), mIsCommaSeparated(false) {}
|
||||
~SVGStringList(){}
|
||||
|
||||
nsresult SetValue(const nsAString& aValue, bool aIsCommaSeparated);
|
||||
void SetIsCommaSeparated(bool aIsCommaSeparated) {
|
||||
mIsCommaSeparated = aIsCommaSeparated;
|
||||
}
|
||||
nsresult SetValue(const nsAString& aValue);
|
||||
|
||||
void Clear() {
|
||||
mStrings.Clear();
|
||||
@ -65,7 +68,7 @@ public:
|
||||
}
|
||||
|
||||
/// This may return an incomplete string on OOM, but that's acceptable.
|
||||
void GetValue(nsAString& aValue, bool aIsCommaSeparated) const;
|
||||
void GetValue(nsAString& aValue) const;
|
||||
|
||||
bool IsEmpty() const {
|
||||
return mStrings.IsEmpty();
|
||||
@ -91,9 +94,8 @@ public:
|
||||
mStrings.Compact();
|
||||
}
|
||||
|
||||
// Returns true if the animated value of this stringlist has been explicitly
|
||||
// set by taking on the base value which has been explicitly set by markup
|
||||
// or a DOM call, false otherwise.
|
||||
// Returns true if the value of this stringlist has been explicitly
|
||||
// set by markup or a DOM call, false otherwise.
|
||||
bool IsExplicitlySet() const
|
||||
{ return mIsSet; }
|
||||
|
||||
@ -168,6 +170,7 @@ protected:
|
||||
*/
|
||||
nsTArray<nsString> mStrings;
|
||||
bool mIsSet;
|
||||
bool mIsCommaSeparated;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
@ -97,7 +97,6 @@ public:
|
||||
nsresult SetSkewX(float aAngle);
|
||||
nsresult SetSkewY(float aAngle);
|
||||
|
||||
protected:
|
||||
static bool MatricesEqual(const gfxMatrix& a, const gfxMatrix& b)
|
||||
{
|
||||
return a.xx == b.xx &&
|
||||
@ -108,6 +107,7 @@ protected:
|
||||
a.y0 == b.y0;
|
||||
}
|
||||
|
||||
protected:
|
||||
gfxMatrix mMatrix;
|
||||
float mAngle, mOriginX, mOriginY;
|
||||
PRUint16 mType;
|
||||
|
@ -72,7 +72,7 @@ public:
|
||||
NS_IMETHOD SetValue(float aValue)
|
||||
{
|
||||
NS_ENSURE_FINITE(aValue, NS_ERROR_ILLEGAL_VALUE);
|
||||
mVal.SetBaseValue(aValue, nsnull);
|
||||
mVal.SetBaseValue(aValue, nsnull, true);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -258,6 +258,11 @@ void
|
||||
nsSVGAngle::SetBaseValueInSpecifiedUnits(float aValue,
|
||||
nsSVGElement *aSVGElement)
|
||||
{
|
||||
if (mBaseVal == aValue) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsAttrValue emptyOrOldValue = aSVGElement->WillChangeAngle(mAttrEnum);
|
||||
mBaseVal = aValue;
|
||||
if (!mIsAnimated) {
|
||||
mAnimVal = mBaseVal;
|
||||
@ -265,7 +270,7 @@ nsSVGAngle::SetBaseValueInSpecifiedUnits(float aValue,
|
||||
else {
|
||||
aSVGElement->AnimationNeedsResample();
|
||||
}
|
||||
aSVGElement->DidChangeAngle(mAttrEnum, true);
|
||||
aSVGElement->DidChangeAngle(mAttrEnum, emptyOrOldValue);
|
||||
}
|
||||
|
||||
nsresult
|
||||
@ -275,9 +280,19 @@ nsSVGAngle::ConvertToSpecifiedUnits(PRUint16 unitType,
|
||||
if (!IsValidUnitType(unitType))
|
||||
return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
|
||||
|
||||
if (mBaseValUnit == PRUint8(unitType))
|
||||
return NS_OK;
|
||||
|
||||
nsAttrValue emptyOrOldValue = aSVGElement->WillChangeAngle(mAttrEnum);
|
||||
|
||||
float valueInUserUnits = mBaseVal * GetDegreesPerUnit(mBaseValUnit);
|
||||
mBaseValUnit = PRUint8(unitType);
|
||||
SetBaseValue(valueInUserUnits, aSVGElement);
|
||||
// Setting aDoSetAttr to false here will ensure we don't call
|
||||
// Will/DidChangeAngle a second time (and dispatch duplicate notifications).
|
||||
SetBaseValue(valueInUserUnits, aSVGElement, false);
|
||||
|
||||
aSVGElement->DidChangeAngle(mAttrEnum, emptyOrOldValue);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -291,6 +306,13 @@ nsSVGAngle::NewValueSpecifiedUnits(PRUint16 unitType,
|
||||
if (!IsValidUnitType(unitType))
|
||||
return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
|
||||
|
||||
if (mBaseVal == valueInSpecifiedUnits && mBaseValUnit == PRUint8(unitType))
|
||||
return NS_OK;
|
||||
|
||||
nsAttrValue emptyOrOldValue;
|
||||
if (aSVGElement) {
|
||||
emptyOrOldValue = aSVGElement->WillChangeAngle(mAttrEnum);
|
||||
}
|
||||
mBaseVal = valueInSpecifiedUnits;
|
||||
mBaseValUnit = PRUint8(unitType);
|
||||
if (!mIsAnimated) {
|
||||
@ -301,7 +323,7 @@ nsSVGAngle::NewValueSpecifiedUnits(PRUint16 unitType,
|
||||
aSVGElement->AnimationNeedsResample();
|
||||
}
|
||||
if (aSVGElement) {
|
||||
aSVGElement->DidChangeAngle(mAttrEnum, true);
|
||||
aSVGElement->DidChangeAngle(mAttrEnum, emptyOrOldValue);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
@ -342,7 +364,14 @@ nsSVGAngle::SetBaseValueString(const nsAString &aValueAsString,
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
if (mBaseVal == value && mBaseValUnit == PRUint8(unitType)) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsAttrValue emptyOrOldValue;
|
||||
if (aDoSetAttr) {
|
||||
emptyOrOldValue = aSVGElement->WillChangeAngle(mAttrEnum);
|
||||
}
|
||||
mBaseVal = value;
|
||||
mBaseValUnit = PRUint8(unitType);
|
||||
if (!mIsAnimated) {
|
||||
@ -353,27 +382,36 @@ nsSVGAngle::SetBaseValueString(const nsAString &aValueAsString,
|
||||
aSVGElement->AnimationNeedsResample();
|
||||
}
|
||||
|
||||
// We don't need to call DidChange* here - we're only called by
|
||||
// nsSVGElement::ParseAttribute under nsGenericElement::SetAttr,
|
||||
// which takes care of notifying.
|
||||
if (aDoSetAttr) {
|
||||
aSVGElement->DidChangeAngle(mAttrEnum, emptyOrOldValue);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
nsSVGAngle::GetBaseValueString(nsAString & aValueAsString)
|
||||
nsSVGAngle::GetBaseValueString(nsAString & aValueAsString) const
|
||||
{
|
||||
GetValueString(aValueAsString, mBaseVal, mBaseValUnit);
|
||||
}
|
||||
|
||||
void
|
||||
nsSVGAngle::GetAnimValueString(nsAString & aValueAsString)
|
||||
nsSVGAngle::GetAnimValueString(nsAString & aValueAsString) const
|
||||
{
|
||||
GetValueString(aValueAsString, mAnimVal, mAnimValUnit);
|
||||
}
|
||||
|
||||
void
|
||||
nsSVGAngle::SetBaseValue(float aValue, nsSVGElement *aSVGElement)
|
||||
nsSVGAngle::SetBaseValue(float aValue, nsSVGElement *aSVGElement,
|
||||
bool aDoSetAttr)
|
||||
{
|
||||
if (mBaseVal == aValue * GetDegreesPerUnit(mBaseValUnit)) {
|
||||
return;
|
||||
}
|
||||
nsAttrValue emptyOrOldValue;
|
||||
if (aSVGElement && aDoSetAttr) {
|
||||
emptyOrOldValue = aSVGElement->WillChangeAngle(mAttrEnum);
|
||||
}
|
||||
|
||||
mBaseVal = aValue / GetDegreesPerUnit(mBaseValUnit);
|
||||
if (!mIsAnimated) {
|
||||
mAnimVal = mBaseVal;
|
||||
@ -381,8 +419,8 @@ nsSVGAngle::SetBaseValue(float aValue, nsSVGElement *aSVGElement)
|
||||
else {
|
||||
aSVGElement->AnimationNeedsResample();
|
||||
}
|
||||
if (aSVGElement) {
|
||||
aSVGElement->DidChangeAngle(mAttrEnum, true);
|
||||
if (aSVGElement && aDoSetAttr) {
|
||||
aSVGElement->DidChangeAngle(mAttrEnum, emptyOrOldValue);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -67,15 +67,15 @@ public:
|
||||
nsresult SetBaseValueString(const nsAString& aValue,
|
||||
nsSVGElement *aSVGElement,
|
||||
bool aDoSetAttr);
|
||||
void GetBaseValueString(nsAString& aValue);
|
||||
void GetAnimValueString(nsAString& aValue);
|
||||
void GetBaseValueString(nsAString& aValue) const;
|
||||
void GetAnimValueString(nsAString& aValue) const;
|
||||
|
||||
float GetBaseValue() const
|
||||
{ return mBaseVal * GetDegreesPerUnit(mBaseValUnit); }
|
||||
float GetAnimValue() const
|
||||
{ return mAnimVal * GetDegreesPerUnit(mAnimValUnit); }
|
||||
|
||||
void SetBaseValue(float aValue, nsSVGElement *aSVGElement);
|
||||
void SetBaseValue(float aValue, nsSVGElement *aSVGElement, bool aDoSetAttr);
|
||||
void SetAnimValue(float aValue, PRUint8 aUnit, nsSVGElement *aSVGElement);
|
||||
|
||||
PRUint8 GetBaseValueUnit() const { return mBaseValUnit; }
|
||||
@ -125,7 +125,7 @@ public:
|
||||
NS_IMETHOD GetValue(float* aResult)
|
||||
{ *aResult = mVal->GetBaseValue(); return NS_OK; }
|
||||
NS_IMETHOD SetValue(float aValue)
|
||||
{ mVal->SetBaseValue(aValue, mSVGElement); return NS_OK; }
|
||||
{ mVal->SetBaseValue(aValue, mSVGElement, true); return NS_OK; }
|
||||
|
||||
NS_IMETHOD GetValueInSpecifiedUnits(float* aResult)
|
||||
{ *aResult = mVal->mBaseVal; return NS_OK; }
|
||||
|
@ -70,13 +70,26 @@ GetValueFromString(const nsAString &aValueAsString,
|
||||
return NS_ERROR_DOM_SYNTAX_ERR;
|
||||
}
|
||||
|
||||
static nsresult
|
||||
GetValueFromAtom(const nsIAtom* aValueAsAtom, bool *aValue)
|
||||
{
|
||||
if (aValueAsAtom == nsGkAtoms::_true) {
|
||||
*aValue = true;
|
||||
return NS_OK;
|
||||
}
|
||||
if (aValueAsAtom == nsGkAtoms::_false) {
|
||||
*aValue = false;
|
||||
return NS_OK;
|
||||
}
|
||||
return NS_ERROR_DOM_SYNTAX_ERR;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsSVGBoolean::SetBaseValueString(const nsAString &aValueAsString,
|
||||
nsSVGElement *aSVGElement)
|
||||
nsSVGBoolean::SetBaseValueAtom(const nsIAtom* aValue, nsSVGElement *aSVGElement)
|
||||
{
|
||||
bool val;
|
||||
|
||||
nsresult rv = GetValueFromString(aValueAsString, &val);
|
||||
nsresult rv = GetValueFromAtom(aValue, &val);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
@ -95,30 +108,28 @@ nsSVGBoolean::SetBaseValueString(const nsAString &aValueAsString,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
nsSVGBoolean::GetBaseValueString(nsAString & aValueAsString)
|
||||
nsIAtom*
|
||||
nsSVGBoolean::GetBaseValueAtom() const
|
||||
{
|
||||
aValueAsString.Assign(mBaseVal
|
||||
? NS_LITERAL_STRING("true")
|
||||
: NS_LITERAL_STRING("false"));
|
||||
return mBaseVal ? nsGkAtoms::_true : nsGkAtoms::_false;
|
||||
}
|
||||
|
||||
void
|
||||
nsSVGBoolean::SetBaseValue(bool aValue,
|
||||
nsSVGElement *aSVGElement)
|
||||
nsSVGBoolean::SetBaseValue(bool aValue, nsSVGElement *aSVGElement)
|
||||
{
|
||||
NS_PRECONDITION(aValue == true || aValue == false, "Boolean out of range");
|
||||
|
||||
if (aValue != mBaseVal) {
|
||||
mBaseVal = aValue;
|
||||
if (!mIsAnimated) {
|
||||
mAnimVal = mBaseVal;
|
||||
}
|
||||
else {
|
||||
aSVGElement->AnimationNeedsResample();
|
||||
}
|
||||
aSVGElement->DidChangeBoolean(mAttrEnum, true);
|
||||
if (aValue == mBaseVal) {
|
||||
return;
|
||||
}
|
||||
|
||||
mBaseVal = aValue;
|
||||
if (!mIsAnimated) {
|
||||
mAnimVal = mBaseVal;
|
||||
} else {
|
||||
aSVGElement->AnimationNeedsResample();
|
||||
}
|
||||
aSVGElement->DidChangeBoolean(mAttrEnum);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -58,9 +58,8 @@ public:
|
||||
mIsAnimated = false;
|
||||
}
|
||||
|
||||
nsresult SetBaseValueString(const nsAString& aValue,
|
||||
nsSVGElement *aSVGElement);
|
||||
void GetBaseValueString(nsAString& aValue);
|
||||
nsresult SetBaseValueAtom(const nsIAtom* aValue, nsSVGElement *aSVGElement);
|
||||
nsIAtom* GetBaseValueAtom() const;
|
||||
|
||||
void SetBaseValue(bool aValue, nsSVGElement *aSVGElement);
|
||||
bool GetBaseValue() const
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -169,24 +169,44 @@ public:
|
||||
return GetNumberInfo().mNumberInfo[aAttrEnum].mPercentagesAllowed;
|
||||
}
|
||||
void SetLength(nsIAtom* aName, const nsSVGLength2 &aLength);
|
||||
virtual void DidChangeLength(PRUint8 aAttrEnum, bool aDoSetAttr);
|
||||
virtual void DidChangeNumber(PRUint8 aAttrEnum, bool aDoSetAttr);
|
||||
virtual void DidChangeNumberPair(PRUint8 aAttrEnum, bool aDoSetAttr);
|
||||
virtual void DidChangeInteger(PRUint8 aAttrEnum, bool aDoSetAttr);
|
||||
virtual void DidChangeIntegerPair(PRUint8 aAttrEnum, bool aDoSetAttr);
|
||||
virtual void DidChangeAngle(PRUint8 aAttrEnum, bool aDoSetAttr);
|
||||
virtual void DidChangeBoolean(PRUint8 aAttrEnum, bool aDoSetAttr);
|
||||
virtual void DidChangeEnum(PRUint8 aAttrEnum, bool aDoSetAttr);
|
||||
virtual void DidChangeViewBox(bool aDoSetAttr);
|
||||
virtual void DidChangePreserveAspectRatio(bool aDoSetAttr);
|
||||
virtual void DidChangeNumberList(PRUint8 aAttrEnum, bool aDoSetAttr);
|
||||
virtual void DidChangeLengthList(PRUint8 aAttrEnum, bool aDoSetAttr);
|
||||
virtual void DidChangePointList(bool aDoSetAttr);
|
||||
virtual void DidChangePathSegList(bool aDoSetAttr);
|
||||
virtual void DidChangeTransformList(bool aDoSetAttr);
|
||||
virtual void DidChangeString(PRUint8 aAttrEnum) {}
|
||||
|
||||
nsAttrValue WillChangeLength(PRUint8 aAttrEnum);
|
||||
nsAttrValue WillChangeNumberPair(PRUint8 aAttrEnum);
|
||||
nsAttrValue WillChangeIntegerPair(PRUint8 aAttrEnum);
|
||||
nsAttrValue WillChangeAngle(PRUint8 aAttrEnum);
|
||||
nsAttrValue WillChangeViewBox();
|
||||
nsAttrValue WillChangePreserveAspectRatio();
|
||||
nsAttrValue WillChangeNumberList(PRUint8 aAttrEnum);
|
||||
nsAttrValue WillChangeLengthList(PRUint8 aAttrEnum);
|
||||
nsAttrValue WillChangePointList();
|
||||
nsAttrValue WillChangePathSegList();
|
||||
nsAttrValue WillChangeTransformList();
|
||||
nsAttrValue WillChangeStringList(bool aIsConditionalProcessingAttribute,
|
||||
PRUint8 aAttrEnum);
|
||||
|
||||
void DidChangeLength(PRUint8 aAttrEnum, const nsAttrValue& aEmptyOrOldValue);
|
||||
void DidChangeNumber(PRUint8 aAttrEnum);
|
||||
void DidChangeNumberPair(PRUint8 aAttrEnum,
|
||||
const nsAttrValue& aEmptyOrOldValue);
|
||||
void DidChangeInteger(PRUint8 aAttrEnum);
|
||||
void DidChangeIntegerPair(PRUint8 aAttrEnum,
|
||||
const nsAttrValue& aEmptyOrOldValue);
|
||||
void DidChangeAngle(PRUint8 aAttrEnum, const nsAttrValue& aEmptyOrOldValue);
|
||||
void DidChangeBoolean(PRUint8 aAttrEnum);
|
||||
void DidChangeEnum(PRUint8 aAttrEnum);
|
||||
void DidChangeViewBox(const nsAttrValue& aEmptyOrOldValue);
|
||||
void DidChangePreserveAspectRatio(const nsAttrValue& aEmptyOrOldValue);
|
||||
void DidChangeNumberList(PRUint8 aAttrEnum,
|
||||
const nsAttrValue& aEmptyOrOldValue);
|
||||
void DidChangeLengthList(PRUint8 aAttrEnum,
|
||||
const nsAttrValue& aEmptyOrOldValue);
|
||||
void DidChangePointList(const nsAttrValue& aEmptyOrOldValue);
|
||||
void DidChangePathSegList(const nsAttrValue& aEmptyOrOldValue);
|
||||
void DidChangeTransformList(const nsAttrValue& aEmptyOrOldValue);
|
||||
void DidChangeString(PRUint8 aAttrEnum) {}
|
||||
void DidChangeStringList(bool aIsConditionalProcessingAttribute,
|
||||
PRUint8 aAttrEnum);
|
||||
PRUint8 aAttrEnum,
|
||||
const nsAttrValue& aEmptyOrOldValue);
|
||||
|
||||
virtual void DidAnimateLength(PRUint8 aAttrEnum);
|
||||
virtual void DidAnimateNumber(PRUint8 aAttrEnum);
|
||||
@ -249,6 +269,16 @@ public:
|
||||
}
|
||||
|
||||
protected:
|
||||
#ifdef DEBUG
|
||||
// We define BeforeSetAttr here and mark it MOZ_FINAL to ensure it is NOT used
|
||||
// by SVG elements.
|
||||
// This is because we're not currently passing the correct value for aValue to
|
||||
// BeforeSetAttr since it would involve allocating extra SVG value types.
|
||||
// See the comment in nsSVGElement::WillChangeValue.
|
||||
virtual nsresult BeforeSetAttr(PRInt32 aNamespaceID, nsIAtom* aName,
|
||||
const nsAttrValueOrString* aValue,
|
||||
bool aNotify) MOZ_FINAL { return NS_OK; }
|
||||
#endif // DEBUG
|
||||
virtual nsresult AfterSetAttr(PRInt32 aNamespaceID, nsIAtom* aName,
|
||||
const nsAttrValue* aValue, bool aNotify);
|
||||
virtual bool ParseAttribute(PRInt32 aNamespaceID, nsIAtom* aAttribute,
|
||||
@ -264,6 +294,11 @@ protected:
|
||||
void UpdateAnimatedContentStyleRule();
|
||||
mozilla::css::StyleRule* GetAnimatedContentStyleRule();
|
||||
|
||||
nsAttrValue WillChangeValue(nsIAtom* aName);
|
||||
void DidChangeValue(nsIAtom* aName, const nsAttrValue& aEmptyOrOldValue,
|
||||
nsAttrValue& aNewValue);
|
||||
void MaybeSerializeAttrBeforeRemoval(nsIAtom* aName, bool aNotify);
|
||||
|
||||
static nsIAtom* GetEventNameForAttr(nsIAtom* aAttr);
|
||||
|
||||
struct LengthInfo {
|
||||
|
@ -67,15 +67,12 @@ nsSVGEnum::GetMapping(nsSVGElement *aSVGElement)
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsSVGEnum::SetBaseValueString(const nsAString& aValue,
|
||||
nsSVGElement *aSVGElement)
|
||||
nsSVGEnum::SetBaseValueAtom(const nsIAtom* aValue, nsSVGElement *aSVGElement)
|
||||
{
|
||||
nsCOMPtr<nsIAtom> valAtom = do_GetAtom(aValue);
|
||||
|
||||
nsSVGEnumMapping *mapping = GetMapping(aSVGElement);
|
||||
|
||||
while (mapping && mapping->mKey) {
|
||||
if (valAtom == *(mapping->mKey)) {
|
||||
if (aValue == *(mapping->mKey)) {
|
||||
mIsBaseSet = true;
|
||||
if (mBaseVal != mapping->mVal) {
|
||||
mBaseVal = mapping->mVal;
|
||||
@ -99,19 +96,19 @@ nsSVGEnum::SetBaseValueString(const nsAString& aValue,
|
||||
return NS_ERROR_DOM_SYNTAX_ERR;
|
||||
}
|
||||
|
||||
void
|
||||
nsSVGEnum::GetBaseValueString(nsAString& aValue, nsSVGElement *aSVGElement)
|
||||
nsIAtom*
|
||||
nsSVGEnum::GetBaseValueAtom(nsSVGElement *aSVGElement)
|
||||
{
|
||||
nsSVGEnumMapping *mapping = GetMapping(aSVGElement);
|
||||
|
||||
while (mapping && mapping->mKey) {
|
||||
if (mBaseVal == mapping->mVal) {
|
||||
(*mapping->mKey)->ToString(aValue);
|
||||
return;
|
||||
return *mapping->mKey;
|
||||
}
|
||||
mapping++;
|
||||
}
|
||||
NS_ERROR("unknown enumeration value");
|
||||
return nsGkAtoms::_empty;
|
||||
}
|
||||
|
||||
nsresult
|
||||
@ -131,7 +128,7 @@ nsSVGEnum::SetBaseValue(PRUint16 aValue,
|
||||
else {
|
||||
aSVGElement->AnimationNeedsResample();
|
||||
}
|
||||
aSVGElement->DidChangeEnum(mAttrEnum, true);
|
||||
aSVGElement->DidChangeEnum(mAttrEnum);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -65,11 +65,8 @@ public:
|
||||
mIsBaseSet = false;
|
||||
}
|
||||
|
||||
nsresult SetBaseValueString(const nsAString& aValue,
|
||||
nsSVGElement *aSVGElement);
|
||||
void GetBaseValueString(nsAString& aValue,
|
||||
nsSVGElement *aSVGElement);
|
||||
|
||||
nsresult SetBaseValueAtom(const nsIAtom* aValue, nsSVGElement *aSVGElement);
|
||||
nsIAtom* GetBaseValueAtom(nsSVGElement *aSVGElement);
|
||||
nsresult SetBaseValue(PRUint16 aValue,
|
||||
nsSVGElement *aSVGElement);
|
||||
PRUint16 GetBaseValue() const
|
||||
|
@ -106,9 +106,16 @@ nsSVGInteger::GetBaseValueString(nsAString & aValueAsString)
|
||||
}
|
||||
|
||||
void
|
||||
nsSVGInteger::SetBaseValue(int aValue,
|
||||
nsSVGElement *aSVGElement)
|
||||
nsSVGInteger::SetBaseValue(int aValue, nsSVGElement *aSVGElement)
|
||||
{
|
||||
// We can't just rely on SetParsedAttrValue (as called by DidChangeInteger)
|
||||
// detecting redundant changes since it will compare false if the existing
|
||||
// attribute value has an associated serialized version (a string value) even
|
||||
// if the integers match due to the way integers are stored in nsAttrValue.
|
||||
if (aValue == mBaseVal && mIsBaseSet) {
|
||||
return;
|
||||
}
|
||||
|
||||
mBaseVal = aValue;
|
||||
mIsBaseSet = true;
|
||||
if (!mIsAnimated) {
|
||||
@ -117,7 +124,7 @@ nsSVGInteger::SetBaseValue(int aValue,
|
||||
else {
|
||||
aSVGElement->AnimationNeedsResample();
|
||||
}
|
||||
aSVGElement->DidChangeInteger(mAttrEnum, true);
|
||||
aSVGElement->DidChangeInteger(mAttrEnum);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -128,7 +128,7 @@ nsSVGIntegerPair::SetBaseValueString(const nsAString &aValueAsString,
|
||||
}
|
||||
|
||||
void
|
||||
nsSVGIntegerPair::GetBaseValueString(nsAString &aValueAsString)
|
||||
nsSVGIntegerPair::GetBaseValueString(nsAString &aValueAsString) const
|
||||
{
|
||||
aValueAsString.Truncate();
|
||||
aValueAsString.AppendInt(mBaseVal[0]);
|
||||
@ -143,6 +143,11 @@ nsSVGIntegerPair::SetBaseValue(PRInt32 aValue, PairIndex aPairIndex,
|
||||
nsSVGElement *aSVGElement)
|
||||
{
|
||||
PRUint32 index = (aPairIndex == eFirst ? 0 : 1);
|
||||
if (mIsBaseSet && mBaseVal[index] == aValue) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsAttrValue emptyOrOldValue = aSVGElement->WillChangeIntegerPair(mAttrEnum);
|
||||
mBaseVal[index] = aValue;
|
||||
mIsBaseSet = true;
|
||||
if (!mIsAnimated) {
|
||||
@ -151,13 +156,18 @@ nsSVGIntegerPair::SetBaseValue(PRInt32 aValue, PairIndex aPairIndex,
|
||||
else {
|
||||
aSVGElement->AnimationNeedsResample();
|
||||
}
|
||||
aSVGElement->DidChangeIntegerPair(mAttrEnum, true);
|
||||
aSVGElement->DidChangeIntegerPair(mAttrEnum, emptyOrOldValue);
|
||||
}
|
||||
|
||||
void
|
||||
nsSVGIntegerPair::SetBaseValues(PRInt32 aValue1, PRInt32 aValue2,
|
||||
nsSVGElement *aSVGElement)
|
||||
{
|
||||
if (mIsBaseSet && mBaseVal[0] == aValue1 && mBaseVal[1] == aValue2) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsAttrValue emptyOrOldValue = aSVGElement->WillChangeIntegerPair(mAttrEnum);
|
||||
mBaseVal[0] = aValue1;
|
||||
mBaseVal[1] = aValue2;
|
||||
mIsBaseSet = true;
|
||||
@ -168,7 +178,7 @@ nsSVGIntegerPair::SetBaseValues(PRInt32 aValue1, PRInt32 aValue2,
|
||||
else {
|
||||
aSVGElement->AnimationNeedsResample();
|
||||
}
|
||||
aSVGElement->DidChangeIntegerPair(mAttrEnum, true);
|
||||
aSVGElement->DidChangeIntegerPair(mAttrEnum, emptyOrOldValue);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -66,7 +66,7 @@ public:
|
||||
|
||||
nsresult SetBaseValueString(const nsAString& aValue,
|
||||
nsSVGElement *aSVGElement);
|
||||
void GetBaseValueString(nsAString& aValue);
|
||||
void GetBaseValueString(nsAString& aValue) const;
|
||||
|
||||
void SetBaseValue(PRInt32 aValue, PairIndex aIndex, nsSVGElement *aSVGElement);
|
||||
void SetBaseValues(PRInt32 aValue1, PRInt32 aValue2, nsSVGElement *aSVGElement);
|
||||
|
@ -307,8 +307,17 @@ nsSVGLength2::GetUnitScaleFactor(nsIFrame *aFrame, PRUint8 aUnitType) const
|
||||
|
||||
void
|
||||
nsSVGLength2::SetBaseValueInSpecifiedUnits(float aValue,
|
||||
nsSVGElement *aSVGElement)
|
||||
nsSVGElement *aSVGElement,
|
||||
bool aDoSetAttr)
|
||||
{
|
||||
if (mIsBaseSet && mBaseVal == aValue) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsAttrValue emptyOrOldValue;
|
||||
if (aDoSetAttr) {
|
||||
emptyOrOldValue = aSVGElement->WillChangeLength(mAttrEnum);
|
||||
}
|
||||
mBaseVal = aValue;
|
||||
mIsBaseSet = true;
|
||||
if (!mIsAnimated) {
|
||||
@ -317,7 +326,9 @@ nsSVGLength2::SetBaseValueInSpecifiedUnits(float aValue,
|
||||
else {
|
||||
aSVGElement->AnimationNeedsResample();
|
||||
}
|
||||
aSVGElement->DidChangeLength(mAttrEnum, true);
|
||||
if (aDoSetAttr) {
|
||||
aSVGElement->DidChangeLength(mAttrEnum, emptyOrOldValue);
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
@ -327,10 +338,23 @@ nsSVGLength2::ConvertToSpecifiedUnits(PRUint16 unitType,
|
||||
if (!IsValidUnitType(unitType))
|
||||
return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
|
||||
|
||||
float valueInUserUnits =
|
||||
if (mIsBaseSet && mSpecifiedUnitType == PRUint8(unitType))
|
||||
return NS_OK;
|
||||
|
||||
// Even though we're not changing the visual effect this length will have
|
||||
// on the document, we still need to send out notifications in case we have
|
||||
// mutation listeners, since the actual string value of the attribute will
|
||||
// change.
|
||||
nsAttrValue emptyOrOldValue = aSVGElement->WillChangeLength(mAttrEnum);
|
||||
|
||||
float valueInUserUnits =
|
||||
mBaseVal / GetUnitScaleFactor(aSVGElement, mSpecifiedUnitType);
|
||||
mSpecifiedUnitType = PRUint8(unitType);
|
||||
SetBaseValue(valueInUserUnits, aSVGElement);
|
||||
// Setting aDoSetAttr to false here will ensure we don't call
|
||||
// Will/DidChangeAngle a second time (and dispatch duplicate notifications).
|
||||
SetBaseValue(valueInUserUnits, aSVGElement, false);
|
||||
|
||||
aSVGElement->DidChangeLength(mAttrEnum, emptyOrOldValue);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
@ -345,6 +369,12 @@ nsSVGLength2::NewValueSpecifiedUnits(PRUint16 unitType,
|
||||
if (!IsValidUnitType(unitType))
|
||||
return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
|
||||
|
||||
if (mIsBaseSet && mBaseVal == valueInSpecifiedUnits &&
|
||||
mSpecifiedUnitType == PRUint8(unitType)) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsAttrValue emptyOrOldValue = aSVGElement->WillChangeLength(mAttrEnum);
|
||||
mBaseVal = valueInSpecifiedUnits;
|
||||
mIsBaseSet = true;
|
||||
mSpecifiedUnitType = PRUint8(unitType);
|
||||
@ -354,7 +384,7 @@ nsSVGLength2::NewValueSpecifiedUnits(PRUint16 unitType,
|
||||
else {
|
||||
aSVGElement->AnimationNeedsResample();
|
||||
}
|
||||
aSVGElement->DidChangeLength(mAttrEnum, true);
|
||||
aSVGElement->DidChangeLength(mAttrEnum, emptyOrOldValue);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -407,12 +437,21 @@ nsSVGLength2::SetBaseValueString(const nsAString &aValueAsString,
|
||||
{
|
||||
float value;
|
||||
PRUint16 unitType;
|
||||
|
||||
|
||||
nsresult rv = GetValueFromString(aValueAsString, &value, &unitType);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
if (mIsBaseSet && mBaseVal == value &&
|
||||
mSpecifiedUnitType == PRUint8(unitType)) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsAttrValue emptyOrOldValue;
|
||||
if (aDoSetAttr) {
|
||||
emptyOrOldValue = aSVGElement->WillChangeLength(mAttrEnum);
|
||||
}
|
||||
mBaseVal = value;
|
||||
mIsBaseSet = true;
|
||||
mSpecifiedUnitType = PRUint8(unitType);
|
||||
@ -423,28 +462,31 @@ nsSVGLength2::SetBaseValueString(const nsAString &aValueAsString,
|
||||
aSVGElement->AnimationNeedsResample();
|
||||
}
|
||||
|
||||
aSVGElement->DidChangeLength(mAttrEnum, aDoSetAttr);
|
||||
if (aDoSetAttr) {
|
||||
aSVGElement->DidChangeLength(mAttrEnum, emptyOrOldValue);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
nsSVGLength2::GetBaseValueString(nsAString & aValueAsString)
|
||||
nsSVGLength2::GetBaseValueString(nsAString & aValueAsString) const
|
||||
{
|
||||
GetValueString(aValueAsString, mBaseVal, mSpecifiedUnitType);
|
||||
}
|
||||
|
||||
void
|
||||
nsSVGLength2::GetAnimValueString(nsAString & aValueAsString)
|
||||
nsSVGLength2::GetAnimValueString(nsAString & aValueAsString) const
|
||||
{
|
||||
GetValueString(aValueAsString, mAnimVal, mSpecifiedUnitType);
|
||||
}
|
||||
|
||||
void
|
||||
nsSVGLength2::SetBaseValue(float aValue, nsSVGElement *aSVGElement)
|
||||
nsSVGLength2::SetBaseValue(float aValue, nsSVGElement *aSVGElement,
|
||||
bool aDoSetAttr)
|
||||
{
|
||||
SetBaseValueInSpecifiedUnits(aValue * GetUnitScaleFactor(aSVGElement,
|
||||
mSpecifiedUnitType),
|
||||
aSVGElement);
|
||||
aSVGElement, aDoSetAttr);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -82,8 +82,8 @@ public:
|
||||
nsresult SetBaseValueString(const nsAString& aValue,
|
||||
nsSVGElement *aSVGElement,
|
||||
bool aDoSetAttr);
|
||||
void GetBaseValueString(nsAString& aValue);
|
||||
void GetAnimValueString(nsAString& aValue);
|
||||
void GetBaseValueString(nsAString& aValue) const;
|
||||
void GetAnimValueString(nsAString& aValue) const;
|
||||
|
||||
float GetBaseValue(nsSVGElement* aSVGElement) const
|
||||
{ return mBaseVal / GetUnitScaleFactor(aSVGElement, mSpecifiedUnitType); }
|
||||
@ -148,8 +148,9 @@ private:
|
||||
float GetUnitScaleFactor(nsSVGSVGElement *aCtx, PRUint8 aUnitType) const;
|
||||
|
||||
// SetBaseValue and SetAnimValue set the value in user units
|
||||
void SetBaseValue(float aValue, nsSVGElement *aSVGElement);
|
||||
void SetBaseValueInSpecifiedUnits(float aValue, nsSVGElement *aSVGElement);
|
||||
void SetBaseValue(float aValue, nsSVGElement *aSVGElement, bool aDoSetAttr);
|
||||
void SetBaseValueInSpecifiedUnits(float aValue, nsSVGElement *aSVGElement,
|
||||
bool aDoSetAttr);
|
||||
void SetAnimValue(float aValue, nsSVGElement *aSVGElement);
|
||||
void SetAnimValueInSpecifiedUnits(float aValue, nsSVGElement *aSVGElement);
|
||||
nsresult NewValueSpecifiedUnits(PRUint16 aUnitType, float aValue,
|
||||
@ -180,7 +181,7 @@ private:
|
||||
if (!NS_finite(aValue)) {
|
||||
return NS_ERROR_ILLEGAL_VALUE;
|
||||
}
|
||||
mVal->SetBaseValue(aValue, mSVGElement);
|
||||
mVal->SetBaseValue(aValue, mSVGElement, true);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -191,7 +192,7 @@ private:
|
||||
if (!NS_finite(aValue)) {
|
||||
return NS_ERROR_ILLEGAL_VALUE;
|
||||
}
|
||||
mVal->SetBaseValueInSpecifiedUnits(aValue, mSVGElement);
|
||||
mVal->SetBaseValueInSpecifiedUnits(aValue, mSVGElement, true);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -224,7 +224,7 @@ NS_IMETHODIMP nsSVGMarkerElement::SetOrientToAngle(nsIDOMSVGAngle *angle)
|
||||
nsresult rv = angle->GetValue(&f);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
NS_ENSURE_FINITE(f, NS_ERROR_DOM_SVG_WRONG_TYPE_ERR);
|
||||
mAngleAttributes[ORIENT].SetBaseValue(f, this);
|
||||
mAngleAttributes[ORIENT].SetBaseValue(f, this, true);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -149,9 +149,12 @@ nsSVGNumber2::GetBaseValueString(nsAString & aValueAsString)
|
||||
}
|
||||
|
||||
void
|
||||
nsSVGNumber2::SetBaseValue(float aValue,
|
||||
nsSVGElement *aSVGElement)
|
||||
nsSVGNumber2::SetBaseValue(float aValue, nsSVGElement *aSVGElement)
|
||||
{
|
||||
if (mIsBaseSet && aValue == mBaseVal) {
|
||||
return;
|
||||
}
|
||||
|
||||
mBaseVal = aValue;
|
||||
mIsBaseSet = true;
|
||||
if (!mIsAnimated) {
|
||||
@ -160,7 +163,7 @@ nsSVGNumber2::SetBaseValue(float aValue,
|
||||
else {
|
||||
aSVGElement->AnimationNeedsResample();
|
||||
}
|
||||
aSVGElement->DidChangeNumber(mAttrEnum, true);
|
||||
aSVGElement->DidChangeNumber(mAttrEnum);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -121,14 +121,14 @@ nsSVGNumberPair::SetBaseValueString(const nsAString &aValueAsString,
|
||||
aSVGElement->AnimationNeedsResample();
|
||||
}
|
||||
|
||||
// We don't need to call DidChange* here - we're only called by
|
||||
// We don't need to call Will/DidChange* here - we're only called by
|
||||
// nsSVGElement::ParseAttribute under nsGenericElement::SetAttr,
|
||||
// which takes care of notifying.
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
nsSVGNumberPair::GetBaseValueString(nsAString &aValueAsString)
|
||||
nsSVGNumberPair::GetBaseValueString(nsAString &aValueAsString) const
|
||||
{
|
||||
aValueAsString.Truncate();
|
||||
aValueAsString.AppendFloat(mBaseVal[0]);
|
||||
@ -143,6 +143,10 @@ nsSVGNumberPair::SetBaseValue(float aValue, PairIndex aPairIndex,
|
||||
nsSVGElement *aSVGElement)
|
||||
{
|
||||
PRUint32 index = (aPairIndex == eFirst ? 0 : 1);
|
||||
if (mIsBaseSet && mBaseVal[index] == aValue) {
|
||||
return;
|
||||
}
|
||||
nsAttrValue emptyOrOldValue = aSVGElement->WillChangeNumberPair(mAttrEnum);
|
||||
mBaseVal[index] = aValue;
|
||||
mIsBaseSet = true;
|
||||
if (!mIsAnimated) {
|
||||
@ -151,13 +155,17 @@ nsSVGNumberPair::SetBaseValue(float aValue, PairIndex aPairIndex,
|
||||
else {
|
||||
aSVGElement->AnimationNeedsResample();
|
||||
}
|
||||
aSVGElement->DidChangeNumberPair(mAttrEnum, true);
|
||||
aSVGElement->DidChangeNumberPair(mAttrEnum, emptyOrOldValue);
|
||||
}
|
||||
|
||||
void
|
||||
nsSVGNumberPair::SetBaseValues(float aValue1, float aValue2,
|
||||
nsSVGElement *aSVGElement)
|
||||
{
|
||||
if (mIsBaseSet && mBaseVal[0] == aValue1 && mBaseVal[1] == aValue2) {
|
||||
return;
|
||||
}
|
||||
nsAttrValue emptyOrOldValue = aSVGElement->WillChangeNumberPair(mAttrEnum);
|
||||
mBaseVal[0] = aValue1;
|
||||
mBaseVal[1] = aValue2;
|
||||
mIsBaseSet = true;
|
||||
@ -168,7 +176,7 @@ nsSVGNumberPair::SetBaseValues(float aValue1, float aValue2,
|
||||
else {
|
||||
aSVGElement->AnimationNeedsResample();
|
||||
}
|
||||
aSVGElement->DidChangeNumberPair(mAttrEnum, true);
|
||||
aSVGElement->DidChangeNumberPair(mAttrEnum, emptyOrOldValue);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -67,7 +67,7 @@ public:
|
||||
|
||||
nsresult SetBaseValueString(const nsAString& aValue,
|
||||
nsSVGElement *aSVGElement);
|
||||
void GetBaseValueString(nsAString& aValue);
|
||||
void GetBaseValueString(nsAString& aValue) const;
|
||||
|
||||
void SetBaseValue(float aValue, PairIndex aIndex, nsSVGElement *aSVGElement);
|
||||
void SetBaseValues(float aValue1, float aValue2, nsSVGElement *aSVGElement);
|
||||
|
@ -127,10 +127,16 @@ void
|
||||
nsSVGViewBox::SetBaseValue(float aX, float aY, float aWidth, float aHeight,
|
||||
nsSVGElement *aSVGElement)
|
||||
{
|
||||
if (mHasBaseVal && mBaseVal == nsSVGViewBoxRect(aX, aY, aWidth, aHeight)) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsAttrValue emptyOrOldValue = aSVGElement->WillChangeViewBox();
|
||||
|
||||
mBaseVal = nsSVGViewBoxRect(aX, aY, aWidth, aHeight);
|
||||
mHasBaseVal = true;
|
||||
|
||||
aSVGElement->DidChangeViewBox(true);
|
||||
aSVGElement->DidChangeViewBox(emptyOrOldValue);
|
||||
if (mAnimVal) {
|
||||
aSVGElement->AnimationNeedsResample();
|
||||
}
|
||||
@ -185,7 +191,7 @@ nsSVGViewBox::SetBaseValueString(const nsAString& aValue,
|
||||
if (mAnimVal) {
|
||||
aSVGElement->AnimationNeedsResample();
|
||||
}
|
||||
// We don't need to call DidChange* here - we're only called by
|
||||
// We don't need to call Will/DidChange* here - we're only called by
|
||||
// nsSVGElement::ParseAttribute under nsGenericElement::SetAttr,
|
||||
// which takes care of notifying.
|
||||
}
|
||||
|
@ -50,6 +50,7 @@ include $(topsrcdir)/config/rules.mk
|
||||
|
||||
_TEST_FILES = \
|
||||
matrixUtils.js \
|
||||
MutationEventChecker.js \
|
||||
test_a_href_01.xhtml \
|
||||
test_a_href_02.xhtml \
|
||||
a_href_destination.svg \
|
||||
@ -65,6 +66,7 @@ _TEST_FILES = \
|
||||
bbox-helper.svg \
|
||||
bounds-helper.svg \
|
||||
test_dataTypes.html \
|
||||
test_dataTypesModEvents.html \
|
||||
dataTypes-helper.svg \
|
||||
getCTM-helper.svg \
|
||||
test_getCTM.html \
|
||||
@ -88,7 +90,9 @@ _TEST_FILES = \
|
||||
test_SVGLengthList.xhtml \
|
||||
test_SVGLengthList-2.xhtml \
|
||||
test_SVGMatrix.xhtml \
|
||||
test_SVGNumberList.xhtml \
|
||||
test_SVGPathSegList.xhtml \
|
||||
test_SVGPointList.xhtml \
|
||||
test_SVGStyleElement.xhtml \
|
||||
test_SVGStringList.xhtml \
|
||||
test_SVGTransformList.xhtml \
|
||||
|
245
content/svg/content/test/MutationEventChecker.js
Normal file
245
content/svg/content/test/MutationEventChecker.js
Normal file
@ -0,0 +1,245 @@
|
||||
// Helper class to check DOM MutationEvents
|
||||
//
|
||||
// Usage:
|
||||
//
|
||||
// * Create a new event checker:
|
||||
// var eventChecker = new MutationEventChecker;
|
||||
// * Set the attribute to watch
|
||||
// eventChecker.watchAttr(<DOM element>, "<attribute name>");
|
||||
// * Set the events to expect (0..n)
|
||||
// eventChecker.expect("add", "modify");
|
||||
// OR
|
||||
// eventChecker.expect("add modify");
|
||||
// OR
|
||||
// eventChecker.expect(MutationEvent.ADDITION, MutationEvent.MODIFICATION);
|
||||
//
|
||||
// An empty string or empty set of arguments is also fine as a way of checking
|
||||
// that all expected events have been received and indicating no events are
|
||||
// expected from the following code, e.g.
|
||||
//
|
||||
// eventChecker.expect("");
|
||||
// // changes that are not expected to generate events
|
||||
// eventChecker.expect("modify");
|
||||
// // change that is expected to generate an event
|
||||
// ...
|
||||
//
|
||||
// * Either finish listening or set the next attribute to watch
|
||||
// eventChecker.finish();
|
||||
// eventChecker.watchAttr(element, "nextAttribute");
|
||||
//
|
||||
// In either case a check is performed that all expected events have been
|
||||
// received.
|
||||
//
|
||||
// * Event checking can be temporarily disabled with ignoreEvents(). The next
|
||||
// call to expect() will cause it to resume.
|
||||
|
||||
function MutationEventChecker()
|
||||
{
|
||||
this.expectedEvents = [];
|
||||
|
||||
this.watchAttr = function(element, attr)
|
||||
{
|
||||
if (this.attr) {
|
||||
this.finish();
|
||||
}
|
||||
|
||||
this.expectedEvents = [];
|
||||
this.element = element;
|
||||
this.attr = attr;
|
||||
this.oldValue = element.getAttribute(attr);
|
||||
this.giveUp = false;
|
||||
this.ignore = false;
|
||||
|
||||
this.element.addEventListener('DOMAttrModified', this._listener, false);
|
||||
}
|
||||
|
||||
this.expect = function()
|
||||
{
|
||||
if (this.giveUp) {
|
||||
return;
|
||||
}
|
||||
|
||||
ok(this.expectedEvents.length == 0,
|
||||
"Expecting new events for " + this.attr +
|
||||
" but the following previously expected events have still not been " +
|
||||
"received: " + this._stillExpecting());
|
||||
if (this.expectedEvents.length != 0) {
|
||||
this.giveUp = true;
|
||||
return;
|
||||
}
|
||||
|
||||
this.ignore = false;
|
||||
|
||||
if (arguments.length == 0 ||
|
||||
arguments.length == 1 && arguments[0] == "") {
|
||||
return;
|
||||
}
|
||||
|
||||
// Turn arguments object into an array
|
||||
var args = Array.prototype.slice.call(arguments);
|
||||
// Check for whitespace separated keywords
|
||||
if (args.length == 1 && typeof args[0] === 'string' &&
|
||||
args[0].indexOf(' ') > 0) {
|
||||
args = args[0].split(' ');
|
||||
}
|
||||
// Convert strings to event Ids
|
||||
this.expectedEvents = args.map(this._argToEventId);
|
||||
}
|
||||
|
||||
// Temporarily disable event checking
|
||||
this.ignoreEvents = function()
|
||||
{
|
||||
// Check all events have been received
|
||||
ok(this.giveUp || this.expectedEvents.length == 0,
|
||||
"Going to ignore subsequent events on " + this.attr +
|
||||
" attribute, but we're still expecting the following events: " +
|
||||
this._stillExpecting());
|
||||
|
||||
this.ignore = true;
|
||||
}
|
||||
|
||||
this.finish = function()
|
||||
{
|
||||
// Check all events have been received
|
||||
ok(this.giveUp || this.expectedEvents.length == 0,
|
||||
"Finishing listening to " + this.attr +
|
||||
" attribute, but we're still expecting the following events: " +
|
||||
this._stillExpecting());
|
||||
|
||||
this.element.removeEventListener('DOMAttrModified', this._listener, false);
|
||||
this.attr = "";
|
||||
}
|
||||
|
||||
this._receiveEvent = function(e)
|
||||
{
|
||||
if (this.giveUp || this.ignore) {
|
||||
this.oldValue = e.newValue;
|
||||
return;
|
||||
}
|
||||
|
||||
// Make sure we're expecting something at all
|
||||
if (this.expectedEvents.length == 0) {
|
||||
ok(false, 'Unexpected ' + this._eventToName(e.attrChange) +
|
||||
' event when none expected on ' + this.attr + ' attribute.');
|
||||
return;
|
||||
}
|
||||
|
||||
var expectedEvent = this.expectedEvents.shift();
|
||||
|
||||
// Make sure we got the event we expected
|
||||
if (e.attrChange != expectedEvent) {
|
||||
ok(false, 'Unexpected ' + this._eventToName(e.attrChange) +
|
||||
' on ' + this.attr + ' attribute. Expected ' +
|
||||
this._eventToName(expectedEvent) + ' (followed by: ' +
|
||||
this._stillExpecting() + ")");
|
||||
// If we get events out of sequence, it doesn't make sense to do any
|
||||
// further testing since we don't really know what to expect
|
||||
this.giveUp = true;
|
||||
return;
|
||||
}
|
||||
|
||||
// Common param checking
|
||||
is(e.target, this.element,
|
||||
'Unexpected node for mutation event on ' + this.attr + ' attribute');
|
||||
is(e.attrName, this.attr, 'Unexpected attribute name for mutation event');
|
||||
|
||||
// Don't bother testing e.relatedNode since Attr nodes are on the way
|
||||
// out anyway (but then, so are mutation events...)
|
||||
|
||||
// Event-specific checking
|
||||
if (e.attrChange == MutationEvent.MODIFICATION) {
|
||||
ok(this.element.hasAttribute(this.attr),
|
||||
'Attribute not set after modification');
|
||||
is(e.prevValue, this.oldValue,
|
||||
'Unexpected old value for modification to ' + this.attr +
|
||||
' attribute');
|
||||
isnot(e.newValue, this.oldValue,
|
||||
'Unexpected new value for modification to ' + this.attr +
|
||||
' attribute');
|
||||
} else if (e.attrChange == MutationEvent.REMOVAL) {
|
||||
ok(!this.element.hasAttribute(this.attr), 'Attribute set after removal');
|
||||
is(e.prevValue, this.oldValue,
|
||||
'Unexpected old value for removal of ' + this.attr +
|
||||
' attribute');
|
||||
// DOM 3 Events doesn't say what value newValue will be for a removal
|
||||
// event but generally empty strings are used for other events when an
|
||||
// attribute isn't relevant
|
||||
ok(e.newValue === "",
|
||||
'Unexpected new value for removal of ' + this.attr +
|
||||
' attribute');
|
||||
} else if (e.attrChange == MutationEvent.ADDITION) {
|
||||
ok(this.element.hasAttribute(this.attr),
|
||||
'Attribute not set after addition');
|
||||
// DOM 3 Events doesn't say what value prevValue will be for an addition
|
||||
// event but generally empty strings are used for other events when an
|
||||
// attribute isn't relevant
|
||||
ok(e.prevValue === "",
|
||||
'Unexpected old value for addition of ' + this.attr +
|
||||
' attribute');
|
||||
ok(typeof(e.newValue) == 'string' && e.newValue !== "",
|
||||
'Unexpected new value for addition of ' + this.attr +
|
||||
' attribute');
|
||||
} else {
|
||||
ok(false, 'Unexpected mutation event type: ' + e.attrChange);
|
||||
this.giveUp = true;
|
||||
}
|
||||
this.oldValue = e.newValue;
|
||||
}
|
||||
this._listener = this._receiveEvent.bind(this);
|
||||
|
||||
this._stillExpecting = function()
|
||||
{
|
||||
if (this.expectedEvents.length == 0) {
|
||||
return "(nothing)";
|
||||
}
|
||||
var eventNames = [];
|
||||
for (var i=0; i < this.expectedEvents.length; i++) {
|
||||
eventNames.push(this._eventToName(this.expectedEvents[i]));
|
||||
}
|
||||
return eventNames.join(", ");
|
||||
}
|
||||
|
||||
this._eventToName = function(evtId)
|
||||
{
|
||||
switch (evtId)
|
||||
{
|
||||
case MutationEvent.MODIFICATION:
|
||||
return "modification";
|
||||
case MutationEvent.ADDITION:
|
||||
return "addition";
|
||||
case MutationEvent.REMOVAL:
|
||||
return "removal";
|
||||
}
|
||||
}
|
||||
|
||||
this._argToEventId = function(arg)
|
||||
{
|
||||
if (typeof arg === 'number')
|
||||
return arg;
|
||||
|
||||
if (typeof arg !== 'string') {
|
||||
ok(false, "Unexpected event type: " + arg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (arg.toLowerCase())
|
||||
{
|
||||
case "mod":
|
||||
case "modify":
|
||||
case "modification":
|
||||
return MutationEvent.MODIFICATION;
|
||||
|
||||
case "add":
|
||||
case "addition":
|
||||
return MutationEvent.ADDITION;
|
||||
|
||||
case "removal":
|
||||
case "remove":
|
||||
return MutationEvent.REMOVAL;
|
||||
|
||||
default:
|
||||
ok(false, "Unexpected event name: " + arg);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
@ -5,6 +5,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=515116
|
||||
<head>
|
||||
<title>Tests specific to SVGLengthList</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="MutationEventChecker.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
@ -36,11 +37,31 @@ function run_tests()
|
||||
|
||||
is(lengths.numberOfItems, 0, 'Checking numberOfItems');
|
||||
|
||||
/*
|
||||
is(lengths.numberOfItems, 2, 'Checking numberOfItems');
|
||||
is(lengths.getItem(1).valueInSpecifiedUnits == 20, 'Checking the value of the second length');
|
||||
is(lengths.getItem(1).unitType == SVGLength.SVG_LENGTHTYPE_CM, 'Checking the unit of the second length');
|
||||
*/
|
||||
// Test mutation events
|
||||
// --- Initialization
|
||||
eventChecker = new MutationEventChecker;
|
||||
eventChecker.watchAttr(text, "x");
|
||||
eventChecker.expect("modify");
|
||||
text.textContent = "abc";
|
||||
text.setAttribute("x", "10 20 30");
|
||||
is(lengths.numberOfItems, 3, 'Checking numberOfItems');
|
||||
// -- Actual changes
|
||||
eventChecker.expect("modify modify modify modify modify");
|
||||
lengths[0].value = 8;
|
||||
lengths[0].valueInSpecifiedUnits = 9;
|
||||
lengths[0].valueAsString = "10";
|
||||
lengths[0].convertToSpecifiedUnits(SVGLength.SVG_LENGTHTYPE_CM);
|
||||
lengths[0].newValueSpecifiedUnits(SVGLength.SVG_LENGTHTYPE_MM, 11);
|
||||
// -- Redundant changes
|
||||
eventChecker.expect("modify");
|
||||
lengths[0].valueAsString = "10";
|
||||
eventChecker.expect("");
|
||||
lengths[0].value = 10;
|
||||
lengths[0].valueInSpecifiedUnits = 10;
|
||||
lengths[0].valueAsString = "10";
|
||||
lengths[0].convertToSpecifiedUnits(SVGLength.SVG_LENGTHTYPE_NUMBER);
|
||||
lengths[0].newValueSpecifiedUnits(SVGLength.SVG_LENGTHTYPE_NUMBER, 10);
|
||||
eventChecker.finish();
|
||||
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
64
content/svg/content/test/test_SVGNumberList.xhtml
Normal file
64
content/svg/content/test/test_SVGNumberList.xhtml
Normal file
@ -0,0 +1,64 @@
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=629200
|
||||
-->
|
||||
<head>
|
||||
<title>Tests specific to SVGNumberList</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="MutationEventChecker.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=629200">Mozilla Bug 629200</a>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display:none;">
|
||||
<svg id="svg" xmlns="http://www.w3.org/2000/svg" width="100" height="100">
|
||||
<text id="text" rotate="10 20 30">abc</text>
|
||||
</svg>
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script class="testbody" type="text/javascript">
|
||||
<![CDATA[
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
/*
|
||||
This file runs a series of SVGNumberList specific tests. Generic SVGXxxList
|
||||
tests can be found in test_SVGxxxList.xhtml. Anything that can be generalized
|
||||
to other list types belongs there.
|
||||
*/
|
||||
|
||||
function run_tests()
|
||||
{
|
||||
document.getElementById('svg').pauseAnimations();
|
||||
|
||||
var text = document.getElementById("text");
|
||||
var numbers = text.rotate.baseVal;
|
||||
|
||||
is(numbers.numberOfItems, 3, 'Checking numberOfItems');
|
||||
|
||||
// Test mutation events
|
||||
// --- Initialization
|
||||
eventChecker = new MutationEventChecker;
|
||||
eventChecker.watchAttr(text, "rotate");
|
||||
// -- Actual changes
|
||||
eventChecker.expect("modify modify");
|
||||
numbers[0].value = 15;
|
||||
text.setAttribute("rotate", "17 20 30");
|
||||
// -- Redundant changes
|
||||
eventChecker.expect("");
|
||||
numbers[0].value = 17;
|
||||
numbers[1].value = 20;
|
||||
text.setAttribute("rotate", "17 20 30");
|
||||
eventChecker.finish();
|
||||
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
window.addEventListener("load", run_tests, false);
|
||||
|
||||
]]>
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
@ -5,6 +5,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=611138
|
||||
<head>
|
||||
<title>Generic tests for SVG animated length lists</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="MutationEventChecker.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
@ -86,17 +87,25 @@ function run_tests()
|
||||
ok(list.numberOfItems == 1 && list.getItem(0) == seg,
|
||||
'initialize should be able initialize an invalid path with a non-moveto item');
|
||||
|
||||
// Test mutation events
|
||||
|
||||
eventChecker = new MutationEventChecker;
|
||||
d = 'M0,0 L12,34'
|
||||
path.setAttribute('d', d);
|
||||
function check_old_value(e) {
|
||||
is(e.target, path, 'check mutation event is for expected node');
|
||||
is(e.attrName, 'd', 'check mutation event is for expected attribute');
|
||||
is(e.prevValue, d, 'check old attribute value is correctly reported');
|
||||
isnot(e.newValue, d, 'check attribute value has changed');
|
||||
}
|
||||
path.addEventListener('DOMAttrModified', check_old_value, false);
|
||||
list.getItem(1).y = 35;
|
||||
path.removeEventListener('DOMAttrModified', check_old_value, false);
|
||||
eventChecker.watchAttr(path, "d");
|
||||
|
||||
// -- Actual changes
|
||||
eventChecker.expect("modify modify modify");
|
||||
list[0].x = 10;
|
||||
list[0].y = 5;
|
||||
path.setAttribute("d", "M20,5 L12,34");
|
||||
|
||||
// -- Redundant changes
|
||||
eventChecker.expect("");
|
||||
list[0].x = 20;
|
||||
list[1].y = 34;
|
||||
path.setAttribute("d", "M20,5 L12,34");
|
||||
eventChecker.finish();
|
||||
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
64
content/svg/content/test/test_SVGPointList.xhtml
Normal file
64
content/svg/content/test/test_SVGPointList.xhtml
Normal file
@ -0,0 +1,64 @@
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=629200
|
||||
-->
|
||||
<head>
|
||||
<title>Tests specific to SVGPointList</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="MutationEventChecker.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=629200">Mozilla Bug 629200</a>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display:none;">
|
||||
<svg id="svg" xmlns="http://www.w3.org/2000/svg" width="100" height="100">
|
||||
<polyline id="polyline" points="50,375 150,380"/>
|
||||
</svg>
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script class="testbody" type="text/javascript">
|
||||
<![CDATA[
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
/*
|
||||
This file runs a series of SVGPointList specific tests. Generic SVGXxxList
|
||||
tests can be found in test_SVGxxxList.xhtml. Anything that can be generalized
|
||||
to other list types belongs there.
|
||||
*/
|
||||
|
||||
function run_tests()
|
||||
{
|
||||
document.getElementById('svg').pauseAnimations();
|
||||
|
||||
var polyline = document.getElementById("polyline");
|
||||
var points = polyline.points;
|
||||
|
||||
is(points.numberOfItems, 2, 'Checking numberOfItems');
|
||||
|
||||
// Test mutation events
|
||||
// --- Initialization
|
||||
eventChecker = new MutationEventChecker;
|
||||
eventChecker.watchAttr(polyline, "points");
|
||||
// -- Actual changes
|
||||
eventChecker.expect("modify modify");
|
||||
points[0].x = 40;
|
||||
polyline.setAttribute("points", "30,375 150,380");
|
||||
// -- Redundant changes
|
||||
eventChecker.expect("");
|
||||
points[0].x = 30;
|
||||
points[1].y = 380;
|
||||
polyline.setAttribute("points", "30,375 150,380");
|
||||
eventChecker.finish();
|
||||
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
window.addEventListener("load", run_tests, false);
|
||||
|
||||
]]>
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
@ -7,6 +7,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=602759
|
||||
<script type="text/javascript" src="/MochiKit/packed.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="matrixUtils.js"></script>
|
||||
<script type="text/javascript" src="MutationEventChecker.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
@ -41,7 +42,8 @@ function main()
|
||||
testCreateSVGTransformFromMatrix,
|
||||
testReadOnly,
|
||||
testOrphan,
|
||||
testFailedSet
|
||||
testFailedSet,
|
||||
testMutationEvents
|
||||
];
|
||||
for (var i = 0; i < tests.length; i++) {
|
||||
tests[i](g);
|
||||
@ -355,6 +357,76 @@ function testFailedSet(g)
|
||||
"Animated transform list should also be empty after setting bad value");
|
||||
}
|
||||
|
||||
function testMutationEvents(g)
|
||||
{
|
||||
// Check mutation events
|
||||
|
||||
// Set initial value
|
||||
g.setAttribute("transform", "translate(50 90)");
|
||||
var list = g.transform.baseVal;
|
||||
is(list.numberOfItems, 1, "Unexpected initial length of list");
|
||||
eventChecker = new MutationEventChecker;
|
||||
eventChecker.watchAttr(g, "transform");
|
||||
|
||||
// consolidate
|
||||
//
|
||||
// Consolidate happens to generate two modification events in our
|
||||
// implementation--it's not ideal but it's better than none
|
||||
eventChecker.expect("modify modify modify");
|
||||
g.setAttribute("transform", "translate(10 10) translate(10 10)");
|
||||
list.consolidate();
|
||||
|
||||
// In the following, each of the operations is performed twice but only one
|
||||
// mutation event is expected. This is to check that redundant mutation
|
||||
// events are not sent.
|
||||
|
||||
// transform.setMatrix
|
||||
eventChecker.expect("modify");
|
||||
var mx = $('svg').createSVGMatrix();
|
||||
list[0].setMatrix(mx);
|
||||
list[0].setMatrix(mx);
|
||||
|
||||
// transform.setTranslate
|
||||
eventChecker.expect("modify");
|
||||
list[0].setTranslate(10, 10);
|
||||
list[0].setTranslate(10, 10);
|
||||
|
||||
// transform.setScale
|
||||
eventChecker.expect("modify");
|
||||
list[0].setScale(2, 2);
|
||||
list[0].setScale(2, 2);
|
||||
|
||||
// transform.setRotate
|
||||
eventChecker.expect("modify");
|
||||
list[0].setRotate(45, 1, 2);
|
||||
list[0].setRotate(45, 1, 2);
|
||||
|
||||
// transform.setSkewX
|
||||
eventChecker.expect("modify");
|
||||
list[0].setSkewX(45);
|
||||
list[0].setSkewX(45);
|
||||
|
||||
// transform.setSkewY
|
||||
eventChecker.expect("modify");
|
||||
list[0].setSkewY(25);
|
||||
list[0].setSkewY(25);
|
||||
|
||||
// transform.matrix
|
||||
eventChecker.expect("modify modify");
|
||||
list[0].matrix.a = 1;
|
||||
list[0].matrix.a = 1;
|
||||
list[0].matrix.e = 5;
|
||||
list[0].matrix.e = 5;
|
||||
|
||||
// setAttribute interaction
|
||||
eventChecker.expect("modify");
|
||||
list[0].setMatrix(mx);
|
||||
eventChecker.expect("");
|
||||
g.setAttribute("transform", "matrix(1, 0, 0, 1, 0, 0)");
|
||||
list[0].setMatrix(mx);
|
||||
eventChecker.finish();
|
||||
}
|
||||
|
||||
window.addEventListener("load", main, false);
|
||||
|
||||
]]>
|
||||
|
@ -6,6 +6,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=515116
|
||||
<title>Generic tests for SVG animated length lists</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="matrixUtils.js"></script>
|
||||
<script type="text/javascript" src="MutationEventChecker.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
@ -452,6 +453,7 @@ function get_array_of_list_items(list)
|
||||
function run_baseVal_API_tests()
|
||||
{
|
||||
var res, threw, items;
|
||||
var eventChecker = new MutationEventChecker;
|
||||
|
||||
for each (var t in tests) {
|
||||
|
||||
@ -462,6 +464,8 @@ function run_baseVal_API_tests()
|
||||
is(t.baseVal.numberOfItems, 4,
|
||||
'The '+t.list_type+' object should contain four list items.');
|
||||
|
||||
eventChecker.watchAttr(t.element, t.attr_name);
|
||||
eventChecker.expect("modify");
|
||||
res = t.baseVal.clear();
|
||||
|
||||
is(t.baseVal.numberOfItems, 0,
|
||||
@ -469,13 +473,48 @@ function run_baseVal_API_tests()
|
||||
' object.');
|
||||
is(res, undefined,
|
||||
'The method '+t.list_type+'.clear() should not return a value.');
|
||||
ok(t.element.hasAttribute(t.attr_name),
|
||||
'The method '+t.list_type+'.clear() should not remove the attribute.');
|
||||
ok(t.element.getAttribute(t.attr_name) === "",
|
||||
'Cleared '+t.attr_name+' ('+t.list_type+') but did not get an '+
|
||||
'empty string back.');
|
||||
|
||||
eventChecker.expect("");
|
||||
t.baseVal.clear();
|
||||
eventChecker.ignoreEvents();
|
||||
|
||||
// Test empty strings
|
||||
|
||||
t.element.setAttribute(t.attr_name, "");
|
||||
ok(t.element.getAttribute(t.attr_name) === "",
|
||||
'Set an empty attribute value for '+t.attr_name+' ('+t.list_type+
|
||||
') but did not get an empty string back.');
|
||||
|
||||
// Test removed attributes
|
||||
|
||||
t.element.removeAttribute(t.attr_name);
|
||||
ok(t.element.getAttribute(t.attr_name) === null,
|
||||
'Removed attribute value for '+t.attr_name+' ('+t.list_type+
|
||||
') but did not get null back.');
|
||||
ok(!t.element.hasAttribute(t.attr_name),
|
||||
'Removed attribute value for '+t.attr_name+' ('+t.list_type+
|
||||
') but hasAttribute still returns true.');
|
||||
|
||||
// Test .initialize():
|
||||
|
||||
t.element.setAttribute(t.attr_name, t.attr_val_4);
|
||||
|
||||
var item = t.item_constructor();
|
||||
// Our current implementation of 'initialize' for most list types performs
|
||||
// a 'clear' followed by an 'insertItemBefore'. This results in two
|
||||
// modification events being dispatched. SVGStringList however avoids the
|
||||
// additional clear.
|
||||
var expectedModEvents =
|
||||
t.item_type == "DOMString" ? "modify" : "modify modify";
|
||||
eventChecker.expect(expectedModEvents);
|
||||
var res = t.baseVal.initialize(item);
|
||||
eventChecker.ignoreEvents();
|
||||
|
||||
|
||||
is(t.baseVal.numberOfItems, 1,
|
||||
'The '+t.list_type+' object should contain one list item.');
|
||||
@ -515,6 +554,7 @@ function run_baseVal_API_tests()
|
||||
'is passed in, even if that object is the only item in that list.');
|
||||
// [SVGWG issue] not what the spec currently says
|
||||
|
||||
eventChecker.expect("");
|
||||
threw = false;
|
||||
try {
|
||||
t.baseVal.initialize({});
|
||||
@ -524,6 +564,7 @@ function run_baseVal_API_tests()
|
||||
ok(threw,
|
||||
'The method '+t.list_type+'.initialize() should throw if passed an '+
|
||||
'object of the wrong type.');
|
||||
eventChecker.ignoreEvents();
|
||||
}
|
||||
|
||||
// Test .insertItemBefore():
|
||||
@ -532,7 +573,9 @@ function run_baseVal_API_tests()
|
||||
|
||||
old_items = get_array_of_list_items(t.baseVal);
|
||||
item = t.item_constructor();
|
||||
eventChecker.expect("modify");
|
||||
res = t.baseVal.insertItemBefore(item, 2);
|
||||
eventChecker.ignoreEvents();
|
||||
|
||||
is(t.baseVal.numberOfItems, 5,
|
||||
'The '+t.list_type+' object should contain five list items.');
|
||||
@ -587,6 +630,7 @@ function run_baseVal_API_tests()
|
||||
'the list at the index specified.');
|
||||
// [SVGWG issue] not what the spec currently says
|
||||
|
||||
eventChecker.expect("");
|
||||
threw = false;
|
||||
try {
|
||||
t.baseVal.insertItemBefore({}, 2);
|
||||
@ -596,6 +640,7 @@ function run_baseVal_API_tests()
|
||||
ok(threw,
|
||||
'The method '+t.list_type+'.insertItemBefore() should throw if passed '+
|
||||
'an object of the wrong type.');
|
||||
eventChecker.ignoreEvents();
|
||||
}
|
||||
|
||||
// Test .replaceItem():
|
||||
@ -604,7 +649,9 @@ function run_baseVal_API_tests()
|
||||
|
||||
old_items = get_array_of_list_items(t.baseVal);
|
||||
item = t.item_constructor();
|
||||
eventChecker.expect("modify");
|
||||
res = t.baseVal.replaceItem(item, 2);
|
||||
eventChecker.ignoreEvents();
|
||||
|
||||
is(t.baseVal.numberOfItems, 4,
|
||||
'The '+t.list_type+' object should contain four list items.');
|
||||
@ -627,6 +674,7 @@ function run_baseVal_API_tests()
|
||||
|
||||
item = t.item_constructor();
|
||||
|
||||
eventChecker.expect("");
|
||||
threw = false;
|
||||
try {
|
||||
t.baseVal.replaceItem(item, 100);
|
||||
@ -636,6 +684,7 @@ function run_baseVal_API_tests()
|
||||
ok(threw,
|
||||
'The method '+t.list_type+'.replaceItem() should throw if passed '+
|
||||
'an index that is out of bounds.');
|
||||
eventChecker.ignoreEvents();
|
||||
|
||||
old_items = get_array_of_list_items(t.baseVal);
|
||||
item = t.baseVal.getItem(3);
|
||||
@ -683,7 +732,9 @@ function run_baseVal_API_tests()
|
||||
|
||||
old_items = get_array_of_list_items(t.baseVal);
|
||||
item = t.baseVal.getItem(2);
|
||||
eventChecker.expect("modify");
|
||||
res = t.baseVal.removeItem(2);
|
||||
eventChecker.ignoreEvents();
|
||||
|
||||
is(t.baseVal.numberOfItems, 3,
|
||||
'The '+t.list_type+' object should contain three list items.');
|
||||
@ -701,6 +752,7 @@ function run_baseVal_API_tests()
|
||||
'the item at index 2 was removed using the '+t.list_type+
|
||||
'.replaceItem() method.');
|
||||
|
||||
eventChecker.expect("");
|
||||
threw = false;
|
||||
try {
|
||||
t.baseVal.removeItem(100);
|
||||
@ -710,6 +762,7 @@ function run_baseVal_API_tests()
|
||||
ok(threw,
|
||||
'The method '+t.list_type+'.removeItem() should throw if passed '+
|
||||
'an index that is out of bounds.');
|
||||
eventChecker.ignoreEvents();
|
||||
|
||||
// Test .appendItem():
|
||||
|
||||
@ -717,7 +770,9 @@ function run_baseVal_API_tests()
|
||||
|
||||
old_items = get_array_of_list_items(t.baseVal);
|
||||
item = t.item_constructor();
|
||||
eventChecker.expect("modify");
|
||||
res = t.baseVal.appendItem(item);
|
||||
eventChecker.ignoreEvents();
|
||||
|
||||
is(t.baseVal.numberOfItems, 5,
|
||||
'The '+t.list_type+' object should contain five list items.');
|
||||
@ -763,6 +818,7 @@ function run_baseVal_API_tests()
|
||||
'that list.');
|
||||
// [SVGWG issue] not what the spec currently says
|
||||
|
||||
eventChecker.expect("");
|
||||
threw = false;
|
||||
try {
|
||||
t.baseVal.appendItem({});
|
||||
@ -772,7 +828,15 @@ function run_baseVal_API_tests()
|
||||
ok(threw,
|
||||
'The method '+t.list_type+'.appendItem() should throw if passed '+
|
||||
'an object of the wrong type.');
|
||||
eventChecker.ignoreEvents();
|
||||
}
|
||||
|
||||
// Test removal and addition events
|
||||
|
||||
eventChecker.expect("remove add");
|
||||
t.element.removeAttribute(t.attr_name);
|
||||
res = t.baseVal.appendItem(item);
|
||||
eventChecker.finish();
|
||||
}
|
||||
}
|
||||
|
||||
@ -880,7 +944,7 @@ function run_animVal_API_tests()
|
||||
|
||||
/**
|
||||
* This function runs some basic tests to check the effect of setAttribute()
|
||||
* calls on object identidy, without taking SMIL animation into consideration.
|
||||
* calls on object identity, without taking SMIL animation into consideration.
|
||||
*/
|
||||
function run_basic_setAttribute_tests()
|
||||
{
|
||||
|
@ -38,8 +38,11 @@ function runTests()
|
||||
is(filter.className.animVal, "bar", "className animVal");
|
||||
filter.removeAttribute("class");
|
||||
is(filter.hasAttribute("class"), false, "class attribute");
|
||||
ok(filter.getAttribute("class") === null, "removed class attribute");
|
||||
is(filter.className.baseVal, "", "className baseVal");
|
||||
is(filter.className.animVal, "", "className animVal");
|
||||
filter.setAttribute("class", "");
|
||||
ok(filter.getAttribute("class") === "", "empty class attribute");
|
||||
|
||||
// length attribute
|
||||
|
||||
@ -57,6 +60,11 @@ function runTests()
|
||||
is(marker.markerWidth.animVal.value, 7.5, "length animVal");
|
||||
is(marker.getAttribute("markerWidth"), "7.5", "length attribute");
|
||||
|
||||
marker.setAttribute("markerWidth", "");
|
||||
ok(marker.getAttribute("markerWidth") === "", "empty length attribute");
|
||||
marker.removeAttribute("markerWidth");
|
||||
ok(marker.getAttribute("markerWidth") === null, "removed length attribute");
|
||||
|
||||
// number attribute
|
||||
|
||||
convolve.setAttribute("divisor", "12.5");
|
||||
@ -67,6 +75,11 @@ function runTests()
|
||||
is(convolve.divisor.animVal, 7.5, "number animVal");
|
||||
is(convolve.getAttribute("divisor"), "7.5", "number attribute");
|
||||
|
||||
convolve.setAttribute("divisor", "");
|
||||
ok(convolve.getAttribute("divisor") === "", "empty number attribute");
|
||||
convolve.removeAttribute("divisor");
|
||||
ok(convolve.getAttribute("divisor") === null, "removed number attribute");
|
||||
|
||||
// number-optional-number attribute
|
||||
|
||||
blur.setAttribute("stdDeviation", "20.5");
|
||||
@ -89,6 +102,13 @@ function runTests()
|
||||
is(blur.stdDeviationY.baseVal, 0.5, "integer-optional-integer second baseVal");
|
||||
is(blur.stdDeviationY.animVal, 0.5, "integer-optional-integer second animVal");
|
||||
|
||||
blur.setAttribute("stdDeviation", "");
|
||||
ok(blur.getAttribute("stdDeviation") === "",
|
||||
"empty number-optional-number attribute");
|
||||
blur.removeAttribute("stdDeviation");
|
||||
ok(blur.getAttribute("stdDeviation") === null,
|
||||
"removed number-optional-number attribute");
|
||||
|
||||
// integer attribute
|
||||
|
||||
convolve.setAttribute("targetX", "12");
|
||||
@ -97,6 +117,10 @@ function runTests()
|
||||
convolve.targetX.baseVal = 7;
|
||||
is(convolve.targetX.animVal, 7, "integer animVal");
|
||||
is(convolve.getAttribute("targetX"), "7", "integer attribute");
|
||||
convolve.setAttribute("targetX", "");
|
||||
ok(convolve.getAttribute("targetX") === "", "empty integer attribute");
|
||||
convolve.removeAttribute("targetX");
|
||||
ok(convolve.getAttribute("targetX") === null, "removed integer attribute");
|
||||
|
||||
// integer-optional-integer attribute
|
||||
|
||||
@ -120,6 +144,13 @@ function runTests()
|
||||
is(filter.filterResY.baseVal, 90, "integer-optional-integer second baseVal");
|
||||
is(filter.filterResY.animVal, 90, "integer-optional-integer second animVal");
|
||||
|
||||
filter.setAttribute("filterRes", "");
|
||||
ok(filter.getAttribute("filterRes") === "",
|
||||
"empty integer-optional-integer attribute");
|
||||
filter.removeAttribute("filterRes");
|
||||
ok(filter.getAttribute("filterRes") === null,
|
||||
"removed integer-optional-integer attribute");
|
||||
|
||||
// angle attribute
|
||||
|
||||
marker.setAttribute("orient", "90deg");
|
||||
@ -136,6 +167,11 @@ function runTests()
|
||||
is(marker.orientAngle.animVal.value, 30, "angle animVal");
|
||||
is(marker.getAttribute("orient"), "30deg", "angle attribute");
|
||||
|
||||
marker.setAttribute("orient", "");
|
||||
ok(marker.getAttribute("orient") === "", "empty angle attribute");
|
||||
marker.removeAttribute("orient");
|
||||
ok(marker.getAttribute("orient") === null, "removed angle attribute");
|
||||
|
||||
// boolean attribute
|
||||
|
||||
convolve.setAttribute("preserveAlpha", "false");
|
||||
@ -144,6 +180,11 @@ function runTests()
|
||||
convolve.preserveAlpha.baseVal = true;
|
||||
is(convolve.preserveAlpha.animVal, true, "boolean animVal");
|
||||
is(convolve.getAttribute("preserveAlpha"), "true", "boolean attribute");
|
||||
convolve.setAttribute("preserveAlpha", "");
|
||||
ok(convolve.getAttribute("preserveAlpha") === "", "empty boolean attribute");
|
||||
convolve.removeAttribute("preserveAlpha");
|
||||
ok(convolve.getAttribute("preserveAlpha") === null,
|
||||
"removed boolean attribute");
|
||||
|
||||
// enum attribute
|
||||
|
||||
@ -153,6 +194,10 @@ function runTests()
|
||||
convolve.edgeMode.baseVal = 1;
|
||||
is(convolve.edgeMode.animVal, 1, "enum animVal");
|
||||
is(convolve.getAttribute("edgeMode"), "duplicate", "enum attribute");
|
||||
convolve.setAttribute("edgeMode", "");
|
||||
ok(convolve.getAttribute("edgeMode") === "", "empty enum attribute");
|
||||
convolve.removeAttribute("edgeMode");
|
||||
ok(convolve.getAttribute("edgeMode") === null, "removed enum attribute");
|
||||
|
||||
// string attribute
|
||||
|
||||
@ -162,6 +207,10 @@ function runTests()
|
||||
convolve.result.baseVal = "bar";
|
||||
is(convolve.result.animVal, "bar", "string animVal");
|
||||
is(convolve.getAttribute("result"), "bar", "string attribute");
|
||||
convolve.setAttribute("result", "");
|
||||
ok(convolve.getAttribute("result") === "", "empty string attribute");
|
||||
convolve.removeAttribute("result");
|
||||
ok(convolve.getAttribute("result") === null, "removed string attribute");
|
||||
|
||||
// preserveAspectRatio attribute
|
||||
|
||||
@ -186,6 +235,13 @@ function runTests()
|
||||
is(basePreserveAspectRatio.meetOrSlice, 2, "preserveAspectRatio.meetOrSlice baseVal");
|
||||
is(animPreserveAspectRatio.meetOrSlice, 2, "preserveAspectRatio.meetOrSlice animVal");
|
||||
|
||||
marker.setAttribute("preserveAspectRatio", "");
|
||||
ok(marker.getAttribute("preserveAspectRatio") === "",
|
||||
"empty preserveAspectRatio attribute");
|
||||
marker.removeAttribute("preserveAspectRatio");
|
||||
ok(marker.getAttribute("preserveAspectRatio") === null,
|
||||
"removed preserveAspectRatio attribute");
|
||||
|
||||
// viewBox attribute
|
||||
var baseViewBox = marker.viewBox.baseVal;
|
||||
var animViewBox = marker.viewBox.animVal;
|
||||
@ -223,6 +279,10 @@ function runTests()
|
||||
is(marker.getAttribute("viewBox"), "5 6 7 8", "viewBox attribute");
|
||||
marker.removeAttribute("viewBox");
|
||||
is(marker.hasAttribute("viewBox"), false, "viewBox hasAttribute");
|
||||
ok(marker.getAttribute("viewBox") === null, "removed viewBox attribute");
|
||||
|
||||
marker.setAttribute("viewBox", "");
|
||||
ok(marker.getAttribute("viewBox") === "", "empty viewBox attribute");
|
||||
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
245
content/svg/content/test/test_dataTypesModEvents.html
Normal file
245
content/svg/content/test/test_dataTypesModEvents.html
Normal file
@ -0,0 +1,245 @@
|
||||
<!DOCTYPE html>
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=629200
|
||||
-->
|
||||
<head>
|
||||
<title>Test for Bug 629200</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="application/javascript" src="MutationEventChecker.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=629200">Mozilla
|
||||
Bug 629200</a>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none"></div>
|
||||
|
||||
<iframe id="svg" src="dataTypes-helper.svg"></iframe>
|
||||
|
||||
<pre id="test">
|
||||
<script class="testbody" type="application/javascript">
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
function runTests()
|
||||
{
|
||||
var doc = $("svg").contentWindow.document;
|
||||
var filter = doc.getElementById("filter");
|
||||
var convolve = doc.getElementById("convolve");
|
||||
var blur = doc.getElementById("blur");
|
||||
var marker = doc.getElementById("marker");
|
||||
var eventChecker = new MutationEventChecker;
|
||||
|
||||
// class attribute
|
||||
|
||||
eventChecker.watchAttr(filter, "class");
|
||||
eventChecker.expect("add modify remove add");
|
||||
filter.setAttribute("class", "foo");
|
||||
filter.className.baseVal = "bar";
|
||||
filter.removeAttribute("class");
|
||||
filter.className.baseVal = "foo";
|
||||
|
||||
eventChecker.expect("");
|
||||
filter.className.baseVal = "foo";
|
||||
filter.setAttribute("class", "foo");
|
||||
|
||||
// length attribute
|
||||
|
||||
eventChecker.watchAttr(marker, "markerWidth");
|
||||
eventChecker.expect("add modify modify modify modify modify remove add");
|
||||
marker.setAttribute("markerWidth", "12.5");
|
||||
marker.markerWidth.baseVal.value = 8;
|
||||
marker.markerWidth.baseVal.valueInSpecifiedUnits = 9;
|
||||
marker.markerWidth.baseVal.valueAsString = "10";
|
||||
marker.markerWidth.baseVal.convertToSpecifiedUnits(
|
||||
SVGLength.SVG_LENGTHTYPE_CM);
|
||||
marker.markerWidth.baseVal.newValueSpecifiedUnits(
|
||||
SVGLength.SVG_LENGTHTYPE_MM, 11);
|
||||
marker.removeAttribute("markerWidth");
|
||||
marker.markerWidth.baseVal.value = 8;
|
||||
|
||||
eventChecker.expect("remove add modify");
|
||||
marker.removeAttribute("markerWidth");
|
||||
console.log(marker.getAttribute("markerWidth"));
|
||||
marker.markerWidth.baseVal.convertToSpecifiedUnits(
|
||||
SVGLength.SVG_LENGTHTYPE_NUMBER);
|
||||
console.log(marker.getAttribute("markerWidth"));
|
||||
marker.markerWidth.baseVal.value = 8;
|
||||
|
||||
eventChecker.expect("");
|
||||
marker.markerWidth.baseVal.value = 8;
|
||||
marker.setAttribute("markerWidth", "8");
|
||||
marker.markerWidth.baseVal.value = 8;
|
||||
marker.markerWidth.baseVal.valueAsString = "8";
|
||||
marker.markerWidth.baseVal.convertToSpecifiedUnits(
|
||||
SVGLength.SVG_LENGTHTYPE_NUMBER);
|
||||
marker.markerWidth.baseVal.newValueSpecifiedUnits(
|
||||
SVGLength.SVG_LENGTHTYPE_NUMBER, 8);
|
||||
|
||||
// number attribute
|
||||
|
||||
eventChecker.watchAttr(convolve, "divisor");
|
||||
eventChecker.expect("add modify remove add");
|
||||
convolve.setAttribute("divisor", "12.5");
|
||||
convolve.divisor.baseVal = 6;
|
||||
convolve.removeAttribute("divisor");
|
||||
convolve.divisor.baseVal = 8;
|
||||
|
||||
eventChecker.expect("");
|
||||
convolve.divisor.baseVal = 8;
|
||||
convolve.setAttribute("divisor", "8");
|
||||
|
||||
// number-optional-number attribute
|
||||
|
||||
eventChecker.watchAttr(blur, "stdDeviation");
|
||||
eventChecker.expect("add modify remove add");
|
||||
blur.setAttribute("stdDeviation", "5, 6");
|
||||
blur.stdDeviationX.baseVal = 8;
|
||||
blur.removeAttribute("stdDeviation");
|
||||
blur.setAttribute("stdDeviation", "2, 3");
|
||||
|
||||
eventChecker.expect("");
|
||||
blur.stdDeviationX.baseVal = 2;
|
||||
blur.stdDeviationY.baseVal = 3;
|
||||
blur.setAttribute("stdDeviation", "2, 3");
|
||||
|
||||
// integer attribute
|
||||
|
||||
eventChecker.watchAttr(convolve, "targetX");
|
||||
eventChecker.expect("add modify remove add");
|
||||
convolve.setAttribute("targetX", "12");
|
||||
convolve.targetX.baseVal = 6;
|
||||
convolve.removeAttribute("targetX");
|
||||
convolve.targetX.baseVal = 8;
|
||||
|
||||
// Check redundant change when comparing typed value to attribute value
|
||||
eventChecker.expect("");
|
||||
convolve.setAttribute("targetX", "8");
|
||||
// Check redundant change when comparing attribute value to typed value
|
||||
eventChecker.expect("remove add");
|
||||
convolve.removeAttribute("targetX");
|
||||
convolve.setAttribute("targetX", "8");
|
||||
convolve.targetX.baseVal = 8;
|
||||
|
||||
// integer-optional-integer attribute
|
||||
|
||||
eventChecker.watchAttr(filter, "filterRes");
|
||||
eventChecker.expect("add modify remove add");
|
||||
filter.setAttribute("filterRes", "60, 70");
|
||||
filter.filterResX.baseVal = 50;
|
||||
filter.removeAttribute("filterRes");
|
||||
filter.setAttribute("filterRes", "50, 60");
|
||||
|
||||
eventChecker.expect("");
|
||||
filter.filterResX.baseVal = 50;
|
||||
filter.setAttribute("filterRes", "50, 60");
|
||||
filter.filterResY.baseVal = 60;
|
||||
|
||||
// angle attribute
|
||||
|
||||
eventChecker.watchAttr(marker, "orient");
|
||||
eventChecker.expect("add modify modify modify modify modify remove add");
|
||||
marker.setAttribute("orient", "90deg");
|
||||
marker.orientAngle.baseVal.value = 12;
|
||||
marker.orientAngle.baseVal.valueInSpecifiedUnits = 23;
|
||||
marker.orientAngle.baseVal.valueAsString = "34";
|
||||
marker.orientAngle.baseVal.newValueSpecifiedUnits(
|
||||
SVGAngle.SVG_ANGLETYPE_GRAD, 34);
|
||||
marker.orientAngle.baseVal.newValueSpecifiedUnits(
|
||||
SVGAngle.SVG_ANGLETYPE_GRAD, 45);
|
||||
marker.removeAttribute("orient");
|
||||
marker.orientAngle.baseVal.value = 40;
|
||||
|
||||
eventChecker.expect("");
|
||||
marker.orientAngle.baseVal.value = 40;
|
||||
marker.orientAngle.baseVal.valueInSpecifiedUnits = 40;
|
||||
marker.orientAngle.baseVal.valueAsString = "40";
|
||||
marker.orientAngle.baseVal.convertToSpecifiedUnits(
|
||||
SVGAngle.SVG_ANGLETYPE_UNSPECIFIED);
|
||||
marker.orientAngle.baseVal.newValueSpecifiedUnits(
|
||||
SVGAngle.SVG_ANGLETYPE_UNSPECIFIED, 40);
|
||||
|
||||
// boolean attribute
|
||||
|
||||
eventChecker.watchAttr(convolve, "preserveAlpha");
|
||||
eventChecker.expect("add modify remove add");
|
||||
convolve.setAttribute("preserveAlpha", "true");
|
||||
convolve.preserveAlpha.baseVal = false;
|
||||
convolve.removeAttribute("preserveAlpha");
|
||||
convolve.preserveAlpha.baseVal = true;
|
||||
|
||||
eventChecker.expect("");
|
||||
convolve.preserveAlpha.baseVal = true;
|
||||
convolve.setAttribute("preserveAlpha", "true");
|
||||
|
||||
// enum attribute
|
||||
|
||||
eventChecker.watchAttr(convolve, "edgeMode");
|
||||
eventChecker.expect("add modify remove add");
|
||||
convolve.setAttribute("edgeMode", "none");
|
||||
convolve.edgeMode.baseVal = SVGFEConvolveMatrixElement.SVG_EDGEMODE_WRAP;
|
||||
convolve.removeAttribute("edgeMode");
|
||||
convolve.edgeMode.baseVal = SVGFEConvolveMatrixElement.SVG_EDGEMODE_NONE;
|
||||
|
||||
eventChecker.expect("");
|
||||
convolve.edgeMode.baseVal = SVGFEConvolveMatrixElement.SVG_EDGEMODE_NONE;
|
||||
convolve.setAttribute("edgeMode", "none");
|
||||
convolve.edgeMode.baseVal = SVGFEConvolveMatrixElement.SVG_EDGEMODE_NONE;
|
||||
|
||||
// string attribute
|
||||
|
||||
eventChecker.watchAttr(convolve, "result");
|
||||
eventChecker.expect("add modify remove add");
|
||||
convolve.setAttribute("result", "bar");
|
||||
convolve.result.baseVal = "foo";
|
||||
convolve.removeAttribute("result");
|
||||
convolve.result.baseVal = "bar";
|
||||
|
||||
eventChecker.expect("");
|
||||
convolve.result.baseVal = "bar";
|
||||
convolve.setAttribute("result", "bar");
|
||||
convolve.result.baseVal = "bar";
|
||||
|
||||
// preserveAspectRatio attribute
|
||||
|
||||
eventChecker.watchAttr(marker, "preserveAspectRatio");
|
||||
eventChecker.expect("add modify remove add");
|
||||
marker.setAttribute("preserveAspectRatio", "xMaxYMid slice");
|
||||
marker.preserveAspectRatio.baseVal.align =
|
||||
SVGPreserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMAXYMAX;
|
||||
marker.removeAttribute("preserveAspectRatio");
|
||||
marker.preserveAspectRatio.baseVal.align =
|
||||
SVGPreserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMIDYMIN;
|
||||
|
||||
eventChecker.expect("");
|
||||
marker.preserveAspectRatio.baseVal.meetOrSlice =
|
||||
SVGPreserveAspectRatio.SVG_MEETORSLICE_MEET;
|
||||
marker.setAttribute("preserveAspectRatio", "xMidYMin meet");
|
||||
|
||||
// viewBox attribute
|
||||
|
||||
eventChecker.watchAttr(marker, "viewBox");
|
||||
eventChecker.expect("add modify remove add");
|
||||
marker.setAttribute("viewBox", "1 2 3 4");
|
||||
marker.viewBox.baseVal.height = 5;
|
||||
marker.removeAttribute("viewBox");
|
||||
marker.viewBox.baseVal.height = 4;
|
||||
|
||||
eventChecker.ignoreEvents();
|
||||
marker.setAttribute("viewBox", "1 2 3 4");
|
||||
eventChecker.expect("");
|
||||
marker.viewBox.baseVal.height = 4;
|
||||
marker.viewBox.baseVal.x = 1;
|
||||
marker.setAttribute("viewBox", "1 2 3 4");
|
||||
|
||||
eventChecker.finish();
|
||||
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
window.addEventListener("load", runTests, false);
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
@ -4121,7 +4121,7 @@ nsDocShell::DisplayLoadError(nsresult aError, nsIURI *aURI,
|
||||
NS_ENSURE_FALSE(messageStr.IsEmpty(), NS_ERROR_FAILURE);
|
||||
// Note: For now, display an alert instead of an error page if we have no
|
||||
// URI object. Missing URI objects are handled badly by session history.
|
||||
if (mUseErrorPages && aURI && aFailedChannel) {
|
||||
if (mUseErrorPages && aURI) {
|
||||
// Display an error page
|
||||
LoadErrorPage(aURI, aURL, errorPage.get(), error.get(),
|
||||
messageStr.get(), cssClass.get(), aFailedChannel);
|
||||
|
@ -97,6 +97,11 @@ DIRS += \
|
||||
$(NULL)
|
||||
endif
|
||||
|
||||
ifdef MOZ_B2G_BT
|
||||
DIRS += \
|
||||
bluetooth \
|
||||
$(NULL)
|
||||
endif
|
||||
TEST_DIRS += tests
|
||||
ifneq (,$(filter gtk2 cocoa windows android qt os2,$(MOZ_WIDGET_TOOLKIT)))
|
||||
TEST_DIRS += plugins/test
|
||||
|
@ -80,6 +80,10 @@
|
||||
#ifdef MOZ_B2G_RIL
|
||||
#include "TelephonyFactory.h"
|
||||
#endif
|
||||
#ifdef MOZ_B2G_BT
|
||||
#include "nsIDOMBluetoothAdapter.h"
|
||||
#include "BluetoothAdapter.h"
|
||||
#endif
|
||||
|
||||
// This should not be in the namespace.
|
||||
DOMCI_DATA(Navigator, mozilla::dom::Navigator)
|
||||
@ -133,6 +137,9 @@ NS_INTERFACE_MAP_BEGIN(Navigator)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIDOMNavigatorTelephony)
|
||||
#endif
|
||||
NS_INTERFACE_MAP_ENTRY(nsIDOMMozNavigatorNetwork)
|
||||
#ifdef MOZ_B2G_BT
|
||||
NS_INTERFACE_MAP_ENTRY(nsIDOMNavigatorBluetooth)
|
||||
#endif
|
||||
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(Navigator)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
@ -182,6 +189,12 @@ Navigator::Invalidate()
|
||||
mConnection->Shutdown();
|
||||
mConnection = nsnull;
|
||||
}
|
||||
|
||||
#ifdef MOZ_B2G_BT
|
||||
if (mBluetooth) {
|
||||
mBluetooth = nsnull;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
nsPIDOMWindow *
|
||||
@ -1112,6 +1125,30 @@ Navigator::GetMozConnection(nsIDOMMozConnection** aConnection)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
#ifdef MOZ_B2G_BT
|
||||
//*****************************************************************************
|
||||
// nsNavigator::nsIDOMNavigatorBluetooth
|
||||
//*****************************************************************************
|
||||
|
||||
NS_IMETHODIMP
|
||||
Navigator::GetMozBluetooth(nsIDOMBluetoothAdapter** aBluetooth)
|
||||
{
|
||||
nsCOMPtr<nsIDOMBluetoothAdapter> bluetooth = mBluetooth;
|
||||
|
||||
if (!bluetooth) {
|
||||
nsCOMPtr<nsPIDOMWindow> window = do_QueryReferent(mWindow);
|
||||
NS_ENSURE_TRUE(window, NS_ERROR_FAILURE);
|
||||
|
||||
mBluetooth = new bluetooth::BluetoothAdapter();
|
||||
|
||||
bluetooth = mBluetooth;
|
||||
}
|
||||
|
||||
bluetooth.forget(aBluetooth);
|
||||
return NS_OK;
|
||||
}
|
||||
#endif //MOZ_B2G_BT
|
||||
|
||||
PRInt64
|
||||
Navigator::SizeOf() const
|
||||
{
|
||||
|
@ -65,6 +65,11 @@ class nsIDOMMozConnection;
|
||||
class nsIDOMTelephony;
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_B2G_BT
|
||||
#include "nsIDOMNavigatorBluetooth.h"
|
||||
#endif
|
||||
|
||||
class nsIDOMAdapter;
|
||||
//*****************************************************************************
|
||||
// Navigator: Script "navigator" object
|
||||
//*****************************************************************************
|
||||
@ -98,6 +103,9 @@ class Navigator : public nsIDOMNavigator
|
||||
, public nsIDOMNavigatorTelephony
|
||||
#endif
|
||||
, public nsIDOMMozNavigatorNetwork
|
||||
#ifdef MOZ_B2G_BT
|
||||
, public nsIDOMNavigatorBluetooth
|
||||
#endif
|
||||
{
|
||||
public:
|
||||
Navigator(nsPIDOMWindow *aInnerWindow);
|
||||
@ -115,6 +123,10 @@ public:
|
||||
#endif
|
||||
NS_DECL_NSIDOMMOZNAVIGATORNETWORK
|
||||
|
||||
#ifdef MOZ_B2G_BT
|
||||
NS_DECL_NSIDOMNAVIGATORBLUETOOTH
|
||||
#endif
|
||||
|
||||
static void Init();
|
||||
|
||||
void Invalidate();
|
||||
@ -146,6 +158,9 @@ private:
|
||||
nsCOMPtr<nsIDOMTelephony> mTelephony;
|
||||
#endif
|
||||
nsRefPtr<network::Connection> mConnection;
|
||||
#ifdef MOZ_B2G_BT
|
||||
nsCOMPtr<nsIDOMBluetoothAdapter> mBluetooth;
|
||||
#endif
|
||||
nsWeakPtr mWindow;
|
||||
};
|
||||
|
||||
|
@ -532,6 +532,10 @@ using mozilla::dom::indexedDB::IDBWrapperCache;
|
||||
#include "CallEvent.h"
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_B2G_BT
|
||||
#include "BluetoothAdapter.h"
|
||||
#endif
|
||||
|
||||
#include "DOMError.h"
|
||||
|
||||
using namespace mozilla;
|
||||
@ -1627,6 +1631,11 @@ static nsDOMClassInfoData sClassInfoData[] = {
|
||||
DOM_DEFAULT_SCRIPTABLE_FLAGS)
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_B2G_BT
|
||||
NS_DEFINE_CLASSINFO_DATA(BluetoothAdapter, nsDOMGenericSH,
|
||||
DOM_DEFAULT_SCRIPTABLE_FLAGS)
|
||||
#endif
|
||||
|
||||
NS_DEFINE_CLASSINFO_DATA(DOMError, nsDOMGenericSH,
|
||||
DOM_DEFAULT_SCRIPTABLE_FLAGS)
|
||||
};
|
||||
@ -2423,6 +2432,9 @@ nsDOMClassInfo::Init()
|
||||
#endif
|
||||
DOM_CLASSINFO_MAP_CONDITIONAL_ENTRY(nsIDOMMozNavigatorNetwork,
|
||||
network::IsAPIEnabled())
|
||||
#ifdef MOZ_B2G_BT
|
||||
DOM_CLASSINFO_MAP_ENTRY(nsIDOMNavigatorBluetooth)
|
||||
#endif
|
||||
DOM_CLASSINFO_MAP_END
|
||||
|
||||
DOM_CLASSINFO_MAP_BEGIN(Plugin, nsIDOMPlugin)
|
||||
@ -4365,6 +4377,12 @@ nsDOMClassInfo::Init()
|
||||
DOM_CLASSINFO_MAP_END
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_B2G_BT
|
||||
DOM_CLASSINFO_MAP_BEGIN(BluetoothAdapter, nsIDOMBluetoothAdapter)
|
||||
DOM_CLASSINFO_MAP_ENTRY(nsIDOMBluetoothAdapter)
|
||||
DOM_CLASSINFO_MAP_END
|
||||
#endif
|
||||
|
||||
DOM_CLASSINFO_MAP_BEGIN(DOMError, nsIDOMDOMError)
|
||||
DOM_CLASSINFO_MAP_ENTRY(nsIDOMDOMError)
|
||||
DOM_CLASSINFO_MAP_END
|
||||
|
@ -540,4 +540,8 @@ DOMCI_CLASS(TelephonyCall)
|
||||
DOMCI_CLASS(CallEvent)
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_B2G_BT
|
||||
DOMCI_CLASS(BluetoothAdapter)
|
||||
#endif
|
||||
|
||||
DOMCI_CLASS(DOMError)
|
||||
|
39
dom/bluetooth/BluetoothAdapter.cpp
Normal file
39
dom/bluetooth/BluetoothAdapter.cpp
Normal file
@ -0,0 +1,39 @@
|
||||
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=40: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "BluetoothAdapter.h"
|
||||
#include "nsDOMClassInfo.h"
|
||||
|
||||
USING_BLUETOOTH_NAMESPACE
|
||||
|
||||
BluetoothAdapter::BluetoothAdapter() : mPower(false)
|
||||
{
|
||||
}
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN(BluetoothAdapter)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIDOMBluetoothAdapter)
|
||||
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
||||
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(BluetoothAdapter)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
NS_IMPL_ADDREF(BluetoothAdapter)
|
||||
NS_IMPL_RELEASE(BluetoothAdapter)
|
||||
|
||||
DOMCI_DATA(BluetoothAdapter, BluetoothAdapter)
|
||||
|
||||
NS_IMETHODIMP
|
||||
BluetoothAdapter::GetPower(bool* aPower)
|
||||
{
|
||||
*aPower = mPower;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
BluetoothAdapter::SetPower(bool aPower)
|
||||
{
|
||||
mPower = aPower;
|
||||
return NS_OK;
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user