diff --git a/accessible/src/html/nsHyperTextAccessible.cpp b/accessible/src/html/nsHyperTextAccessible.cpp index 1b0fce62ff22..c1060c317002 100644 --- a/accessible/src/html/nsHyperTextAccessible.cpp +++ b/accessible/src/html/nsHyperTextAccessible.cpp @@ -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) && diff --git a/b2g/installer/package-manifest.in b/b2g/installer/package-manifest.in index ff4274923561..5e3d84ae0f6b 100644 --- a/b2g/installer/package-manifest.in +++ b/b2g/installer/package-manifest.in @@ -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 diff --git a/browser/app/profile/firefox.js b/browser/app/profile/firefox.js index 9caa62d572a0..f89a8abda58c 100644 --- a/browser/app/profile/firefox.js +++ b/browser/app/profile/firefox.js @@ -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); diff --git a/browser/base/content/browser.js b/browser/base/content/browser.js index e59319f098ff..3adbc57d129c 100644 --- a/browser/base/content/browser.js +++ b/browser/base/content/browser.js @@ -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 }); }, diff --git a/browser/base/content/tabbrowser.xml b/browser/base/content/tabbrowser.xml index 30f18e072758..90aa31dba5dd 100644 --- a/browser/base/content/tabbrowser.xml +++ b/browser/base/content/tabbrowser.xml @@ -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; diff --git a/browser/base/content/test/authenticate.sjs b/browser/base/content/test/authenticate.sjs index 7c2102fd0dbb..58da655cf98f 100644 --- a/browser/base/content/test/authenticate.sjs +++ b/browser/base/content/test/authenticate.sjs @@ -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); diff --git a/browser/base/content/test/browser_homeDrop.js b/browser/base/content/test/browser_homeDrop.js index a6cb961ae211..c8c63cc1a7a6 100644 --- a/browser/base/content/test/browser_homeDrop.js +++ b/browser/base/content/test/browser_homeDrop.js @@ -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: diff --git a/browser/devtools/debugger/test/browser_dbg_select-line.js b/browser/devtools/debugger/test/browser_dbg_select-line.js index 57e7b8186b9e..885e5786c96a 100644 --- a/browser/devtools/debugger/test/browser_dbg_select-line.js +++ b/browser/devtools/debugger/test/browser_dbg_select-line.js @@ -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); }); diff --git a/browser/installer/package-manifest.in b/browser/installer/package-manifest.in index 21fc0c3088e6..98f687c2dac2 100644 --- a/browser/installer/package-manifest.in +++ b/browser/installer/package-manifest.in @@ -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/* diff --git a/browser/locales/en-US/searchplugins/google-params.inc b/browser/locales/en-US/searchplugins/google-params.inc deleted file mode 100644 index 1764477c8f88..000000000000 --- a/browser/locales/en-US/searchplugins/google-params.inc +++ /dev/null @@ -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 diff --git a/browser/locales/en-US/searchplugins/google.xml b/browser/locales/en-US/searchplugins/google.xml index 3e6794c39e48..6bf3f44cca36 100644 --- a/browser/locales/en-US/searchplugins/google.xml +++ b/browser/locales/en-US/searchplugins/google.xml @@ -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> diff --git a/build/mobile/robocop/Actions.java.in b/build/mobile/robocop/Actions.java.in index 7be67df3cf54..0c123016921d 100644 --- a/build/mobile/robocop/Actions.java.in +++ b/build/mobile/robocop/Actions.java.in @@ -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); } diff --git a/build/mobile/robocop/Assert.java.in b/build/mobile/robocop/Assert.java.in index d3afb7bd31c3..28a14dbdb5c9 100644 --- a/build/mobile/robocop/Assert.java.in +++ b/build/mobile/robocop/Assert.java.in @@ -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); } diff --git a/build/mobile/robocop/Driver.java.in b/build/mobile/robocop/Driver.java.in index b026fe47a23c..e358ec89a239 100644 --- a/build/mobile/robocop/Driver.java.in +++ b/build/mobile/robocop/Driver.java.in @@ -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(); } diff --git a/build/mobile/robocop/Element.java.in b/build/mobile/robocop/Element.java.in index 76bbbd716730..2c87bd208f9e 100644 --- a/build/mobile/robocop/Element.java.in +++ b/build/mobile/robocop/Element.java.in @@ -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(); } diff --git a/build/mobile/robocop/FennecMochitestAssert.java.in b/build/mobile/robocop/FennecMochitestAssert.java.in index 35a596522427..20199ec51109 100644 --- a/build/mobile/robocop/FennecMochitestAssert.java.in +++ b/build/mobile/robocop/FennecMochitestAssert.java.in @@ -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?"); + } } diff --git a/build/mobile/robocop/FennecNativeActions.java.in b/build/mobile/robocop/FennecNativeActions.java.in index 1992d87c83e0..973a3fd70bb6 100644 --- a/build/mobile/robocop/FennecNativeActions.java.in +++ b/build/mobile/robocop/FennecNativeActions.java.in @@ -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); - } } diff --git a/build/mobile/robocop/FennecNativeDriver.java.in b/build/mobile/robocop/FennecNativeDriver.java.in index 76263ca7d782..eb6d048dcb54 100644 --- a/build/mobile/robocop/FennecNativeDriver.java.in +++ b/build/mobile/robocop/FennecNativeDriver.java.in @@ -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); + } } - } } diff --git a/build/mobile/robocop/FennecNativeElement.java.in b/build/mobile/robocop/FennecNativeElement.java.in index bbbe04304044..0785a0de2bd9 100644 --- a/build/mobile/robocop/FennecNativeElement.java.in +++ b/build/mobile/robocop/FennecNativeElement.java.in @@ -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; - } } diff --git a/build/mobile/robocop/FennecTalosAssert.java.in b/build/mobile/robocop/FennecTalosAssert.java.in index 5fa85a4405f8..9a9d75511d44 100644 --- a/build/mobile/robocop/FennecTalosAssert.java.in +++ b/build/mobile/robocop/FennecTalosAssert.java.in @@ -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) { } } diff --git a/build/mobile/robocop/RoboCopException.java.in b/build/mobile/robocop/RoboCopException.java.in index de908cc32137..adc5b6af5195 100644 --- a/build/mobile/robocop/RoboCopException.java.in +++ b/build/mobile/robocop/RoboCopException.java.in @@ -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); + } } diff --git a/config/autoconf.mk.in b/config/autoconf.mk.in index 57cca0db44bf..b8d954ccc17e 100644 --- a/config/autoconf.mk.in +++ b/config/autoconf.mk.in @@ -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@ diff --git a/configure.in b/configure.in index d983a02ff42c..4d9a187c4614 100644 --- a/configure.in +++ b/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 ======================================================== diff --git a/content/base/public/nsIMessageWakeupService.idl b/content/base/public/nsIMessageWakeupService.idl deleted file mode 100644 index bd16ee8eb329..000000000000 --- a/content/base/public/nsIMessageWakeupService.idl +++ /dev/null @@ -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); -}; - diff --git a/content/base/src/messageWakeupService.js b/content/base/src/messageWakeupService.js index bdf011cde031..ffc6cfc8e940 100644 --- a/content/base/src/messageWakeupService.js +++ b/content/base/src/messageWakeupService.js @@ -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: [], diff --git a/content/base/src/nsAttrAndChildArray.h b/content/base/src/nsAttrAndChildArray.h index a3e66c1e4012..2e56ac5ddfee 100644 --- a/content/base/src/nsAttrAndChildArray.h +++ b/content/base/src/nsAttrAndChildArray.h @@ -136,6 +136,10 @@ public: } PRInt64 SizeOf() const; + bool HasMappedAttrs() const + { + return MappedAttrCount(); + } private: nsAttrAndChildArray(const nsAttrAndChildArray& aOther) MOZ_DELETE; diff --git a/content/base/src/nsAttrValue.cpp b/content/base/src/nsAttrValue.cpp index f0791f2b99ae..dd9b995358f0 100644 --- a/content/base/src/nsAttrValue.cpp +++ b/content/base/src/nsAttrValue.cpp @@ -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() { diff --git a/content/base/src/nsAttrValue.h b/content/base/src/nsAttrValue.h index 8b797248f11e..7e90f8807506 100644 --- a/content/base/src/nsAttrValue.h +++ b/content/base/src/nsAttrValue.h @@ -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) { diff --git a/content/base/src/nsEventSource.cpp b/content/base/src/nsEventSource.cpp index cb91fea9bdbf..b0860e281512 100644 --- a/content/base/src/nsEventSource.cpp +++ b/content/base/src/nsEventSource.cpp @@ -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 diff --git a/content/base/src/nsEventSource.h b/content/base/src/nsEventSource.h index 4ee1c32b0045..0b04bce34e56 100644 --- a/content/base/src/nsEventSource.h +++ b/content/base/src/nsEventSource.h @@ -216,6 +216,7 @@ protected: bool mErrorLoadOnRedirect; bool mGoingToDispatchAllMessages; bool mWithCredentials; + bool mWaitingForOnStopRequest; // used while reading the input streams nsCOMPtr<nsIUnicodeDecoder> mUnicodeDecoder; diff --git a/content/base/src/nsWebSocket.cpp b/content/base/src/nsWebSocket.cpp index 1a6f14571203..b5b53594db3e 100644 --- a/content/base/src/nsWebSocket.cpp +++ b/content/base/src/nsWebSocket.cpp @@ -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 diff --git a/content/base/src/nsXMLHttpRequest.cpp b/content/base/src/nsXMLHttpRequest.cpp index 170b68fa4598..bb86e90fecea 100644 --- a/content/base/src/nsXMLHttpRequest.cpp +++ b/content/base/src/nsXMLHttpRequest.cpp @@ -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; diff --git a/content/base/src/nsXMLHttpRequest.h b/content/base/src/nsXMLHttpRequest.h index 3d5a1ab84249..f25c953d6a6b 100644 --- a/content/base/src/nsXMLHttpRequest.h +++ b/content/base/src/nsXMLHttpRequest.h @@ -365,7 +365,7 @@ protected: void HandleTimeoutCallback(); bool mErrorLoad; - + bool mWaitingForOnStopRequest; bool mProgressTimerIsActive; bool mProgressEventWasDelayed; bool mIsHtml; diff --git a/content/base/test/test_bug338679.html b/content/base/test/test_bug338679.html index cea297736a2f..ac34bfc0156e 100644 --- a/content/base/test/test_bug338679.html +++ b/content/base/test/test_bug338679.html @@ -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; diff --git a/content/canvas/src/WebGLContext.h b/content/canvas/src/WebGLContext.h index 5f1d14181b15..5a709d0c1ea3 100644 --- a/content/canvas/src/WebGLContext.h +++ b/content/canvas/src/WebGLContext.h @@ -2388,6 +2388,7 @@ public: NS_DECL_ISUPPORTS NS_DECL_NSIWEBGLEXTENSION + virtual ~WebGLExtension() {} }; inline const WebGLRectangleObject *WebGLContext::FramebufferRectangleObject() const { diff --git a/content/html/content/src/nsDOMValidityState.h b/content/html/content/src/nsDOMValidityState.h index 8370b45b9a26..5980757f2346 100644 --- a/content/html/content/src/nsDOMValidityState.h +++ b/content/html/content/src/nsDOMValidityState.h @@ -42,7 +42,7 @@ #include "nsIConstraintValidation.h" -class nsDOMValidityState : public nsIDOMValidityState +class nsDOMValidityState MOZ_FINAL : public nsIDOMValidityState { public: NS_DECL_ISUPPORTS diff --git a/content/html/content/src/nsHTMLInputElement.cpp b/content/html/content/src/nsHTMLInputElement.cpp index a17eb86e732c..0c862a57b98c 100644 --- a/content/html/content/src/nsHTMLInputElement.cpp +++ b/content/html/content/src/nsHTMLInputElement.cpp @@ -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) diff --git a/content/html/content/src/nsHTMLInputElement.h b/content/html/content/src/nsHTMLInputElement.h index c462c85b6ea9..453b8f7a06f1 100644 --- a/content/html/content/src/nsHTMLInputElement.h +++ b/content/html/content/src/nsHTMLInputElement.h @@ -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 diff --git a/content/html/content/src/nsHTMLMediaElement.cpp b/content/html/content/src/nsHTMLMediaElement.cpp index c4cc3d966c29..fcb41e0946ca 100644 --- a/content/html/content/src/nsHTMLMediaElement.cpp +++ b/content/html/content/src/nsHTMLMediaElement.cpp @@ -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 diff --git a/content/html/content/src/nsMediaError.h b/content/html/content/src/nsMediaError.h index 33d657f650c8..c540afd92335 100644 --- a/content/html/content/src/nsMediaError.h +++ b/content/html/content/src/nsMediaError.h @@ -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); diff --git a/content/html/content/src/nsTimeRanges.h b/content/html/content/src/nsTimeRanges.h index 172cadb5b85f..8359b2378deb 100644 --- a/content/html/content/src/nsTimeRanges.h +++ b/content/html/content/src/nsTimeRanges.h @@ -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 diff --git a/content/media/nsBuiltinDecoder.cpp b/content/media/nsBuiltinDecoder.cpp index c4b0c294b2ed..a0f40e5802f3 100644 --- a/content/media/nsBuiltinDecoder.cpp +++ b/content/media/nsBuiltinDecoder.cpp @@ -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 diff --git a/content/svg/content/src/DOMSVGLength.cpp b/content/svg/content/src/DOMSVGLength.cpp index 8e0de116e52d..ada2143a2042 100644 --- a/content/svg/content/src/DOMSVGLength.cpp +++ b/content/svg/content/src/DOMSVGLength.cpp @@ -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 { diff --git a/content/svg/content/src/DOMSVGLengthList.cpp b/content/svg/content/src/DOMSVGLengthList.cpp index b59930d9bdd6..f5b46c46e0a6 100644 --- a/content/svg/content/src/DOMSVGLengthList.cpp +++ b/content/svg/content/src/DOMSVGLengthList.cpp @@ -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(); } diff --git a/content/svg/content/src/DOMSVGNumber.cpp b/content/svg/content/src/DOMSVGNumber.cpp index 2648f32b1d4b..a9f815964a2f 100644 --- a/content/svg/content/src/DOMSVGNumber.cpp +++ b/content/svg/content/src/DOMSVGNumber.cpp @@ -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(); } diff --git a/content/svg/content/src/DOMSVGNumberList.cpp b/content/svg/content/src/DOMSVGNumberList.cpp index 6e9d8b804584..1f458180f52f 100644 --- a/content/svg/content/src/DOMSVGNumberList.cpp +++ b/content/svg/content/src/DOMSVGNumberList.cpp @@ -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(); } diff --git a/content/svg/content/src/DOMSVGPathSeg.cpp b/content/svg/content/src/DOMSVGPathSeg.cpp index 53c5680923ff..36c90033217e 100644 --- a/content/svg/content/src/DOMSVGPathSeg.cpp +++ b/content/svg/content/src/DOMSVGPathSeg.cpp @@ -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(); \ } \ diff --git a/content/svg/content/src/DOMSVGPathSegList.cpp b/content/svg/content/src/DOMSVGPathSegList.cpp index ff0c9ad645dc..b2ae7ab3ecb7 100644 --- a/content/svg/content/src/DOMSVGPathSegList.cpp +++ b/content/svg/content/src/DOMSVGPathSegList.cpp @@ -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(); } diff --git a/content/svg/content/src/DOMSVGPoint.cpp b/content/svg/content/src/DOMSVGPoint.cpp index ba3d6ef946b9..dbe96022c94b 100644 --- a/content/svg/content/src/DOMSVGPoint.cpp +++ b/content/svg/content/src/DOMSVGPoint.cpp @@ -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(); } diff --git a/content/svg/content/src/DOMSVGPointList.cpp b/content/svg/content/src/DOMSVGPointList.cpp index 18baadb595c3..aa660fe41876 100644 --- a/content/svg/content/src/DOMSVGPointList.cpp +++ b/content/svg/content/src/DOMSVGPointList.cpp @@ -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(); } diff --git a/content/svg/content/src/DOMSVGStringList.cpp b/content/svg/content/src/DOMSVGStringList.cpp index 8fd2a53d605c..7f0966b1b55a 100644 --- a/content/svg/content/src/DOMSVGStringList.cpp +++ b/content/svg/content/src/DOMSVGStringList.cpp @@ -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; } diff --git a/content/svg/content/src/DOMSVGStringList.h b/content/svg/content/src/DOMSVGStringList.h index 6bb74f3c5625..1437687db758 100644 --- a/content/svg/content/src/DOMSVGStringList.h +++ b/content/svg/content/src/DOMSVGStringList.h @@ -111,8 +111,6 @@ private: ~DOMSVGStringList(); - void DidChangeStringList(PRUint8 aAttrEnum, bool aDoSetAttr); - SVGStringList &InternalList(); // Strong ref to our element to keep it alive. diff --git a/content/svg/content/src/DOMSVGTests.cpp b/content/svg/content/src/DOMSVGTests.cpp index cdfa3585214b..77e4bdcddafa 100644 --- a/content/svg/content/src/DOMSVGTests.cpp +++ b/content/svg/content/src/DOMSVGTests.cpp @@ -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(); diff --git a/content/svg/content/src/DOMSVGTests.h b/content/svg/content/src/DOMSVGTests.h index f1332a8ac226..7fc3cb232c32 100644 --- a/content/svg/content/src/DOMSVGTests.h +++ b/content/svg/content/src/DOMSVGTests.h @@ -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__ diff --git a/content/svg/content/src/DOMSVGTransform.cpp b/content/svg/content/src/DOMSVGTransform.cpp index 94d36007c250..8f8956464c36 100644 --- a/content/svg/content/src/DOMSVGTransform.cpp +++ b/content/svg/content/src/DOMSVGTransform.cpp @@ -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(); } diff --git a/content/svg/content/src/DOMSVGTransform.h b/content/svg/content/src/DOMSVGTransform.h index 58654e0b213b..7f1f6ec6fa82 100644 --- a/content/svg/content/src/DOMSVGTransform.h +++ b/content/svg/content/src/DOMSVGTransform.h @@ -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 diff --git a/content/svg/content/src/DOMSVGTransformList.cpp b/content/svg/content/src/DOMSVGTransformList.cpp index 6484e15b5c5f..c8c89f18c020 100644 --- a/content/svg/content/src/DOMSVGTransformList.cpp +++ b/content/svg/content/src/DOMSVGTransformList.cpp @@ -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(); } diff --git a/content/svg/content/src/Makefile.in b/content/svg/content/src/Makefile.in index f27cb4d45170..601a5e30d1c6 100644 --- a/content/svg/content/src/Makefile.in +++ b/content/svg/content/src/Makefile.in @@ -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 diff --git a/content/svg/content/src/SVGAnimatedPreserveAspectRatio.cpp b/content/svg/content/src/SVGAnimatedPreserveAspectRatio.cpp index 9905e3a4831b..429de200e136 100644 --- a/content/svg/content/src/SVGAnimatedPreserveAspectRatio.cpp +++ b/content/svg/content/src/SVGAnimatedPreserveAspectRatio.cpp @@ -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(); } diff --git a/content/svg/content/src/SVGAnimatedPreserveAspectRatio.h b/content/svg/content/src/SVGAnimatedPreserveAspectRatio.h index b8c353481d0a..5b2e8396aef2 100644 --- a/content/svg/content/src/SVGAnimatedPreserveAspectRatio.h +++ b/content/svg/content/src/SVGAnimatedPreserveAspectRatio.h @@ -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); diff --git a/content/svg/content/src/SVGAttrValueWrapper.cpp b/content/svg/content/src/SVGAttrValueWrapper.cpp new file mode 100644 index 000000000000..af3f5455c1c6 --- /dev/null +++ b/content/svg/content/src/SVGAttrValueWrapper.cpp @@ -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); +} diff --git a/content/svg/content/src/SVGAttrValueWrapper.h b/content/svg/content/src/SVGAttrValueWrapper.h new file mode 100644 index 000000000000..b0419d570999 --- /dev/null +++ b/content/svg/content/src/SVGAttrValueWrapper.h @@ -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__ diff --git a/content/svg/content/src/SVGStringList.cpp b/content/svg/content/src/SVGStringList.cpp index 6cb8a69fd1b2..a8a608135da1 100644 --- a/content/svg/content/src/SVGStringList.cpp +++ b/content/svg/content/src/SVGStringList.cpp @@ -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, ','); diff --git a/content/svg/content/src/SVGStringList.h b/content/svg/content/src/SVGStringList.h index 4548564c95da..5452d944f8d3 100644 --- a/content/svg/content/src/SVGStringList.h +++ b/content/svg/content/src/SVGStringList.h @@ -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 diff --git a/content/svg/content/src/SVGTransform.h b/content/svg/content/src/SVGTransform.h index b4d661e9e91a..51bf7c660347 100644 --- a/content/svg/content/src/SVGTransform.h +++ b/content/svg/content/src/SVGTransform.h @@ -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; diff --git a/content/svg/content/src/nsSVGAngle.cpp b/content/svg/content/src/nsSVGAngle.cpp index 087d00f2ee85..689799708365 100644 --- a/content/svg/content/src/nsSVGAngle.cpp +++ b/content/svg/content/src/nsSVGAngle.cpp @@ -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); } } diff --git a/content/svg/content/src/nsSVGAngle.h b/content/svg/content/src/nsSVGAngle.h index ff518f1834c5..10ab5d3e7b05 100644 --- a/content/svg/content/src/nsSVGAngle.h +++ b/content/svg/content/src/nsSVGAngle.h @@ -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; } diff --git a/content/svg/content/src/nsSVGBoolean.cpp b/content/svg/content/src/nsSVGBoolean.cpp index 2b7db25d2215..c31fca96e4df 100644 --- a/content/svg/content/src/nsSVGBoolean.cpp +++ b/content/svg/content/src/nsSVGBoolean.cpp @@ -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 diff --git a/content/svg/content/src/nsSVGBoolean.h b/content/svg/content/src/nsSVGBoolean.h index 4ca77411d0aa..f649c37ce478 100644 --- a/content/svg/content/src/nsSVGBoolean.h +++ b/content/svg/content/src/nsSVGBoolean.h @@ -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 diff --git a/content/svg/content/src/nsSVGElement.cpp b/content/svg/content/src/nsSVGElement.cpp index 61c693aa4dd9..1b8d052dc594 100644 --- a/content/svg/content/src/nsSVGElement.cpp +++ b/content/svg/content/src/nsSVGElement.cpp @@ -89,6 +89,7 @@ #include <stdarg.h> #include "nsSMILMappedAttribute.h" #include "SVGMotionSMILAttr.h" +#include "nsAttrValueOrString.h" using namespace mozilla; @@ -262,6 +263,15 @@ nsresult nsSVGElement::AfterSetAttr(PRInt32 aNamespaceID, nsIAtom* aName, const nsAttrValue* aValue, bool aNotify) { + // We don't currently use nsMappedAttributes within SVG. If this changes, we + // need to be very careful because some nsAttrValues used by SVG point to + // member data of SVG elements and if an nsAttrValue outlives the SVG element + // whose data it points to (by virtue of being stored in + // mAttrsAndChildren->mMappedAttributes, meaning it's shared between + // elements), the pointer will dangle. See bug 724680. + NS_ABORT_IF_FALSE(!mAttrsAndChildren.HasMappedAttrs(), + "Unexpected use of nsMappedAttributes within SVG"); + // If this is an svg presentation attribute we need to map it into // the content stylerule. // XXX For some reason incremental mapping doesn't work, so for now @@ -290,6 +300,8 @@ nsSVGElement::ParseAttribute(PRInt32 aNamespaceID, { nsresult rv = NS_OK; bool foundMatch = false; + bool didSetResult = false; + if (aNamespaceID == kNameSpaceID_None) { // Check for nsSVGLength2 attribute @@ -301,6 +313,9 @@ nsSVGElement::ParseAttribute(PRInt32 aNamespaceID, rv = lengthInfo.mLengths[i].SetBaseValueString(aValue, this, false); if (NS_FAILED(rv)) { lengthInfo.Reset(i); + } else { + aResult.SetTo(lengthInfo.mLengths[i], &aValue); + didSetResult = true; } foundMatch = true; break; @@ -315,6 +330,10 @@ nsSVGElement::ParseAttribute(PRInt32 aNamespaceID, rv = lengthListInfo.mLengthLists[i].SetBaseValueString(aValue); if (NS_FAILED(rv)) { lengthListInfo.Reset(i); + } else { + aResult.SetTo(lengthListInfo.mLengthLists[i].GetBaseValue(), + &aValue); + didSetResult = true; } foundMatch = true; break; @@ -330,6 +349,10 @@ nsSVGElement::ParseAttribute(PRInt32 aNamespaceID, rv = numberListInfo.mNumberLists[i].SetBaseValueString(aValue); if (NS_FAILED(rv)) { numberListInfo.Reset(i); + } else { + aResult.SetTo(numberListInfo.mNumberLists[i].GetBaseValue(), + &aValue); + didSetResult = true; } foundMatch = true; break; @@ -342,11 +365,12 @@ nsSVGElement::ParseAttribute(PRInt32 aNamespaceID, if (GetPointListAttrName() == aAttribute) { SVGAnimatedPointList* pointList = GetAnimatedPointList(); if (pointList) { - rv = pointList->SetBaseValueString(aValue); - if (NS_FAILED(rv)) { - // The spec says we parse everything up to the failure, so we don't - // call pointList->ClearBaseValue() - } + pointList->SetBaseValueString(aValue); + // The spec says we parse everything up to the failure, so we DON'T + // need to check the result of SetBaseValueString or call + // pointList->ClearBaseValue() if it fails + aResult.SetTo(pointList->GetBaseValue(), &aValue); + didSetResult = true; foundMatch = true; } } @@ -357,11 +381,12 @@ nsSVGElement::ParseAttribute(PRInt32 aNamespaceID, if (GetPathDataAttrName() == aAttribute) { SVGAnimatedPathSegList* segList = GetAnimPathSegList(); if (segList) { - rv = segList->SetBaseValueString(aValue); - if (NS_FAILED(rv)) { - // The spec says we parse everything up to the failure, so we don't - // call segList->ClearBaseValue() - } + segList->SetBaseValueString(aValue); + // The spec says we parse everything up to the failure, so we DON'T + // need to check the result of SetBaseValueString or call + // segList->ClearBaseValue() if it fails + aResult.SetTo(segList->GetBaseValue(), &aValue); + didSetResult = true; foundMatch = true; } } @@ -375,6 +400,9 @@ nsSVGElement::ParseAttribute(PRInt32 aNamespaceID, rv = numberInfo.mNumbers[i].SetBaseValueString(aValue, this); if (NS_FAILED(rv)) { numberInfo.Reset(i); + } else { + aResult.SetTo(numberInfo.mNumbers[i].GetBaseValue(), &aValue); + didSetResult = true; } foundMatch = true; break; @@ -390,6 +418,9 @@ nsSVGElement::ParseAttribute(PRInt32 aNamespaceID, rv = numberPairInfo.mNumberPairs[i].SetBaseValueString(aValue, this); if (NS_FAILED(rv)) { numberPairInfo.Reset(i); + } else { + aResult.SetTo(numberPairInfo.mNumberPairs[i], &aValue); + didSetResult = true; } foundMatch = true; break; @@ -405,6 +436,9 @@ nsSVGElement::ParseAttribute(PRInt32 aNamespaceID, rv = integerInfo.mIntegers[i].SetBaseValueString(aValue, this); if (NS_FAILED(rv)) { integerInfo.Reset(i); + } else { + aResult.SetTo(integerInfo.mIntegers[i].GetBaseValue(), &aValue); + didSetResult = true; } foundMatch = true; break; @@ -417,9 +451,13 @@ nsSVGElement::ParseAttribute(PRInt32 aNamespaceID, IntegerPairAttributesInfo integerPairInfo = GetIntegerPairInfo(); for (i = 0; i < integerPairInfo.mIntegerPairCount; i++) { if (aAttribute == *integerPairInfo.mIntegerPairInfo[i].mName) { - rv = integerPairInfo.mIntegerPairs[i].SetBaseValueString(aValue, this); + rv = + integerPairInfo.mIntegerPairs[i].SetBaseValueString(aValue, this); if (NS_FAILED(rv)) { integerPairInfo.Reset(i); + } else { + aResult.SetTo(integerPairInfo.mIntegerPairs[i], &aValue); + didSetResult = true; } foundMatch = true; break; @@ -435,6 +473,9 @@ nsSVGElement::ParseAttribute(PRInt32 aNamespaceID, rv = angleInfo.mAngles[i].SetBaseValueString(aValue, this, false); if (NS_FAILED(rv)) { angleInfo.Reset(i); + } else { + aResult.SetTo(angleInfo.mAngles[i], &aValue); + didSetResult = true; } foundMatch = true; break; @@ -447,9 +488,13 @@ nsSVGElement::ParseAttribute(PRInt32 aNamespaceID, BooleanAttributesInfo booleanInfo = GetBooleanInfo(); for (i = 0; i < booleanInfo.mBooleanCount; i++) { if (aAttribute == *booleanInfo.mBooleanInfo[i].mName) { - rv = booleanInfo.mBooleans[i].SetBaseValueString(aValue, this); + nsCOMPtr<nsIAtom> valAtom = do_GetAtom(aValue); + rv = booleanInfo.mBooleans[i].SetBaseValueAtom(valAtom, this); if (NS_FAILED(rv)) { booleanInfo.Reset(i); + } else { + aResult.SetTo(valAtom); + didSetResult = true; } foundMatch = true; break; @@ -462,9 +507,13 @@ nsSVGElement::ParseAttribute(PRInt32 aNamespaceID, EnumAttributesInfo enumInfo = GetEnumInfo(); for (i = 0; i < enumInfo.mEnumCount; i++) { if (aAttribute == *enumInfo.mEnumInfo[i].mName) { - rv = enumInfo.mEnums[i].SetBaseValueString(aValue, this); + nsCOMPtr<nsIAtom> valAtom = do_GetAtom(aValue); + rv = enumInfo.mEnums[i].SetBaseValueAtom(valAtom, this); if (NS_FAILED(rv)) { enumInfo.Reset(i); + } else { + aResult.SetTo(valAtom); + didSetResult = true; } foundMatch = true; break; @@ -486,9 +535,12 @@ nsSVGElement::ParseAttribute(PRInt32 aNamespaceID, StringListAttributesInfo stringListInfo = GetStringListInfo(); for (i = 0; i < stringListInfo.mStringListCount; i++) { if (aAttribute == *stringListInfo.mStringListInfo[i].mName) { - rv = stringListInfo.mStringLists[i].SetValue(aValue, false); + rv = stringListInfo.mStringLists[i].SetValue(aValue); if (NS_FAILED(rv)) { stringListInfo.Reset(i); + } else { + aResult.SetTo(stringListInfo.mStringLists[i], &aValue); + didSetResult = true; } foundMatch = true; break; @@ -504,6 +556,9 @@ nsSVGElement::ParseAttribute(PRInt32 aNamespaceID, rv = viewBox->SetBaseValueString(aValue, this); if (NS_FAILED(rv)) { viewBox->Init(); + } else { + aResult.SetTo(*viewBox, &aValue); + didSetResult = true; } foundMatch = true; } @@ -515,6 +570,9 @@ nsSVGElement::ParseAttribute(PRInt32 aNamespaceID, rv = preserveAspectRatio->SetBaseValueString(aValue, this); if (NS_FAILED(rv)) { preserveAspectRatio->Init(); + } else { + aResult.SetTo(*preserveAspectRatio, &aValue); + didSetResult = true; } foundMatch = true; } @@ -525,6 +583,9 @@ nsSVGElement::ParseAttribute(PRInt32 aNamespaceID, rv = transformList->SetBaseValueString(aValue); if (NS_FAILED(rv)) { transformList->ClearBaseValue(); + } else { + aResult.SetTo(transformList->GetBaseValue(), &aValue); + didSetResult = true; } foundMatch = true; } @@ -550,7 +611,9 @@ nsSVGElement::ParseAttribute(PRInt32 aNamespaceID, ReportAttributeParseFailure(OwnerDoc(), aAttribute, aValue); return false; } - aResult.SetTo(aValue); + if (!didSetResult) { + aResult.SetTo(aValue); + } return true; } @@ -584,8 +647,8 @@ nsSVGElement::UnsetAttrInternal(PRInt32 aNamespaceID, nsIAtom* aName, for (PRUint32 i = 0; i < lenInfo.mLengthCount; i++) { if (aName == *lenInfo.mLengthInfo[i].mName) { + MaybeSerializeAttrBeforeRemoval(aName, aNotify); lenInfo.Reset(i); - DidChangeLength(i, false); return; } } @@ -595,8 +658,8 @@ nsSVGElement::UnsetAttrInternal(PRInt32 aNamespaceID, nsIAtom* aName, for (PRUint32 i = 0; i < lengthListInfo.mLengthListCount; i++) { if (aName == *lengthListInfo.mLengthListInfo[i].mName) { + MaybeSerializeAttrBeforeRemoval(aName, aNotify); lengthListInfo.Reset(i); - DidChangeLengthList(i, false); return; } } @@ -606,8 +669,8 @@ nsSVGElement::UnsetAttrInternal(PRInt32 aNamespaceID, nsIAtom* aName, for (PRUint32 i = 0; i < numberListInfo.mNumberListCount; i++) { if (aName == *numberListInfo.mNumberListInfo[i].mName) { + MaybeSerializeAttrBeforeRemoval(aName, aNotify); numberListInfo.Reset(i); - DidChangeNumberList(i, false); return; } } @@ -616,6 +679,7 @@ nsSVGElement::UnsetAttrInternal(PRInt32 aNamespaceID, nsIAtom* aName, if (GetPointListAttrName() == aName) { SVGAnimatedPointList *pointList = GetAnimatedPointList(); if (pointList) { + MaybeSerializeAttrBeforeRemoval(aName, aNotify); pointList->ClearBaseValue(); return; } @@ -625,8 +689,8 @@ nsSVGElement::UnsetAttrInternal(PRInt32 aNamespaceID, nsIAtom* aName, if (GetPathDataAttrName() == aName) { SVGAnimatedPathSegList *segList = GetAnimPathSegList(); if (segList) { + MaybeSerializeAttrBeforeRemoval(aName, aNotify); segList->ClearBaseValue(); - DidChangePathSegList(false); return; } } @@ -637,7 +701,6 @@ nsSVGElement::UnsetAttrInternal(PRInt32 aNamespaceID, nsIAtom* aName, for (PRUint32 i = 0; i < numInfo.mNumberCount; i++) { if (aName == *numInfo.mNumberInfo[i].mName) { numInfo.Reset(i); - DidChangeNumber(i, false); return; } } @@ -647,8 +710,8 @@ nsSVGElement::UnsetAttrInternal(PRInt32 aNamespaceID, nsIAtom* aName, for (PRUint32 i = 0; i < numPairInfo.mNumberPairCount; i++) { if (aName == *numPairInfo.mNumberPairInfo[i].mName) { + MaybeSerializeAttrBeforeRemoval(aName, aNotify); numPairInfo.Reset(i); - DidChangeNumberPair(i, false); return; } } @@ -659,7 +722,6 @@ nsSVGElement::UnsetAttrInternal(PRInt32 aNamespaceID, nsIAtom* aName, for (PRUint32 i = 0; i < intInfo.mIntegerCount; i++) { if (aName == *intInfo.mIntegerInfo[i].mName) { intInfo.Reset(i); - DidChangeInteger(i, false); return; } } @@ -669,8 +731,8 @@ nsSVGElement::UnsetAttrInternal(PRInt32 aNamespaceID, nsIAtom* aName, for (PRUint32 i = 0; i < intPairInfo.mIntegerPairCount; i++) { if (aName == *intPairInfo.mIntegerPairInfo[i].mName) { + MaybeSerializeAttrBeforeRemoval(aName, aNotify); intPairInfo.Reset(i); - DidChangeIntegerPair(i, false); return; } } @@ -680,8 +742,8 @@ nsSVGElement::UnsetAttrInternal(PRInt32 aNamespaceID, nsIAtom* aName, for (PRUint32 i = 0; i < angleInfo.mAngleCount; i++) { if (aName == *angleInfo.mAngleInfo[i].mName) { + MaybeSerializeAttrBeforeRemoval(aName, aNotify); angleInfo.Reset(i); - DidChangeAngle(i, false); return; } } @@ -692,7 +754,6 @@ nsSVGElement::UnsetAttrInternal(PRInt32 aNamespaceID, nsIAtom* aName, for (PRUint32 i = 0; i < boolInfo.mBooleanCount; i++) { if (aName == *boolInfo.mBooleanInfo[i].mName) { boolInfo.Reset(i); - DidChangeBoolean(i, false); return; } } @@ -703,7 +764,6 @@ nsSVGElement::UnsetAttrInternal(PRInt32 aNamespaceID, nsIAtom* aName, for (PRUint32 i = 0; i < enumInfo.mEnumCount; i++) { if (aName == *enumInfo.mEnumInfo[i].mName) { enumInfo.Reset(i); - DidChangeEnum(i, false); return; } } @@ -712,8 +772,8 @@ nsSVGElement::UnsetAttrInternal(PRInt32 aNamespaceID, nsIAtom* aName, if (aName == nsGkAtoms::viewBox) { nsSVGViewBox* viewBox = GetViewBox(); if (viewBox) { + MaybeSerializeAttrBeforeRemoval(aName, aNotify); viewBox->Init(); - DidChangeViewBox(false); return; } } @@ -722,10 +782,9 @@ nsSVGElement::UnsetAttrInternal(PRInt32 aNamespaceID, nsIAtom* aName, if (aName == nsGkAtoms::preserveAspectRatio) { SVGAnimatedPreserveAspectRatio *preserveAspectRatio = GetPreserveAspectRatio(); - if (preserveAspectRatio) { + MaybeSerializeAttrBeforeRemoval(aName, aNotify); preserveAspectRatio->Init(); - DidChangePreserveAspectRatio(false); return; } } @@ -734,8 +793,8 @@ nsSVGElement::UnsetAttrInternal(PRInt32 aNamespaceID, nsIAtom* aName, if (GetTransformListAttrName() == aName) { SVGAnimatedTransformList *transformList = GetAnimatedTransformList(); if (transformList) { + MaybeSerializeAttrBeforeRemoval(aName, aNotify); transformList->ClearBaseValue(); - DidChangeTransformList(false); return; } } @@ -743,6 +802,7 @@ nsSVGElement::UnsetAttrInternal(PRInt32 aNamespaceID, nsIAtom* aName, // Check for conditional processing attributes nsCOMPtr<DOMSVGTests> tests(do_QueryInterface(this)); if (tests && tests->IsConditionalProcessingAttribute(aName)) { + MaybeSerializeAttrBeforeRemoval(aName, aNotify); tests->UnsetAttr(aName); return; } @@ -752,6 +812,7 @@ nsSVGElement::UnsetAttrInternal(PRInt32 aNamespaceID, nsIAtom* aName, for (PRUint32 i = 0; i < stringListInfo.mStringListCount; i++) { if (aName == *stringListInfo.mStringListInfo[i].mName) { + MaybeSerializeAttrBeforeRemoval(aName, aNotify); stringListInfo.Reset(i); return; } @@ -765,7 +826,6 @@ nsSVGElement::UnsetAttrInternal(PRInt32 aNamespaceID, nsIAtom* aName, if (aNamespaceID == stringInfo.mStringInfo[i].mNamespaceID && aName == *stringInfo.mStringInfo[i].mName) { stringInfo.Reset(i); - DidChangeString(i); return; } } @@ -1247,6 +1307,137 @@ nsSVGElement::GetAnimatedContentStyleRule() nsnull)); } +/** + * Helper methods for the type-specific WillChangeXXX methods. + * + * This method sends out appropriate pre-change notifications so that selector + * restyles (e.g. due to changes that cause |elem[attr="val"]| to start/stop + * matching) work, and it returns an nsAttrValue that _may_ contain the + * attribute's pre-change value. + * + * The nsAttrValue returned by this method depends on whether there are + * mutation event listeners listening for changes to this element's attributes. + * If not, then the object returned is empty. If there are, then the + * nsAttrValue returned contains a serialized copy of the attribute's value + * prior to the change, and this object should be passed to the corresponding + * DidChangeXXX method call (assuming a WillChangeXXX call is required for the + * SVG type - see comment below). This is necessary so that the 'prevValue' + * property of the mutation event that is dispatched will correctly contain the + * old value. + * + * The reason we need to serialize the old value if there are mutation + * event listeners is because the underlying nsAttrValue for the attribute + * points directly to a parsed representation of the attribute (e.g. an + * SVGAnimatedLengthList*) that is a member of the SVG element. That object + * will have changed by the time DidChangeXXX has been called, so without the + * serialization of the old attribute value that we provide, DidChangeXXX + * would have no way to get the old value to pass to SetAttrAndNotify. + * + * We only return the old value when there are mutation event listeners because + * it's not needed otherwise, and because it's expensive to serialize the old + * value. This is especially true for list type attributes, which may be built + * up via the SVG DOM resulting in a large number of Will/DidModifyXXX calls + * before the script finally finishes setting the attribute. + * + * Note that unlike using SetParsedAttr, using Will/DidChangeXXX does NOT check + * and filter out redundant changes. Before calling WillChangeXXX, the caller + * should check whether the new and old values are actually the same, and skip + * calling Will/DidChangeXXX if they are. + * + * Also note that not all SVG types use this scheme. For types that can be + * represented by an nsAttrValue without pointing back to an SVG object (e.g. + * enums, booleans, integers) we can simply use SetParsedAttr which will do all + * of the above for us. For such types there is no matching WillChangeXXX + * method, only DidChangeXXX which calls SetParsedAttr. + */ +nsAttrValue +nsSVGElement::WillChangeValue(nsIAtom* aName) +{ + // We need an empty attr value: + // a) to pass to BeforeSetAttr when GetParsedAttr returns nsnull + // b) to store the old value in the case we have mutation listeners + // We can use the same value for both purposes since (a) happens before (b). + // Also, we should be careful to always return this value to benefit from + // return value optimization. + nsAttrValue emptyOrOldAttrValue; + const nsAttrValue* attrValue = GetParsedAttr(aName); + + // This is not strictly correct--the attribute value parameter for + // BeforeSetAttr should reflect the value that *will* be set but that implies + // allocating, e.g. an extra nsSVGLength2, and isn't necessary at the moment + // since no SVG elements overload BeforeSetAttr. For now we just pass the + // current value. + nsAttrValueOrString attrStringOrValue(attrValue ? *attrValue + : emptyOrOldAttrValue); + DebugOnly<nsresult> rv = + BeforeSetAttr(kNameSpaceID_None, aName, &attrStringOrValue, + kNotifyDocumentObservers); + // SVG elements aren't expected to overload BeforeSetAttr in such a way that + // it may fail. So long as this is the case we don't need to check and pass on + // the return value which simplifies the calling code significantly. + NS_ABORT_IF_FALSE(NS_SUCCEEDED(rv), "Unexpected failure from BeforeSetAttr"); + + // We only need to set the old value if we have listeners since otherwise it + // isn't used. + if (attrValue && + nsContentUtils::HasMutationListeners(this, + NS_EVENT_BITS_MUTATION_ATTRMODIFIED, + this)) { + emptyOrOldAttrValue.SetToSerialized(*attrValue); + } + + PRUint8 modType = attrValue + ? static_cast<PRUint8>(nsIDOMMutationEvent::MODIFICATION) + : static_cast<PRUint8>(nsIDOMMutationEvent::ADDITION); + nsNodeUtils::AttributeWillChange(this, kNameSpaceID_None, aName, modType); + + return emptyOrOldAttrValue; +} + +/** + * Helper methods for the type-specific DidChangeXXX methods. + * + * aEmptyOrOldValue will normally be the object returned from the corresponding + * WillChangeXXX call. This is because: + * a) WillChangeXXX will ensure the object is set when we have mutation + * listeners, and + * b) WillChangeXXX will ensure the object represents a serialized version of + * the old attribute value so that the value doesn't change when the + * underlying SVG type is updated. + */ +void +nsSVGElement::DidChangeValue(nsIAtom* aName, + const nsAttrValue& aEmptyOrOldValue, + nsAttrValue& aNewValue) +{ + bool hasListeners = + nsContentUtils::HasMutationListeners(this, + NS_EVENT_BITS_MUTATION_ATTRMODIFIED, + this); + PRUint8 modType = HasAttr(kNameSpaceID_None, aName) + ? static_cast<PRUint8>(nsIDOMMutationEvent::MODIFICATION) + : static_cast<PRUint8>(nsIDOMMutationEvent::ADDITION); + SetAttrAndNotify(kNameSpaceID_None, aName, nsnull, aEmptyOrOldValue, + aNewValue, modType, hasListeners, kNotifyDocumentObservers, + kCallAfterSetAttr); +} + +void +nsSVGElement::MaybeSerializeAttrBeforeRemoval(nsIAtom* aName, bool aNotify) +{ + if (!aNotify || + !nsContentUtils::HasMutationListeners(this, + NS_EVENT_BITS_MUTATION_ATTRMODIFIED, + this)) { + return; + } + + nsAutoString serializedValue; + mAttrsAndChildren.GetAttr(aName)->ToString(serializedValue); + nsAttrValue attrValue(serializedValue); + mAttrsAndChildren.SetAndTakeAttr(aName, attrValue); +} + /* static */ nsIAtom* nsSVGElement::GetEventNameForAttr(nsIAtom* aAttr) { @@ -1329,25 +1520,27 @@ nsSVGElement::SetLength(nsIAtom* aName, const nsSVGLength2 &aLength) NS_ABORT_IF_FALSE(false, "no length found to set"); } -void -nsSVGElement::DidChangeLength(PRUint8 aAttrEnum, bool aDoSetAttr) +nsAttrValue +nsSVGElement::WillChangeLength(PRUint8 aAttrEnum) { - if (!aDoSetAttr) - return; + return WillChangeValue(*GetLengthInfo().mLengthInfo[aAttrEnum].mName); +} +void +nsSVGElement::DidChangeLength(PRUint8 aAttrEnum, + const nsAttrValue& aEmptyOrOldValue) +{ LengthAttributesInfo info = GetLengthInfo(); NS_ASSERTION(info.mLengthCount > 0, "DidChangeLength on element with no length attribs"); - NS_ASSERTION(aAttrEnum < info.mLengthCount, "aAttrEnum out of range"); - nsAutoString serializedValue; - info.mLengths[aAttrEnum].GetBaseValueString(serializedValue); + nsAttrValue newValue; + newValue.SetTo(info.mLengths[aAttrEnum], nsnull); - nsAttrValue attrValue(serializedValue); - SetParsedAttr(kNameSpaceID_None, *info.mLengthInfo[aAttrEnum].mName, nsnull, - attrValue, true); + DidChangeValue(*info.mLengthInfo[aAttrEnum].mName, aEmptyOrOldValue, + newValue); } void @@ -1424,24 +1617,27 @@ nsSVGElement::LengthListAttributesInfo::Reset(PRUint8 aAttrEnum) // caller notifies } -void -nsSVGElement::DidChangeLengthList(PRUint8 aAttrEnum, bool aDoSetAttr) +nsAttrValue +nsSVGElement::WillChangeLengthList(PRUint8 aAttrEnum) { - if (!aDoSetAttr) - return; + return WillChangeValue(*GetLengthListInfo().mLengthListInfo[aAttrEnum].mName); +} +void +nsSVGElement::DidChangeLengthList(PRUint8 aAttrEnum, + const nsAttrValue& aEmptyOrOldValue) +{ LengthListAttributesInfo info = GetLengthListInfo(); NS_ASSERTION(info.mLengthListCount > 0, "DidChangeLengthList on element with no length list attribs"); NS_ASSERTION(aAttrEnum < info.mLengthListCount, "aAttrEnum out of range"); - nsAutoString serializedValue; - info.mLengthLists[aAttrEnum].GetBaseValue().GetValueAsString(serializedValue); + nsAttrValue newValue; + newValue.SetTo(info.mLengthLists[aAttrEnum].GetBaseValue(), nsnull); - nsAttrValue attrValue(serializedValue); - SetParsedAttr(kNameSpaceID_None, *info.mLengthListInfo[aAttrEnum].mName, - nsnull, attrValue, true); + DidChangeValue(*info.mLengthListInfo[aAttrEnum].mName, aEmptyOrOldValue, + newValue); } void @@ -1506,24 +1702,28 @@ nsSVGElement::NumberListAttributesInfo::Reset(PRUint8 aAttrEnum) // caller notifies } -void -nsSVGElement::DidChangeNumberList(PRUint8 aAttrEnum, bool aDoSetAttr) +nsAttrValue +nsSVGElement::WillChangeNumberList(PRUint8 aAttrEnum) { - if (!aDoSetAttr) - return; + return WillChangeValue(*GetNumberListInfo().mNumberListInfo[aAttrEnum].mName); +} +void +nsSVGElement::DidChangeNumberList(PRUint8 aAttrEnum, + const nsAttrValue& aEmptyOrOldValue) +{ NumberListAttributesInfo info = GetNumberListInfo(); NS_ABORT_IF_FALSE(info.mNumberListCount > 0, - "DidChangeNumberList on element with no number list attribs"); - NS_ABORT_IF_FALSE(aAttrEnum < info.mNumberListCount, "aAttrEnum out of range"); + "DidChangeNumberList on element with no number list attribs"); + NS_ABORT_IF_FALSE(aAttrEnum < info.mNumberListCount, + "aAttrEnum out of range"); - nsAutoString serializedValue; - info.mNumberLists[aAttrEnum].GetBaseValue().GetValueAsString(serializedValue); + nsAttrValue newValue; + newValue.SetTo(info.mNumberLists[aAttrEnum].GetBaseValue(), nsnull); - nsAttrValue attrValue(serializedValue); - SetParsedAttr(kNameSpaceID_None, *info.mNumberListInfo[aAttrEnum].mName, - nsnull, attrValue, true); + DidChangeValue(*info.mNumberListInfo[aAttrEnum].mName, aEmptyOrOldValue, + newValue); } void @@ -1565,20 +1765,24 @@ nsSVGElement::GetAnimatedNumberList(nsIAtom *aAttrName) return nsnull; } -void -nsSVGElement::DidChangePointList(bool aDoSetAttr) +nsAttrValue +nsSVGElement::WillChangePointList() { - NS_ABORT_IF_FALSE(GetPointListAttrName(), "Changing non-existent point list?"); + NS_ABORT_IF_FALSE(GetPointListAttrName(), + "Changing non-existent point list?"); + return WillChangeValue(GetPointListAttrName()); +} - if (!aDoSetAttr) - return; +void +nsSVGElement::DidChangePointList(const nsAttrValue& aEmptyOrOldValue) +{ + NS_ABORT_IF_FALSE(GetPointListAttrName(), + "Changing non-existent point list?"); - nsAutoString serializedValue; - GetAnimatedPointList()->GetBaseValue().GetValueAsString(serializedValue); + nsAttrValue newValue; + newValue.SetTo(GetAnimatedPointList()->GetBaseValue(), nsnull); - nsAttrValue attrValue(serializedValue); - SetParsedAttr(kNameSpaceID_None, GetPointListAttrName(), nsnull, - attrValue, true); + DidChangeValue(GetPointListAttrName(), aEmptyOrOldValue, newValue); } void @@ -1596,18 +1800,24 @@ nsSVGElement::DidAnimatePointList() } } -void -nsSVGElement::DidChangePathSegList(bool aDoSetAttr) +nsAttrValue +nsSVGElement::WillChangePathSegList() { - if (!aDoSetAttr) - return; + NS_ABORT_IF_FALSE(GetPathDataAttrName(), + "Changing non-existent path seg list?"); + return WillChangeValue(GetPathDataAttrName()); +} - nsAutoString serializedValue; - GetAnimPathSegList()->GetBaseValue().GetValueAsString(serializedValue); +void +nsSVGElement::DidChangePathSegList(const nsAttrValue& aEmptyOrOldValue) +{ + NS_ABORT_IF_FALSE(GetPathDataAttrName(), + "Changing non-existent path seg list?"); - nsAttrValue attrValue(serializedValue); - SetParsedAttr(kNameSpaceID_None, GetPathDataAttrName(), nsnull, - attrValue, true); + nsAttrValue newValue; + newValue.SetTo(GetAnimPathSegList()->GetBaseValue(), nsnull); + + DidChangeValue(GetPathDataAttrName(), aEmptyOrOldValue, newValue); } void @@ -1638,22 +1848,17 @@ void nsSVGElement::NumberAttributesInfo::Reset(PRUint8 aAttrEnum) } void -nsSVGElement::DidChangeNumber(PRUint8 aAttrEnum, bool aDoSetAttr) +nsSVGElement::DidChangeNumber(PRUint8 aAttrEnum) { - if (!aDoSetAttr) - return; - NumberAttributesInfo info = GetNumberInfo(); NS_ASSERTION(info.mNumberCount > 0, "DidChangeNumber on element with no number attribs"); - NS_ASSERTION(aAttrEnum < info.mNumberCount, "aAttrEnum out of range"); - nsAutoString serializedValue; - info.mNumbers[aAttrEnum].GetBaseValueString(serializedValue); + nsAttrValue attrValue; + attrValue.SetTo(info.mNumbers[aAttrEnum].GetBaseValue(), nsnull); - nsAttrValue attrValue(serializedValue); SetParsedAttr(kNameSpaceID_None, *info.mNumberInfo[aAttrEnum].mName, nsnull, attrValue, true); } @@ -1705,25 +1910,27 @@ void nsSVGElement::NumberPairAttributesInfo::Reset(PRUint8 aAttrEnum) mNumberPairInfo[aAttrEnum].mDefaultValue2); } -void -nsSVGElement::DidChangeNumberPair(PRUint8 aAttrEnum, bool aDoSetAttr) +nsAttrValue +nsSVGElement::WillChangeNumberPair(PRUint8 aAttrEnum) { - if (!aDoSetAttr) - return; + return WillChangeValue(*GetNumberPairInfo().mNumberPairInfo[aAttrEnum].mName); +} +void +nsSVGElement::DidChangeNumberPair(PRUint8 aAttrEnum, + const nsAttrValue& aEmptyOrOldValue) +{ NumberPairAttributesInfo info = GetNumberPairInfo(); NS_ASSERTION(info.mNumberPairCount > 0, "DidChangePairNumber on element with no number pair attribs"); - NS_ASSERTION(aAttrEnum < info.mNumberPairCount, "aAttrEnum out of range"); - nsAutoString serializedValue; - info.mNumberPairs[aAttrEnum].GetBaseValueString(serializedValue); + nsAttrValue newValue; + newValue.SetTo(info.mNumberPairs[aAttrEnum], nsnull); - nsAttrValue attrValue(serializedValue); - SetParsedAttr(kNameSpaceID_None, *info.mNumberPairInfo[aAttrEnum].mName, nsnull, - attrValue, true); + DidChangeValue(*info.mNumberPairInfo[aAttrEnum].mName, aEmptyOrOldValue, + newValue); } void @@ -1752,22 +1959,17 @@ void nsSVGElement::IntegerAttributesInfo::Reset(PRUint8 aAttrEnum) } void -nsSVGElement::DidChangeInteger(PRUint8 aAttrEnum, bool aDoSetAttr) +nsSVGElement::DidChangeInteger(PRUint8 aAttrEnum) { - if (!aDoSetAttr) - return; - IntegerAttributesInfo info = GetIntegerInfo(); NS_ASSERTION(info.mIntegerCount > 0, "DidChangeInteger on element with no integer attribs"); - NS_ASSERTION(aAttrEnum < info.mIntegerCount, "aAttrEnum out of range"); - nsAutoString serializedValue; - info.mIntegers[aAttrEnum].GetBaseValueString(serializedValue); + nsAttrValue attrValue; + attrValue.SetTo(info.mIntegers[aAttrEnum].GetBaseValue(), nsnull); - nsAttrValue attrValue(serializedValue); SetParsedAttr(kNameSpaceID_None, *info.mIntegerInfo[aAttrEnum].mName, nsnull, attrValue, true); } @@ -1819,25 +2021,28 @@ void nsSVGElement::IntegerPairAttributesInfo::Reset(PRUint8 aAttrEnum) mIntegerPairInfo[aAttrEnum].mDefaultValue2); } -void -nsSVGElement::DidChangeIntegerPair(PRUint8 aAttrEnum, bool aDoSetAttr) +nsAttrValue +nsSVGElement::WillChangeIntegerPair(PRUint8 aAttrEnum) { - if (!aDoSetAttr) - return; + return WillChangeValue( + *GetIntegerPairInfo().mIntegerPairInfo[aAttrEnum].mName); +} +void +nsSVGElement::DidChangeIntegerPair(PRUint8 aAttrEnum, + const nsAttrValue& aEmptyOrOldValue) +{ IntegerPairAttributesInfo info = GetIntegerPairInfo(); NS_ASSERTION(info.mIntegerPairCount > 0, "DidChangeIntegerPair on element with no integer pair attribs"); - NS_ASSERTION(aAttrEnum < info.mIntegerPairCount, "aAttrEnum out of range"); - nsAutoString serializedValue; - info.mIntegerPairs[aAttrEnum].GetBaseValueString(serializedValue); + nsAttrValue newValue; + newValue.SetTo(info.mIntegerPairs[aAttrEnum], nsnull); - nsAttrValue attrValue(serializedValue); - SetParsedAttr(kNameSpaceID_None, *info.mIntegerPairInfo[aAttrEnum].mName, nsnull, - attrValue, true); + DidChangeValue(*info.mIntegerPairInfo[aAttrEnum].mName, aEmptyOrOldValue, + newValue); } void @@ -1866,25 +2071,26 @@ void nsSVGElement::AngleAttributesInfo::Reset(PRUint8 aAttrEnum) mAngleInfo[aAttrEnum].mDefaultUnitType); } -void -nsSVGElement::DidChangeAngle(PRUint8 aAttrEnum, bool aDoSetAttr) +nsAttrValue +nsSVGElement::WillChangeAngle(PRUint8 aAttrEnum) { - if (!aDoSetAttr) - return; + return WillChangeValue(*GetAngleInfo().mAngleInfo[aAttrEnum].mName); +} +void +nsSVGElement::DidChangeAngle(PRUint8 aAttrEnum, + const nsAttrValue& aEmptyOrOldValue) +{ AngleAttributesInfo info = GetAngleInfo(); NS_ASSERTION(info.mAngleCount > 0, "DidChangeAngle on element with no angle attribs"); - NS_ASSERTION(aAttrEnum < info.mAngleCount, "aAttrEnum out of range"); - nsAutoString serializedValue; - info.mAngles[aAttrEnum].GetBaseValueString(serializedValue); + nsAttrValue newValue; + newValue.SetTo(info.mAngles[aAttrEnum], nsnull); - nsAttrValue attrValue(serializedValue); - SetParsedAttr(kNameSpaceID_None, *info.mAngleInfo[aAttrEnum].mName, nsnull, - attrValue, true); + DidChangeValue(*info.mAngleInfo[aAttrEnum].mName, aEmptyOrOldValue, newValue); } void @@ -1913,22 +2119,15 @@ void nsSVGElement::BooleanAttributesInfo::Reset(PRUint8 aAttrEnum) } void -nsSVGElement::DidChangeBoolean(PRUint8 aAttrEnum, bool aDoSetAttr) +nsSVGElement::DidChangeBoolean(PRUint8 aAttrEnum) { - if (!aDoSetAttr) - return; - BooleanAttributesInfo info = GetBooleanInfo(); NS_ASSERTION(info.mBooleanCount > 0, "DidChangeBoolean on element with no boolean attribs"); - NS_ASSERTION(aAttrEnum < info.mBooleanCount, "aAttrEnum out of range"); - nsAutoString serializedValue; - info.mBooleans[aAttrEnum].GetBaseValueString(serializedValue); - - nsAttrValue attrValue(serializedValue); + nsAttrValue attrValue(info.mBooleans[aAttrEnum].GetBaseValueAtom()); SetParsedAttr(kNameSpaceID_None, *info.mBooleanInfo[aAttrEnum].mName, nsnull, attrValue, true); } @@ -1959,22 +2158,15 @@ void nsSVGElement::EnumAttributesInfo::Reset(PRUint8 aAttrEnum) } void -nsSVGElement::DidChangeEnum(PRUint8 aAttrEnum, bool aDoSetAttr) +nsSVGElement::DidChangeEnum(PRUint8 aAttrEnum) { - if (!aDoSetAttr) - return; - EnumAttributesInfo info = GetEnumInfo(); NS_ASSERTION(info.mEnumCount > 0, "DidChangeEnum on element with no enum attribs"); - NS_ASSERTION(aAttrEnum < info.mEnumCount, "aAttrEnum out of range"); - nsAutoString serializedValue; - info.mEnums[aAttrEnum].GetBaseValueString(serializedValue, this); - - nsAttrValue attrValue(serializedValue); + nsAttrValue attrValue(info.mEnums[aAttrEnum].GetBaseValueAtom(this)); SetParsedAttr(kNameSpaceID_None, *info.mEnumInfo[aAttrEnum].mName, nsnull, attrValue, true); } @@ -1998,22 +2190,23 @@ nsSVGElement::GetViewBox() return nsnull; } -void -nsSVGElement::DidChangeViewBox(bool aDoSetAttr) +nsAttrValue +nsSVGElement::WillChangeViewBox() { - if (!aDoSetAttr) - return; + return WillChangeValue(nsGkAtoms::viewBox); +} +void +nsSVGElement::DidChangeViewBox(const nsAttrValue& aEmptyOrOldValue) +{ nsSVGViewBox *viewBox = GetViewBox(); NS_ASSERTION(viewBox, "DidChangeViewBox on element with no viewBox attrib"); - nsAutoString serializedValue; - viewBox->GetBaseValueString(serializedValue); + nsAttrValue newValue; + newValue.SetTo(*viewBox, nsnull); - nsAttrValue attrValue(serializedValue); - SetParsedAttr(kNameSpaceID_None, nsGkAtoms::viewBox, nsnull, - attrValue, true); + DidChangeValue(nsGkAtoms::viewBox, aEmptyOrOldValue, newValue); } void @@ -2034,24 +2227,26 @@ nsSVGElement::GetPreserveAspectRatio() return nsnull; } -void -nsSVGElement::DidChangePreserveAspectRatio(bool aDoSetAttr) +nsAttrValue +nsSVGElement::WillChangePreserveAspectRatio() { - if (!aDoSetAttr) - return; + return WillChangeValue(nsGkAtoms::preserveAspectRatio); +} +void +nsSVGElement::DidChangePreserveAspectRatio(const nsAttrValue& aEmptyOrOldValue) +{ SVGAnimatedPreserveAspectRatio *preserveAspectRatio = GetPreserveAspectRatio(); NS_ASSERTION(preserveAspectRatio, - "DidChangePreserveAspectRatio on element with no preserveAspectRatio attrib"); + "DidChangePreserveAspectRatio on element with no " + "preserveAspectRatio attrib"); - nsAutoString serializedValue; - preserveAspectRatio->GetBaseValueString(serializedValue); + nsAttrValue newValue; + newValue.SetTo(*preserveAspectRatio, nsnull); - nsAttrValue attrValue(serializedValue); - SetParsedAttr(kNameSpaceID_None, nsGkAtoms::preserveAspectRatio, nsnull, - attrValue, true); + DidChangeValue(nsGkAtoms::preserveAspectRatio, aEmptyOrOldValue, newValue); } void @@ -2066,22 +2261,22 @@ nsSVGElement::DidAnimatePreserveAspectRatio() } } -void -nsSVGElement::DidChangeTransformList(bool aDoSetAttr) +nsAttrValue +nsSVGElement::WillChangeTransformList() { - if (!aDoSetAttr) - return; + return WillChangeValue(GetTransformListAttrName()); +} - SVGAnimatedTransformList* transformList = GetAnimatedTransformList(); - NS_ABORT_IF_FALSE(transformList, - "DidChangeTransformList on element with no transform list"); +void +nsSVGElement::DidChangeTransformList(const nsAttrValue& aEmptyOrOldValue) +{ + NS_ABORT_IF_FALSE(GetTransformListAttrName(), + "Changing non-existent transform list?"); - nsAutoString serializedValue; - transformList->GetBaseValue().GetValueAsString(serializedValue); + nsAttrValue newValue; + newValue.SetTo(GetAnimatedTransformList()->GetBaseValue(), nsnull); - nsAttrValue attrValue(serializedValue); - SetParsedAttr(kNameSpaceID_None, GetTransformListAttrName(), nsnull, - attrValue, true); + DidChangeValue(GetTransformListAttrName(), aEmptyOrOldValue, newValue); } void @@ -2155,29 +2350,49 @@ nsSVGElement::GetStringListInfo() return StringListAttributesInfo(nsnull, nsnull, 0); } -void -nsSVGElement::DidChangeStringList(bool aIsConditionalProcessingAttribute, - PRUint8 aAttrEnum) +nsAttrValue +nsSVGElement::WillChangeStringList(bool aIsConditionalProcessingAttribute, + PRUint8 aAttrEnum) { + nsIAtom* name; if (aIsConditionalProcessingAttribute) { nsCOMPtr<DOMSVGTests> tests(do_QueryInterface(this)); - tests->DidChangeStringList(aAttrEnum); - return; + name = tests->GetAttrName(aAttrEnum); + } else { + name = *GetStringListInfo().mStringListInfo[aAttrEnum].mName; + } + return WillChangeValue(name); +} + +void +nsSVGElement::DidChangeStringList(bool aIsConditionalProcessingAttribute, + PRUint8 aAttrEnum, + const nsAttrValue& aEmptyOrOldValue) +{ + nsIAtom* name; + nsAttrValue newValue; + nsCOMPtr<DOMSVGTests> tests; + + if (aIsConditionalProcessingAttribute) { + tests = do_QueryInterface(this); + name = tests->GetAttrName(aAttrEnum); + tests->GetAttrValue(aAttrEnum, newValue); + } else { + StringListAttributesInfo info = GetStringListInfo(); + + NS_ASSERTION(info.mStringListCount > 0, + "DidChangeStringList on element with no string list attribs"); + NS_ASSERTION(aAttrEnum < info.mStringListCount, "aAttrEnum out of range"); + + name = *info.mStringListInfo[aAttrEnum].mName; + newValue.SetTo(info.mStringLists[aAttrEnum], nsnull); } - StringListAttributesInfo info = GetStringListInfo(); + DidChangeValue(name, aEmptyOrOldValue, newValue); - NS_ASSERTION(info.mStringListCount > 0, - "DidChangeStringList on element with no string list attribs"); - - NS_ASSERTION(aAttrEnum < info.mStringListCount, "aAttrEnum out of range"); - - nsAutoString serializedValue; - info.mStringLists[aAttrEnum].GetValue(serializedValue, this); - - nsAttrValue attrValue(serializedValue); - SetParsedAttr(kNameSpaceID_None, *info.mStringListInfo[aAttrEnum].mName, - nsnull, attrValue, true); + if (aIsConditionalProcessingAttribute) { + tests->MaybeInvalidate(); + } } void diff --git a/content/svg/content/src/nsSVGElement.h b/content/svg/content/src/nsSVGElement.h index 53c9c4914bf0..92e1a451274e 100644 --- a/content/svg/content/src/nsSVGElement.h +++ b/content/svg/content/src/nsSVGElement.h @@ -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 { diff --git a/content/svg/content/src/nsSVGEnum.cpp b/content/svg/content/src/nsSVGEnum.cpp index 696c436b3f84..3e5e5317dc65 100644 --- a/content/svg/content/src/nsSVGEnum.cpp +++ b/content/svg/content/src/nsSVGEnum.cpp @@ -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; } diff --git a/content/svg/content/src/nsSVGEnum.h b/content/svg/content/src/nsSVGEnum.h index c59cd36d9e66..502537675544 100644 --- a/content/svg/content/src/nsSVGEnum.h +++ b/content/svg/content/src/nsSVGEnum.h @@ -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 diff --git a/content/svg/content/src/nsSVGInteger.cpp b/content/svg/content/src/nsSVGInteger.cpp index dced1e93840c..8a1f06dbb0d6 100644 --- a/content/svg/content/src/nsSVGInteger.cpp +++ b/content/svg/content/src/nsSVGInteger.cpp @@ -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 diff --git a/content/svg/content/src/nsSVGIntegerPair.cpp b/content/svg/content/src/nsSVGIntegerPair.cpp index b5f5d8b85960..dc35ada0e4ed 100644 --- a/content/svg/content/src/nsSVGIntegerPair.cpp +++ b/content/svg/content/src/nsSVGIntegerPair.cpp @@ -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 diff --git a/content/svg/content/src/nsSVGIntegerPair.h b/content/svg/content/src/nsSVGIntegerPair.h index 63ae54412167..2e181615b958 100644 --- a/content/svg/content/src/nsSVGIntegerPair.h +++ b/content/svg/content/src/nsSVGIntegerPair.h @@ -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); diff --git a/content/svg/content/src/nsSVGLength2.cpp b/content/svg/content/src/nsSVGLength2.cpp index 4709ae0e8ba0..40301209dc08 100644 --- a/content/svg/content/src/nsSVGLength2.cpp +++ b/content/svg/content/src/nsSVGLength2.cpp @@ -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 diff --git a/content/svg/content/src/nsSVGLength2.h b/content/svg/content/src/nsSVGLength2.h index 1882ef2ec7fc..1d555b0826bf 100644 --- a/content/svg/content/src/nsSVGLength2.h +++ b/content/svg/content/src/nsSVGLength2.h @@ -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; } diff --git a/content/svg/content/src/nsSVGMarkerElement.cpp b/content/svg/content/src/nsSVGMarkerElement.cpp index e16500449b4f..91c6e2950fc0 100644 --- a/content/svg/content/src/nsSVGMarkerElement.cpp +++ b/content/svg/content/src/nsSVGMarkerElement.cpp @@ -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; } diff --git a/content/svg/content/src/nsSVGNumber2.cpp b/content/svg/content/src/nsSVGNumber2.cpp index 5a0450c132e8..9cc4d64632a2 100644 --- a/content/svg/content/src/nsSVGNumber2.cpp +++ b/content/svg/content/src/nsSVGNumber2.cpp @@ -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 diff --git a/content/svg/content/src/nsSVGNumberPair.cpp b/content/svg/content/src/nsSVGNumberPair.cpp index 38254fbfcd0c..825704e0476d 100644 --- a/content/svg/content/src/nsSVGNumberPair.cpp +++ b/content/svg/content/src/nsSVGNumberPair.cpp @@ -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 diff --git a/content/svg/content/src/nsSVGNumberPair.h b/content/svg/content/src/nsSVGNumberPair.h index e520ec523cad..f6987724c870 100644 --- a/content/svg/content/src/nsSVGNumberPair.h +++ b/content/svg/content/src/nsSVGNumberPair.h @@ -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); diff --git a/content/svg/content/src/nsSVGViewBox.cpp b/content/svg/content/src/nsSVGViewBox.cpp index 3c34bb5fa417..3d29219439fb 100644 --- a/content/svg/content/src/nsSVGViewBox.cpp +++ b/content/svg/content/src/nsSVGViewBox.cpp @@ -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. } diff --git a/content/svg/content/test/Makefile.in b/content/svg/content/test/Makefile.in index 0925d9de0b03..5bcc478ca3bc 100644 --- a/content/svg/content/test/Makefile.in +++ b/content/svg/content/test/Makefile.in @@ -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 \ diff --git a/content/svg/content/test/MutationEventChecker.js b/content/svg/content/test/MutationEventChecker.js new file mode 100644 index 000000000000..1394b6ca1640 --- /dev/null +++ b/content/svg/content/test/MutationEventChecker.js @@ -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; + } + } +} diff --git a/content/svg/content/test/test_SVGLengthList.xhtml b/content/svg/content/test/test_SVGLengthList.xhtml index 876421df3f60..fe96cb2c2054 100644 --- a/content/svg/content/test/test_SVGLengthList.xhtml +++ b/content/svg/content/test/test_SVGLengthList.xhtml @@ -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(); } diff --git a/content/svg/content/test/test_SVGNumberList.xhtml b/content/svg/content/test/test_SVGNumberList.xhtml new file mode 100644 index 000000000000..fcd471f4c4f2 --- /dev/null +++ b/content/svg/content/test/test_SVGNumberList.xhtml @@ -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> diff --git a/content/svg/content/test/test_SVGPathSegList.xhtml b/content/svg/content/test/test_SVGPathSegList.xhtml index 73513197f4f9..b1c42bc1e8b2 100644 --- a/content/svg/content/test/test_SVGPathSegList.xhtml +++ b/content/svg/content/test/test_SVGPathSegList.xhtml @@ -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(); } diff --git a/content/svg/content/test/test_SVGPointList.xhtml b/content/svg/content/test/test_SVGPointList.xhtml new file mode 100644 index 000000000000..fbeaacf77a53 --- /dev/null +++ b/content/svg/content/test/test_SVGPointList.xhtml @@ -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> diff --git a/content/svg/content/test/test_SVGTransformList.xhtml b/content/svg/content/test/test_SVGTransformList.xhtml index 00793cc2169b..453f1efefb16 100644 --- a/content/svg/content/test/test_SVGTransformList.xhtml +++ b/content/svg/content/test/test_SVGTransformList.xhtml @@ -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); ]]> diff --git a/content/svg/content/test/test_SVGxxxList.xhtml b/content/svg/content/test/test_SVGxxxList.xhtml index e13171b968b5..08286d487ff1 100644 --- a/content/svg/content/test/test_SVGxxxList.xhtml +++ b/content/svg/content/test/test_SVGxxxList.xhtml @@ -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() { diff --git a/content/svg/content/test/test_dataTypes.html b/content/svg/content/test/test_dataTypes.html index 75930af3020b..a6035cfdd713 100644 --- a/content/svg/content/test/test_dataTypes.html +++ b/content/svg/content/test/test_dataTypes.html @@ -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(); } diff --git a/content/svg/content/test/test_dataTypesModEvents.html b/content/svg/content/test/test_dataTypesModEvents.html new file mode 100644 index 000000000000..e45c6415a618 --- /dev/null +++ b/content/svg/content/test/test_dataTypesModEvents.html @@ -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> diff --git a/docshell/base/nsDocShell.cpp b/docshell/base/nsDocShell.cpp index 7faa360321ac..6fd6c8cf816e 100644 --- a/docshell/base/nsDocShell.cpp +++ b/docshell/base/nsDocShell.cpp @@ -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); diff --git a/dom/Makefile.in b/dom/Makefile.in index d082f8d51756..91a0480f65e5 100644 --- a/dom/Makefile.in +++ b/dom/Makefile.in @@ -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 diff --git a/dom/base/Navigator.cpp b/dom/base/Navigator.cpp index e9890da74f07..d032c2986fe1 100644 --- a/dom/base/Navigator.cpp +++ b/dom/base/Navigator.cpp @@ -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 { diff --git a/dom/base/Navigator.h b/dom/base/Navigator.h index 35dc43dfa05f..3ba648c7a1ab 100644 --- a/dom/base/Navigator.h +++ b/dom/base/Navigator.h @@ -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; }; diff --git a/dom/base/nsDOMClassInfo.cpp b/dom/base/nsDOMClassInfo.cpp index 2ef36d34bd8a..efe13341ef79 100644 --- a/dom/base/nsDOMClassInfo.cpp +++ b/dom/base/nsDOMClassInfo.cpp @@ -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 diff --git a/dom/base/nsDOMClassInfoClasses.h b/dom/base/nsDOMClassInfoClasses.h index 8a945a897d1d..2c3aeed980ce 100644 --- a/dom/base/nsDOMClassInfoClasses.h +++ b/dom/base/nsDOMClassInfoClasses.h @@ -540,4 +540,8 @@ DOMCI_CLASS(TelephonyCall) DOMCI_CLASS(CallEvent) #endif +#ifdef MOZ_B2G_BT +DOMCI_CLASS(BluetoothAdapter) +#endif + DOMCI_CLASS(DOMError) diff --git a/dom/bluetooth/BluetoothAdapter.cpp b/dom/bluetooth/BluetoothAdapter.cpp new file mode 100644 index 000000000000..80faefc2a4a8 --- /dev/null +++ b/dom/bluetooth/BluetoothAdapter.cpp @@ -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; +} diff --git a/dom/bluetooth/BluetoothAdapter.h b/dom/bluetooth/BluetoothAdapter.h new file mode 100644 index 000000000000..3db9a26f735c --- /dev/null +++ b/dom/bluetooth/BluetoothAdapter.h @@ -0,0 +1,28 @@ +/* -*- 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/. */ + +#ifndef mozilla_dom_bluetooth_bluetoothadapter_h__ +#define mozilla_dom_bluetooth_bluetoothadapter_h__ + +#include "BluetoothCommon.h" +#include "nsIDOMBluetoothAdapter.h" + +BEGIN_BLUETOOTH_NAMESPACE + +class BluetoothAdapter : public nsIDOMBluetoothAdapter +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSIDOMBLUETOOTHADAPTER + + BluetoothAdapter(); + +protected: + bool mPower; +}; + +END_BLUETOOTH_NAMESPACE +#endif diff --git a/dom/bluetooth/BluetoothCommon.h b/dom/bluetooth/BluetoothCommon.h new file mode 100644 index 000000000000..e74435926527 --- /dev/null +++ b/dom/bluetooth/BluetoothCommon.h @@ -0,0 +1,19 @@ +/* -*- 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/. */ + +#ifndef mozilla_dom_bluetooth_bluetoothcommon_h__ +#define mozilla_dom_bluetooth_bluetoothcommon_h__ + +#define BEGIN_BLUETOOTH_NAMESPACE \ + namespace mozilla { namespace dom { namespace bluetooth { +#define END_BLUETOOTH_NAMESPACE \ + } /* namespace bluetooth */ } /* namespace dom */ } /* namespace mozilla */ +#define USING_BLUETOOTH_NAMESPACE \ + using namespace mozilla::dom::bluetooth; + +class nsIDOMBluetooth; + +#endif // mozilla_dom_bluetooth_bluetoothcommon_h__ diff --git a/dom/bluetooth/Makefile.in b/dom/bluetooth/Makefile.in new file mode 100644 index 000000000000..7d782e5356c9 --- /dev/null +++ b/dom/bluetooth/Makefile.in @@ -0,0 +1,30 @@ +# 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/. + +DEPTH = ../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +MODULE = dom +LIBRARY_NAME = dombluetooth_s +XPIDL_MODULE = dom_bluetooth +LIBXUL_LIBRARY = 1 +FORCE_STATIC_LIB = 1 + +include $(topsrcdir)/dom/dom-config.mk + +CPPSRCS = \ + BluetoothAdapter.cpp \ + $(NULL) + +XPIDLSRCS = \ + nsIDOMNavigatorBluetooth.idl \ + nsIDOMBluetoothAdapter.idl \ + $(NULL) + +include $(topsrcdir)/config/rules.mk + diff --git a/dom/bluetooth/nsIDOMBluetoothAdapter.idl b/dom/bluetooth/nsIDOMBluetoothAdapter.idl new file mode 100644 index 000000000000..1dc2e1265fd9 --- /dev/null +++ b/dom/bluetooth/nsIDOMBluetoothAdapter.idl @@ -0,0 +1,13 @@ +/* -*- 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 "nsISupports.idl" + +[scriptable, builtinclass, uuid(29689a22-45ff-4ccf-b552-5364ce3a3642)] +interface nsIDOMBluetoothAdapter : nsISupports +{ + attribute boolean power; +}; diff --git a/dom/bluetooth/nsIDOMNavigatorBluetooth.idl b/dom/bluetooth/nsIDOMNavigatorBluetooth.idl new file mode 100644 index 000000000000..18f28de44f15 --- /dev/null +++ b/dom/bluetooth/nsIDOMNavigatorBluetooth.idl @@ -0,0 +1,15 @@ +/* -*- 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 "nsISupports.idl" + +interface nsIDOMBluetoothAdapter; + +[scriptable, uuid(677f2c2d-c4d1-41ea-addc-21d30d0d3858)] +interface nsIDOMNavigatorBluetooth : nsISupports +{ + readonly attribute nsIDOMBluetoothAdapter mozBluetooth; +}; diff --git a/dom/dom-config.mk b/dom/dom-config.mk index ac61255020c0..69004508d428 100644 --- a/dom/dom-config.mk +++ b/dom/dom-config.mk @@ -31,5 +31,9 @@ DOM_SRCDIRS += \ $(NULL) endif +ifdef MOZ_B2G_BT +DOM_SRCDIRS += dom/bluetooth +endif + LOCAL_INCLUDES += $(DOM_SRCDIRS:%=-I$(topsrcdir)/%) DEFINES += -D_IMPL_NS_LAYOUT diff --git a/dom/plugins/base/android/ANPNativeWindow.cpp b/dom/plugins/base/android/ANPNativeWindow.cpp index 4359688a859d..b693284f3d5b 100644 --- a/dom/plugins/base/android/ANPNativeWindow.cpp +++ b/dom/plugins/base/android/ANPNativeWindow.cpp @@ -52,14 +52,16 @@ using namespace mozilla; #define LOG(args...) __android_log_print(ANDROID_LOG_INFO, "GeckoPlugins" , ## args) #define ASSIGN(obj, name) (obj)->name = anp_native_window_##name -static ANPNativeWindow anp_native_window_acquireNativeWindow(NPP instance) { +static nsresult GetOwner(NPP instance, nsPluginInstanceOwner** owner) { nsNPAPIPluginInstance* pinst = static_cast<nsNPAPIPluginInstance*>(instance->ndata); - nsPluginInstanceOwner* owner; - if (NS_FAILED(pinst->GetOwner((nsIPluginInstanceOwner**)&owner))) { - return NULL; - } + return pinst->GetOwner((nsIPluginInstanceOwner**)owner); +} +static ANPNativeWindow anp_native_window_acquireNativeWindow(NPP instance) { + nsRefPtr<nsPluginInstanceOwner> owner; + if (NS_FAILED(GetOwner(instance, getter_AddRefs(owner)))) + return NULL; ANPNativeWindow window = owner->Layer()->GetNativeWindowForContent(); owner->Invalidate(); @@ -68,12 +70,9 @@ static ANPNativeWindow anp_native_window_acquireNativeWindow(NPP instance) { } static void anp_native_window_invertPluginContent(NPP instance, bool isContentInverted) { - nsNPAPIPluginInstance* pinst = static_cast<nsNPAPIPluginInstance*>(instance->ndata); - - nsPluginInstanceOwner* owner; - if (NS_FAILED(pinst->GetOwner((nsIPluginInstanceOwner**)&owner))) { + nsRefPtr<nsPluginInstanceOwner> owner; + if (NS_FAILED(GetOwner(instance, getter_AddRefs(owner)))) return; - } owner->Layer()->SetInverted(isContentInverted); } diff --git a/dom/plugins/base/android/ANPVideo.cpp b/dom/plugins/base/android/ANPVideo.cpp index 6b75425a046c..9f49c5f1909d 100644 --- a/dom/plugins/base/android/ANPVideo.cpp +++ b/dom/plugins/base/android/ANPVideo.cpp @@ -35,22 +35,23 @@ using namespace mozilla; -static AndroidMediaLayer* GetLayerForInstance(NPP instance) { +static nsresult GetOwner(NPP instance, nsPluginInstanceOwner** owner) { nsNPAPIPluginInstance* pinst = static_cast<nsNPAPIPluginInstance*>(instance->ndata); - nsPluginInstanceOwner* owner; - if (NS_FAILED(pinst->GetOwner((nsIPluginInstanceOwner**)&owner))) { - return NULL; - } + return pinst->GetOwner((nsIPluginInstanceOwner**)owner); +} +static AndroidMediaLayer* GetLayerForInstance(NPP instance) { + nsRefPtr<nsPluginInstanceOwner> owner; + if (NS_FAILED(GetOwner(instance, getter_AddRefs(owner)))) + return NULL; + return owner->Layer(); } static void Invalidate(NPP instance) { - nsNPAPIPluginInstance* pinst = static_cast<nsNPAPIPluginInstance*>(instance->ndata); - - nsPluginInstanceOwner* owner; - if (NS_FAILED(pinst->GetOwner((nsIPluginInstanceOwner**)&owner))) + nsRefPtr<nsPluginInstanceOwner> owner; + if (NS_FAILED(GetOwner(instance, getter_AddRefs(owner)))) return; owner->Invalidate(); diff --git a/dom/plugins/base/android/ANPWindow.cpp b/dom/plugins/base/android/ANPWindow.cpp index 75b643df386c..ca9c202a33d4 100644 --- a/dom/plugins/base/android/ANPWindow.cpp +++ b/dom/plugins/base/android/ANPWindow.cpp @@ -85,6 +85,12 @@ anp_window_requestCenterFitZoom(NPP instance) NOT_IMPLEMENTED(); } +static nsresult GetOwner(NPP instance, nsPluginInstanceOwner** owner) { + nsNPAPIPluginInstance* pinst = static_cast<nsNPAPIPluginInstance*>(instance->ndata); + + return pinst->GetOwner((nsIPluginInstanceOwner**)owner); +} + ANPRectI anp_window_visibleRect(NPP instance) { @@ -92,8 +98,8 @@ anp_window_visibleRect(NPP instance) nsNPAPIPluginInstance* pinst = static_cast<nsNPAPIPluginInstance*>(instance->ndata); - nsPluginInstanceOwner* owner; - if (NS_FAILED(pinst->GetOwner((nsIPluginInstanceOwner**)&owner))) { + nsRefPtr<nsPluginInstanceOwner> owner; + if (NS_FAILED(GetOwner(instance, getter_AddRefs(owner)))) { return rect; } diff --git a/dom/plugins/base/nsNPAPIPluginInstance.cpp b/dom/plugins/base/nsNPAPIPluginInstance.cpp index 0f90ad6ded6f..e77d98cca147 100644 --- a/dom/plugins/base/nsNPAPIPluginInstance.cpp +++ b/dom/plugins/base/nsNPAPIPluginInstance.cpp @@ -90,6 +90,7 @@ nsNPAPIPluginInstance::nsNPAPIPluginInstance(nsNPAPIPlugin* plugin) #ifdef MOZ_WIDGET_ANDROID mSurface(nsnull), mANPDrawingModel(0), + mOnScreen(true), #endif mRunning(NOT_STARTED), mWindowless(false), @@ -724,6 +725,44 @@ void nsNPAPIPluginInstance::SetEventModel(NPEventModel aModel) #endif #if defined(MOZ_WIDGET_ANDROID) + +static void SendLifecycleEvent(nsNPAPIPluginInstance* aInstance, PRUint32 aAction) +{ + ANPEvent event; + event.inSize = sizeof(ANPEvent); + event.eventType = kLifecycle_ANPEventType; + event.data.lifecycle.action = aAction; + aInstance->HandleEvent(&event, nsnull); +} + +void nsNPAPIPluginInstance::NotifyForeground(bool aForeground) +{ + PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("nsNPAPIPluginInstance::SetForeground this=%p\n foreground=%d",this, aForeground)); + if (RUNNING != mRunning) + return; + + SendLifecycleEvent(this, aForeground ? kResume_ANPLifecycleAction : kPause_ANPLifecycleAction); +} + +void nsNPAPIPluginInstance::NotifyOnScreen(bool aOnScreen) +{ + PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("nsNPAPIPluginInstance::SetOnScreen this=%p\n onScreen=%d",this, aOnScreen)); + if (RUNNING != mRunning || mOnScreen == aOnScreen) + return; + + mOnScreen = aOnScreen; + SendLifecycleEvent(this, aOnScreen ? kOnScreen_ANPLifecycleAction : kOffScreen_ANPLifecycleAction); +} + +void nsNPAPIPluginInstance::MemoryPressure() +{ + PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("nsNPAPIPluginInstance::MemoryPressure this=%p\n",this)); + if (RUNNING != mRunning) + return; + + SendLifecycleEvent(this, kFreeMemory_ANPLifecycleAction); +} + void nsNPAPIPluginInstance::SetANPDrawingModel(PRUint32 aModel) { mANPDrawingModel = aModel; diff --git a/dom/plugins/base/nsNPAPIPluginInstance.h b/dom/plugins/base/nsNPAPIPluginInstance.h index ca13f71accfa..38094948a7a6 100644 --- a/dom/plugins/base/nsNPAPIPluginInstance.h +++ b/dom/plugins/base/nsNPAPIPluginInstance.h @@ -147,6 +147,14 @@ public: #endif #ifdef MOZ_WIDGET_ANDROID + void NotifyForeground(bool aForeground); + void NotifyOnScreen(bool aOnScreen); + void MemoryPressure(); + + bool IsOnScreen() { + return mOnScreen; + } + PRUint32 GetANPDrawingModel() { return mANPDrawingModel; } void SetANPDrawingModel(PRUint32 aModel); @@ -282,6 +290,7 @@ private: bool mUsePluginLayersPref; #ifdef MOZ_WIDGET_ANDROID void* mSurface; + bool mOnScreen; #endif }; diff --git a/dom/plugins/base/nsPluginHost.cpp b/dom/plugins/base/nsPluginHost.cpp index 94d2bee76f10..fa9cecdb5c85 100644 --- a/dom/plugins/base/nsPluginHost.cpp +++ b/dom/plugins/base/nsPluginHost.cpp @@ -375,6 +375,10 @@ nsPluginHost::nsPluginHost() if (obsService) { obsService->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false); obsService->AddObserver(this, NS_PRIVATE_BROWSING_SWITCH_TOPIC, false); +#ifdef MOZ_WIDGET_ANDROID + obsService->AddObserver(this, "application-foreground", false); + obsService->AddObserver(this, "application-background", false); +#endif } #ifdef PLUGIN_LOGGING @@ -3381,6 +3385,24 @@ NS_IMETHODIMP nsPluginHost::Observe(nsISupports *aSubject, mInstances[i]->PrivateModeStateChanged(); } } +#ifdef MOZ_WIDGET_ANDROID + if (!nsCRT::strcmp("application-background", aTopic)) { + for(PRUint32 i = 0; i < mInstances.Length(); i++) { + mInstances[i]->NotifyForeground(false); + } + } + if (!nsCRT::strcmp("application-foreground", aTopic)) { + for(PRUint32 i = 0; i < mInstances.Length(); i++) { + if (mInstances[i]->IsOnScreen()) + mInstances[i]->NotifyForeground(true); + } + } + if (!nsCRT::strcmp("memory-pressure", aTopic)) { + for(PRUint32 i = 0; i < mInstances.Length(); i++) { + mInstances[i]->MemoryPressure(); + } + } +#endif return NS_OK; } diff --git a/dom/plugins/base/nsPluginInstanceOwner.cpp b/dom/plugins/base/nsPluginInstanceOwner.cpp index 05e39f1c8d99..b67de18fbcf2 100644 --- a/dom/plugins/base/nsPluginInstanceOwner.cpp +++ b/dom/plugins/base/nsPluginInstanceOwner.cpp @@ -339,9 +339,8 @@ nsPluginInstanceOwner::nsPluginInstanceOwner() mWaitingForPaint = false; #ifdef MOZ_WIDGET_ANDROID - mOnScreen = false; mInverted = false; - mLayer = new AndroidMediaLayer(); + mLayer = nsnull; #endif } @@ -393,10 +392,7 @@ nsPluginInstanceOwner::~nsPluginInstanceOwner() mPluginWindow = nsnull; #ifdef MOZ_WIDGET_ANDROID - if (mLayer) { - delete mLayer; - mLayer = nsnull; - } + RemovePluginView(); #endif if (mInstance) { @@ -1688,22 +1684,6 @@ void nsPluginInstanceOwner::SendSize(int width, int height) mInstance->HandleEvent(&event, nsnull); } -void nsPluginInstanceOwner::SendOnScreenEvent(bool onScreen) -{ - if (!mInstance) - return; - - if ((onScreen && !mOnScreen) || (!onScreen && mOnScreen)) { - ANPEvent event; - event.inSize = sizeof(ANPEvent); - event.eventType = kLifecycle_ANPEventType; - event.data.lifecycle.action = onScreen ? kOnScreen_ANPLifecycleAction : kOffScreen_ANPLifecycleAction; - mInstance->HandleEvent(&event, nsnull); - - mOnScreen = onScreen; - } -} - bool nsPluginInstanceOwner::AddPluginView(const gfxRect& aRect) { void* javaSurface = mInstance->GetJavaSurface(); @@ -1754,14 +1734,12 @@ bool nsPluginInstanceOwner::AddPluginView(const gfxRect& aRect) aRect.height); #endif - SendOnScreenEvent(true); - return true; } void nsPluginInstanceOwner::RemovePluginView() { - if (!mInstance || !mObjectFrame | !mOnScreen) + if (!mInstance || !mObjectFrame) return; void* surface = mInstance->GetJavaSurface(); @@ -1779,7 +1757,6 @@ void nsPluginInstanceOwner::RemovePluginView() "removePluginView", "(Landroid/view/View;)V"); env->CallStaticVoidMethod(cls, method, surface); - SendOnScreenEvent(false); } void nsPluginInstanceOwner::Invalidate() { @@ -2759,6 +2736,14 @@ nsPluginInstanceOwner::Destroy() mContent->RemoveEventListener(NS_LITERAL_STRING("text"), this, true); #endif +#if MOZ_WIDGET_ANDROID + RemovePluginView(); + + if (mLayer) + mLayer->SetVisible(false); + +#endif + if (mWidget) { if (mPluginWindow) { mPluginWindow->SetPluginWidget(nsnull); @@ -2867,7 +2852,7 @@ void nsPluginInstanceOwner::Paint(gfxContext* aContext, const gfxRect& aFrameRect, const gfxRect& aDirtyRect) { - if (!mInstance || !mObjectFrame) + if (!mInstance || !mObjectFrame || !mPluginDocumentActiveState) return; PRInt32 model = mInstance->GetANPDrawingModel(); @@ -2880,11 +2865,13 @@ void nsPluginInstanceOwner::Paint(gfxContext* aContext, } if (model == kOpenGL_ANPDrawingModel) { + if (!mLayer) + mLayer = new AndroidMediaLayer(); + // FIXME: this is gross float zoomLevel = aFrameRect.width / (float)mPluginWindow->width; mLayer->UpdatePosition(aFrameRect, zoomLevel); - SendOnScreenEvent(true); SendSize((int)aFrameRect.width, (int)aFrameRect.height); return; } @@ -3587,17 +3574,6 @@ void nsPluginInstanceOwner::UpdateWindowPositionAndClipRect(bool aSetWindow) } else { mPluginWindow->clipRect.right = 0; mPluginWindow->clipRect.bottom = 0; -#if 0 //MOZ_WIDGET_ANDROID - if (mInstance) { - PRInt32 model = mInstance->GetANPDrawingModel(); - - if (model == kSurface_ANPDrawingModel) { - RemovePluginView(); - } else if (model == kOpenGL_ANPDrawingModel) { - HidePluginLayer(); - } - } -#endif } if (!aSetWindow) @@ -3625,6 +3601,26 @@ nsPluginInstanceOwner::UpdateDocumentActiveState(bool aIsActive) { mPluginDocumentActiveState = aIsActive; UpdateWindowPositionAndClipRect(true); + +#ifdef MOZ_WIDGET_ANDROID + if (mInstance) { + if (mLayer) + mLayer->SetVisible(mPluginDocumentActiveState); + + if (!mPluginDocumentActiveState) + RemovePluginView(); + + mInstance->NotifyOnScreen(mPluginDocumentActiveState); + + // This is, perhaps, incorrect. It is supposed to be sent + // when "the webview has paused or resumed". The side effect + // is that Flash video players pause or resume (if they were + // playing before) based on the value here. I personally think + // we want that on Android when switching to another tab, so + // that's why we call it here. + mInstance->NotifyForeground(mPluginDocumentActiveState); + } +#endif } #endif // XP_MACOSX diff --git a/dom/plugins/base/nsPluginInstanceOwner.h b/dom/plugins/base/nsPluginInstanceOwner.h index b328650548b6..4e4a029c2484 100644 --- a/dom/plugins/base/nsPluginInstanceOwner.h +++ b/dom/plugins/base/nsPluginInstanceOwner.h @@ -328,16 +328,14 @@ private: void FixUpURLS(const nsString &name, nsAString &value); #ifdef MOZ_WIDGET_ANDROID void SendSize(int width, int height); - void SendOnScreenEvent(bool onScreen); bool AddPluginView(const gfxRect& aRect); void RemovePluginView(); - bool mOnScreen; bool mInverted; // For kOpenGL_ANPDrawingModel - mozilla::AndroidMediaLayer *mLayer; + nsRefPtr<mozilla::AndroidMediaLayer> mLayer; #endif nsPluginNativeWindow *mPluginWindow; diff --git a/gfx/layers/basic/BasicImages.cpp b/gfx/layers/basic/BasicImages.cpp index 5fd5942c9c08..90806cd38e1a 100644 --- a/gfx/layers/basic/BasicImages.cpp +++ b/gfx/layers/basic/BasicImages.cpp @@ -62,8 +62,9 @@ public: BasicPlanarYCbCrImage(const gfxIntSize& aScaleHint, gfxImageFormat aOffscreenFormat, BufferRecycleBin *aRecycleBin) : PlanarYCbCrImage(aRecycleBin) , mScaleHint(aScaleHint) - , mOffscreenFormat(aOffscreenFormat) - {} + { + SetOffscreenFormat(aOffscreenFormat); + } ~BasicPlanarYCbCrImage() { @@ -79,7 +80,6 @@ public: private: gfxIntSize mScaleHint; - gfxImageFormat mOffscreenFormat; int mStride; nsAutoArrayPtr<PRUint8> mDecodedBuffer; }; diff --git a/hal/gonk/GonkHal.cpp b/hal/gonk/GonkHal.cpp index c2abe7a22350..4c98315b003d 100644 --- a/hal/gonk/GonkHal.cpp +++ b/hal/gonk/GonkHal.cpp @@ -256,6 +256,10 @@ DisableBatteryNotifications() void GetCurrentBatteryInformation(hal::BatteryInformation *aBatteryInfo) { + static const int BATTERY_NOT_CHARGING = 0; + static const int BATTERY_CHARGING_USB = 1; + static const int BATTERY_CHARGING_AC = 2; + FILE *capacityFile = fopen("/sys/class/power_supply/battery/capacity", "r"); double capacity = dom::battery::kDefaultLevel * 100; if (capacityFile) { @@ -270,8 +274,17 @@ GetCurrentBatteryInformation(hal::BatteryInformation *aBatteryInfo) fclose(chargingFile); } + #ifdef DEBUG + if (chargingSrc != BATTERY_NOT_CHARGING && + chargingSrc != BATTERY_CHARGING_USB && + chargingSrc != BATTERY_CHARGING_AC) { + HAL_LOG(("charging_source contained unknown value: %d", chargingSrc)); + } + #endif + aBatteryInfo->level() = capacity / 100; - aBatteryInfo->charging() = chargingSrc == 1; + aBatteryInfo->charging() = (chargingSrc == BATTERY_CHARGING_USB || + chargingSrc == BATTERY_CHARGING_AC); aBatteryInfo->remainingTime() = dom::battery::kUnknownRemainingTime; } diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index 9de5ebb31d37..21cf6810648a 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -2660,8 +2660,9 @@ typedef struct JSDumpingTracer { } JSDumpingTracer; static void -DumpNotify(JSTracer *trc, void *thing, JSGCTraceKind kind) +DumpNotify(JSTracer *trc, void **thingp, JSGCTraceKind kind) { + void *thing = *thingp; JSDumpingTracer *dtrc; JSContext *cx; JSDHashEntryStub *entry; diff --git a/js/src/jsapi.h b/js/src/jsapi.h index 517cc4b36b38..e9a49a4eeba7 100644 --- a/js/src/jsapi.h +++ b/js/src/jsapi.h @@ -3099,7 +3099,7 @@ JSVAL_TRACE_KIND(jsval v) * wants to use the existing liveness of entries. */ typedef void -(* JSTraceCallback)(JSTracer *trc, void *thing, JSGCTraceKind kind); +(* JSTraceCallback)(JSTracer *trc, void **thingp, JSGCTraceKind kind); struct JSTracer { JSRuntime *runtime; diff --git a/js/src/jsfriendapi.cpp b/js/src/jsfriendapi.cpp index e323ca29cac7..93d98bc54ed5 100644 --- a/js/src/jsfriendapi.cpp +++ b/js/src/jsfriendapi.cpp @@ -483,13 +483,14 @@ struct JSDumpHeapTracer : public JSTracer { }; static void -DumpHeapVisitChild(JSTracer *trc, void *thing, JSGCTraceKind kind); +DumpHeapVisitChild(JSTracer *trc, void **thingp, JSGCTraceKind kind); static void -DumpHeapPushIfNew(JSTracer *trc, void *thing, JSGCTraceKind kind) +DumpHeapPushIfNew(JSTracer *trc, void **thingp, JSGCTraceKind kind) { JS_ASSERT(trc->callback == DumpHeapPushIfNew || trc->callback == DumpHeapVisitChild); + void *thing = *thingp; JSDumpHeapTracer *dtrc = static_cast<JSDumpHeapTracer *>(trc); /* @@ -509,13 +510,13 @@ DumpHeapPushIfNew(JSTracer *trc, void *thing, JSGCTraceKind kind) } static void -DumpHeapVisitChild(JSTracer *trc, void *thing, JSGCTraceKind kind) +DumpHeapVisitChild(JSTracer *trc, void **thingp, JSGCTraceKind kind) { JS_ASSERT(trc->callback == DumpHeapVisitChild); JSDumpHeapTracer *dtrc = static_cast<JSDumpHeapTracer *>(trc); const char *edgeName = JS_GetTraceEdgeName(dtrc, dtrc->buffer, sizeof(dtrc->buffer)); - fprintf(dtrc->output, "> %p %s\n", (void *)thing, edgeName); - DumpHeapPushIfNew(dtrc, thing, kind); + fprintf(dtrc->output, "> %p %s\n", *thingp, edgeName); + DumpHeapPushIfNew(dtrc, thingp, kind); } void diff --git a/js/src/jsgc.cpp b/js/src/jsgc.cpp index 4304d25e858d..c63b0dcdefbd 100644 --- a/js/src/jsgc.cpp +++ b/js/src/jsgc.cpp @@ -1859,7 +1859,7 @@ GCMarker::markDelayedChildren() #ifdef DEBUG static void -EmptyMarkCallback(JSTracer *trc, void *thing, JSGCTraceKind kind) +EmptyMarkCallback(JSTracer *trc, void **thingp, JSGCTraceKind kind) { } #endif @@ -3456,7 +3456,7 @@ struct VerifyTracer : JSTracer { * node. */ static void -AccumulateEdge(JSTracer *jstrc, void *thing, JSGCTraceKind kind) +AccumulateEdge(JSTracer *jstrc, void **thingp, JSGCTraceKind kind) { VerifyTracer *trc = (VerifyTracer *)jstrc; @@ -3469,7 +3469,7 @@ AccumulateEdge(JSTracer *jstrc, void *thing, JSGCTraceKind kind) VerifyNode *node = trc->curnode; uint32_t i = node->count; - node->edges[i].thing = thing; + node->edges[i].thing = *thingp; node->edges[i].kind = kind; node->edges[i].label = trc->debugPrinter ? NULL : (char *)trc->debugPrintArg; node->count++; @@ -3590,9 +3590,9 @@ oom: } static void -CheckAutorooter(JSTracer *jstrc, void *thing, JSGCTraceKind kind) +CheckAutorooter(JSTracer *jstrc, void **thingp, JSGCTraceKind kind) { - static_cast<Cell *>(thing)->markIfUnmarked(); + static_cast<Cell *>(*thingp)->markIfUnmarked(); } /* @@ -3603,13 +3603,13 @@ CheckAutorooter(JSTracer *jstrc, void *thing, JSGCTraceKind kind) * modified) must point to marked objects. */ static void -CheckEdge(JSTracer *jstrc, void *thing, JSGCTraceKind kind) +CheckEdge(JSTracer *jstrc, void **thingp, JSGCTraceKind kind) { VerifyTracer *trc = (VerifyTracer *)jstrc; VerifyNode *node = trc->curnode; for (uint32_t i = 0; i < node->count; i++) { - if (node->edges[i].thing == thing) { + if (node->edges[i].thing == *thingp) { JS_ASSERT(node->edges[i].kind == kind); node->edges[i].thing = NULL; return; diff --git a/js/src/jsgcmark.cpp b/js/src/jsgcmark.cpp index 6fbb4ff95cbe..feb1907918e4 100644 --- a/js/src/jsgcmark.cpp +++ b/js/src/jsgcmark.cpp @@ -107,10 +107,13 @@ MarkInternal(JSTracer *trc, T *thing) * GC. */ if (!rt->gcCurrentCompartment || thing->compartment() == rt->gcCurrentCompartment) { - if (IS_GC_MARKING_TRACER(trc)) + if (IS_GC_MARKING_TRACER(trc)) { PushMarkStack(static_cast<GCMarker *>(trc), thing); - else - trc->callback(trc, (void *)thing, GetGCThingTraceKind(thing)); + } else { + void *tmp = (void *)thing; + trc->callback(trc, &tmp, GetGCThingTraceKind(thing)); + JS_ASSERT(tmp == thing); + } } #ifdef DEBUG diff --git a/js/src/jsinterp.cpp b/js/src/jsinterp.cpp index 3120bffb364a..7d1961996dc3 100644 --- a/js/src/jsinterp.cpp +++ b/js/src/jsinterp.cpp @@ -3138,7 +3138,18 @@ BEGIN_CASE(JSOP_DEFCONST) BEGIN_CASE(JSOP_DEFVAR) { PropertyName *dn = atoms[GET_INDEX(regs.pc)]->asPropertyName(); - if (!DefVarOrConstOperation(cx, op, dn, regs.fp())) + + /* ES5 10.5 step 8 (with subsequent errata). */ + uintN attrs = JSPROP_ENUMERATE; + if (!regs.fp()->isEvalFrame()) + attrs |= JSPROP_PERMANENT; + if (op == JSOP_DEFCONST) + attrs |= JSPROP_READONLY; + + /* Step 8b. */ + JSObject &obj = regs.fp()->varObj(); + + if (!DefVarOrConstOperation(cx, obj, dn, attrs)) goto error; } END_CASE(JSOP_DEFVAR) diff --git a/js/src/jsinterpinlines.h b/js/src/jsinterpinlines.h index 6426ff30bd38..c6167a356077 100644 --- a/js/src/jsinterpinlines.h +++ b/js/src/jsinterpinlines.h @@ -439,27 +439,19 @@ NameOperation(JSContext *cx, jsbytecode *pc, Value *vp) } inline bool -DefVarOrConstOperation(JSContext *cx, JSOp op, PropertyName *dn, StackFrame *fp) +DefVarOrConstOperation(JSContext *cx, JSObject &varobj, PropertyName *dn, uintN attrs) { - /* ES5 10.5 step 8 (with subsequent errata). */ - uintN attrs = JSPROP_ENUMERATE; - if (!fp->isEvalFrame()) - attrs |= JSPROP_PERMANENT; - if (op == JSOP_DEFCONST) - attrs |= JSPROP_READONLY; - - /* Step 8b. */ - JSObject &obj = fp->varObj(); - JS_ASSERT(!obj.getOps()->defineProperty); + JS_ASSERT(varobj.isVarObj()); + JS_ASSERT(!varobj.getOps()->defineProperty); JSProperty *prop; JSObject *obj2; - if (!obj.lookupProperty(cx, dn, &obj2, &prop)) + if (!varobj.lookupProperty(cx, dn, &obj2, &prop)) return false; /* Steps 8c, 8d. */ - if (!prop || (obj2 != &obj && obj.isGlobal())) { - if (!DefineNativeProperty(cx, &obj, dn, UndefinedValue(), + if (!prop || (obj2 != &varobj && varobj.isGlobal())) { + if (!DefineNativeProperty(cx, &varobj, dn, UndefinedValue(), JS_PropertyStub, JS_StrictPropertyStub, attrs, 0, 0)) { return false; @@ -470,7 +462,7 @@ DefVarOrConstOperation(JSContext *cx, JSOp op, PropertyName *dn, StackFrame *fp) * see a redeclaration that's |const|, we consider it a conflict. */ uintN oldAttrs; - if (!obj.getPropertyAttributes(cx, dn, &oldAttrs)) + if (!varobj.getPropertyAttributes(cx, dn, &oldAttrs)) return false; if (attrs & JSPROP_READONLY) { JSAutoByteString bytes; diff --git a/js/src/jsopcode.cpp b/js/src/jsopcode.cpp index ea7e6583517f..8e802bb73d51 100644 --- a/js/src/jsopcode.cpp +++ b/js/src/jsopcode.cpp @@ -384,25 +384,25 @@ js_DisassembleAtPC(JSContext *cx, JSScript *script, JSBool lines, jsbytecode *pc jsbytecode *next, *end; uintN len; - SprintCString(sp, "loc "); + sp->put("loc "); if (lines) - SprintCString(sp, "line"); - SprintCString(sp, " op\n"); - SprintCString(sp, "----- "); + sp->put("line"); + sp->put(" op\n"); + sp->put("----- "); if (lines) - SprintCString(sp, "----"); - SprintCString(sp, " --\n"); + sp->put("----"); + sp->put(" --\n"); next = script->code; end = next + script->length; while (next < end) { if (next == script->main()) - SprintCString(sp, "main:\n"); + sp->put("main:\n"); if (pc != NULL) { if (pc == next) - SprintCString(sp, "--> "); + sp->put("--> "); else - SprintCString(sp, " "); + sp->put(" "); } len = js_Disassemble1(cx, script, next, next - script->code, lines, sp); if (!len) @@ -716,7 +716,7 @@ js_Disassemble1(JSContext *cx, JSScript *script, jsbytecode *pc, return 0; } } - SprintCString(sp, "\n"); + sp->put("\n"); return len; } @@ -863,6 +863,12 @@ Sprinter::put(const char *s, size_t len) return oldOffset; } +ptrdiff_t +Sprinter::put(const char *s) +{ + return put(s, strlen(s)); +} + ptrdiff_t Sprinter::putString(JSString *s) { @@ -934,24 +940,6 @@ Sprinter::getOffsetOf(const char *string) const return string - base; } -ptrdiff_t -js::SprintPut(Sprinter *sp, const char *s, size_t len) -{ - return sp->put(s, len); -} - -ptrdiff_t -js::SprintCString(Sprinter *sp, const char *s) -{ - return SprintPut(sp, s, strlen(s)); -} - -ptrdiff_t -js::SprintString(Sprinter *sp, JSString *str) -{ - return sp->putString(str); -} - ptrdiff_t js::Sprint(Sprinter *sp, const char *format, ...) { @@ -966,7 +954,7 @@ js::Sprint(Sprinter *sp, const char *format, ...) JS_ReportOutOfMemory(sp->context); return -1; } - offset = SprintCString(sp, bp); + offset = sp->put(bp); sp->context->free_(bp); return offset; } @@ -1242,7 +1230,7 @@ js_printf(JSPrinter *jp, const char *format, ...) } cc = strlen(bp); - if (SprintPut(&jp->sprinter, bp, (size_t)cc) < 0) + if (jp->sprinter.put(bp, (size_t)cc) < 0) cc = -1; jp->sprinter.context->free_(bp); @@ -1253,7 +1241,7 @@ js_printf(JSPrinter *jp, const char *format, ...) JSBool js_puts(JSPrinter *jp, const char *s) { - return SprintCString(&jp->sprinter, s) >= 0; + return jp->sprinter.put(s) >= 0; } /************************************************************************/ @@ -1342,7 +1330,7 @@ SprintOpcode(SprintStack *ss, const char *str, jsbytecode *pc, } ptrdiff_t offset = ss->sprinter.getOffset(); UpdateDecompiledParent(ss->printer, pc, parentpc, offset - startOffset); - SprintCString(&ss->sprinter, str); + ss->sprinter.put(str); } /* @@ -1425,7 +1413,7 @@ GetOff(SprintStack *ss, uintN i) if (!bytes) return 0; if (bytes != FAILED_EXPRESSION_DECOMPILER) { - off = SprintCString(&ss->sprinter, bytes); + off = ss->sprinter.put(bytes); if (off < 0) off = 0; ss->offsets[i] = off; @@ -1491,7 +1479,7 @@ PushOff(SprintStack *ss, ptrdiff_t off, JSOp op, jsbytecode *pc = NULL) static bool PushStr(SprintStack *ss, const char *str, JSOp op) { - ptrdiff_t off = SprintCString(&ss->sprinter, str); + ptrdiff_t off = ss->sprinter.put(str); if (off < 0) return false; return PushOff(ss, off, op); @@ -1615,16 +1603,15 @@ SprintDoubleValue(Sprinter *sp, jsval v, JSOp *opp) JS_ASSERT(JSVAL_IS_DOUBLE(v)); d = JSVAL_TO_DOUBLE(v); if (JSDOUBLE_IS_NEGZERO(d)) { - todo = SprintCString(sp, "-0"); + todo = sp->put("-0"); *opp = JSOP_NEG; } else if (!JSDOUBLE_IS_FINITE(d)) { - /* Don't use Infinity and NaN, they're mutable. */ - todo = SprintCString(sp, - JSDOUBLE_IS_NaN(d) - ? "0 / 0" - : (d < 0) - ? "1 / -0" - : "1 / 0"); + /* Don't use Infinity and NaN, as local variables may shadow them. */ + todo = sp->put(JSDOUBLE_IS_NaN(d) + ? "0 / 0" + : (d < 0) + ? "1 / -0" + : "1 / 0"); *opp = JSOP_DIV; } else { ToCStringBuf cbuf; @@ -1950,7 +1937,7 @@ DecompileDestructuringLHS(SprintStack *ss, jsbytecode *pc, jsbytecode *endpc, JS switch (op) { case JSOP_POP: *hole = JS_TRUE; - if (SprintPut(&ss->sprinter, ", ", 2) < 0) + if (ss->sprinter.put(", ", 2) < 0) return NULL; break; @@ -1994,7 +1981,7 @@ DecompileDestructuringLHS(SprintStack *ss, jsbytecode *pc, jsbytecode *endpc, JS * in-place so pop/concat this pushed string. */ lval = PopStr(ss, JSOP_NOP); - if (SprintCString(&ss->sprinter, lval) < 0) + if (ss->sprinter.put(lval) < 0) return NULL; LOCAL_ASSERT(*pc == JSOP_POP); @@ -2034,7 +2021,7 @@ DecompileDestructuringLHS(SprintStack *ss, jsbytecode *pc, jsbytecode *endpc, JS return NULL; } else { lval = GetLocal(ss, i); - if (!lval || SprintCString(&ss->sprinter, lval) < 0) + if (!lval || ss->sprinter.put(lval) < 0) return NULL; } if (op != JSOP_SETLOCALPOP) { @@ -2071,10 +2058,10 @@ DecompileDestructuringLHS(SprintStack *ss, jsbytecode *pc, jsbytecode *endpc, JS ss->sprinter.setOffset(todo); if (*lval == '\0') { /* lval is from JSOP_BINDNAME, so just print xval. */ - todo = SprintCString(&ss->sprinter, xval); + todo = ss->sprinter.put(xval); } else if (*xval == '\0') { /* xval is from JSOP_SETCALL or JSOP_BINDXMLNAME, print lval. */ - todo = SprintCString(&ss->sprinter, lval); + todo = ss->sprinter.put(lval); } else { todo = Sprint(&ss->sprinter, (JOF_OPMODE(ss->opcodes[ss->top+1]) == JOF_XMLNAME) @@ -2117,7 +2104,7 @@ DecompileDestructuring(SprintStack *ss, jsbytecode *pc, jsbytecode *endpc, * chars so the destructuring decompilation accumulates contiguously in * ss->sprinter starting with "[". */ - ptrdiff_t head = SprintPut(&ss->sprinter, "[", 1); + ptrdiff_t head = ss->sprinter.put("[", 1); if (head < 0 || !PushOff(ss, head, JSOP_NOP)) return NULL; ss->sprinter.setOffset(ss->sprinter.getOffset() - PAREN_SLOP); @@ -2178,7 +2165,7 @@ DecompileDestructuring(SprintStack *ss, jsbytecode *pc, jsbytecode *endpc, /* Fill in any holes (holes at the end don't matter). */ while (++lasti < i) { - if (SprintPut(&ss->sprinter, ", ", 2) < 0) + if (ss->sprinter.put(", ", 2) < 0) return NULL; } } @@ -2196,7 +2183,7 @@ DecompileDestructuring(SprintStack *ss, jsbytecode *pc, jsbytecode *endpc, #endif if (!QuoteString(&ss->sprinter, atom, IsIdentifier(atom) ? 0 : (jschar)'\'')) return NULL; - if (SprintPut(&ss->sprinter, ": ", 2) < 0) + if (ss->sprinter.put(": ", 2) < 0) return NULL; break; } @@ -2268,7 +2255,7 @@ DecompileDestructuring(SprintStack *ss, jsbytecode *pc, jsbytecode *endpc, break; } - if (!hole && SprintPut(&ss->sprinter, ", ", 2) < 0) + if (!hole && ss->sprinter.put(", ", 2) < 0) return NULL; pc += JSOP_DUP_LENGTH; @@ -2276,7 +2263,7 @@ DecompileDestructuring(SprintStack *ss, jsbytecode *pc, jsbytecode *endpc, out: const char *lval = ss->sprinter.stringAt(head); - if (SprintPut(&ss->sprinter, (*lval == '[') ? "]" : "}", 1) < 0) + if (ss->sprinter.put((*lval == '[') ? "]" : "}", 1) < 0) return NULL; return pc; } @@ -2312,12 +2299,12 @@ DecompileGroupAssignment(SprintStack *ss, jsbytecode *pc, jsbytecode *endpc, LOAD_OP_DATA(pc); if (op != JSOP_GETLOCAL) break; - if (!hole && SprintPut(&ss->sprinter, ", ", 2) < 0) + if (!hole && ss->sprinter.put(", ", 2) < 0) return NULL; } LOCAL_ASSERT(op == JSOP_POPN); - if (SprintPut(&ss->sprinter, "] = [", 5) < 0) + if (ss->sprinter.put("] = [", 5) < 0) return NULL; end = ss->top - 1; @@ -2331,7 +2318,7 @@ DecompileGroupAssignment(SprintStack *ss, jsbytecode *pc, jsbytecode *endpc, } } - if (SprintPut(&ss->sprinter, "]", 1) < 0) + if (ss->sprinter.put("]", 1) < 0) return NULL; ss->sprinter.setOffset(ss->offsets[i]); ss->top = start; @@ -2867,7 +2854,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb) (void)PopStr(ss, op, &lastlvalpc); /* Print only the right operand of the assignment-op. */ - todo = SprintCString(&ss->sprinter, rval); + todo = ss->sprinter.put(rval); } else if (!inXML) { rval = PopStrPrecDupe(ss, cs->prec + !!(cs->format & JOF_LEFTASSOC), &rvalpc); lval = PopStrPrec(ss, cs->prec + !(cs->format & JOF_LEFTASSOC), &lvalpc); @@ -2886,7 +2873,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb) case 1: rval = PopStrDupe(ss, op, &rvalpc); - todo = SprintCString(&ss->sprinter, token); + todo = ss->sprinter.put(token); SprintOpcode(ss, rval, rvalpc, pc, todo); break; @@ -2894,10 +2881,10 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb) sn = js_GetSrcNote(jp->script, pc); if (sn && SN_TYPE(sn) == SRC_CONTINUE) { /* Hoisted let decl (e.g. 'y' in 'let (x) { let y; }'). */ - todo = SprintCString(&ss->sprinter, SkipString); + todo = ss->sprinter.put(SkipString); break; } - todo = SprintCString(&ss->sprinter, token); + todo = ss->sprinter.put(token); break; default: @@ -3084,7 +3071,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb) return NULL; } } - if (SprintPut(&ss->sprinter, "]", 1) < 0) + if (ss->sprinter.put("]", 1) < 0) return NULL; /* @@ -3117,7 +3104,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb) * NB: todo at this point indexes space in ss->sprinter * that is liable to be overwritten. The code below knows * exactly how long rval lives, or else copies it down via - * SprintCString. + * Sprinter::put. */ rval = ss->sprinter.stringAt(todo); rvalpc = NULL; @@ -3144,7 +3131,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb) */ if (GET_UINT16(pc) == 0) break; - todo = SprintCString(&ss->sprinter, rval); + todo = ss->sprinter.put(rval); saveop = JSOP_NOP; } } @@ -3214,7 +3201,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb) rval = PopStrDupe(ss, op, &rvalpc); todo = ss->sprinter.getOffset(); SprintOpcode(ss, lval, lvalpc, pushpc, todo); - SprintCString(&ss->sprinter, ", "); + ss->sprinter.put(", "); SprintOpcode(ss, rval, rvalpc, pushpc, todo); break; @@ -3423,7 +3410,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb) ss->top = top; ss->sprinter.setOffset(GetOff(ss, top)); if (op == JSOP_LEAVEBLOCKEXPR) - todo = SprintCString(&ss->sprinter, rval); + todo = ss->sprinter.put(rval); break; } @@ -3484,10 +3471,10 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb) return NULL; if (groupAssign) { - if (SprintCString(&ss->sprinter, rhs) < 0) + if (ss->sprinter.put(rhs) < 0) return NULL; } else if (!strncmp(rhs, DestructuredString, DestructuredStringLength)) { - if (SprintCString(&ss->sprinter, rhs + DestructuredStringLength) < 0) + if (ss->sprinter.put(rhs + DestructuredStringLength) < 0) return NULL; } else { JS_ASSERT(atoms[i] != cx->runtime->atomState.emptyAtom); @@ -3745,7 +3732,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb) ? "%s (%s)" : "%s %s", js_yield_str, rval) - : SprintCString(&ss->sprinter, js_yield_str); + : ss->sprinter.put(js_yield_str); break; } @@ -4108,9 +4095,9 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb) rval = PopStrDupe(ss, op, &rvalpc); todo = ss->sprinter.getOffset(); SprintOpcode(ss, xval, xvalpc, pushpc, todo); - SprintCString(&ss->sprinter, " ? "); + ss->sprinter.put(" ? "); SprintOpcode(ss, lval, lvalpc, pushpc, todo); - SprintCString(&ss->sprinter, " : "); + ss->sprinter.put(" : "); SprintOpcode(ss, rval, rvalpc, pushpc, todo); break; @@ -4175,7 +4162,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb) rval = POP_STR(); LOCAL_ASSERT(strcmp(rval, forelem_cookie) == 0); if (*xval == '\0') { - todo = SprintCString(&ss->sprinter, lval); + todo = ss->sprinter.put(lval); } else { todo = Sprint(&ss->sprinter, (JOF_OPMODE(lastop) == JOF_XMLNAME) @@ -4192,7 +4179,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb) case JSOP_DUP2: rval = GetStr(ss, ss->top-2); - todo = SprintCString(&ss->sprinter, rval); + todo = ss->sprinter.put(rval); if (todo < 0 || !PushOff(ss, todo, (JSOp) ss->opcodes[ss->top-2])) { return NULL; @@ -4311,7 +4298,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb) rval = GetStr(ss, ss->top-1); saveop = (JSOp) ss->opcodes[ss->top-1]; - todo = SprintCString(&ss->sprinter, rval); + todo = ss->sprinter.put(rval); break; case JSOP_SWAP: @@ -4417,14 +4404,14 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb) Sprint(&ss->sprinter, "%s ", js_new_str); } SprintOpcode(ss, argv[0], lvalpc, pc, todo); - SprintCString(&ss->sprinter, lval); + ss->sprinter.put(lval); for (i = 1; i <= argc; i++) { SprintOpcode(ss, argv[i], argbytecodes[i], pc, todo); if (i < argc) - SprintCString(&ss->sprinter, ", "); + ss->sprinter.put(", "); } - SprintCString(&ss->sprinter, rval); + ss->sprinter.put(rval); cx->free_(argv); cx->free_(argbytecodes); @@ -4666,9 +4653,9 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb) SprintOpcode(ss, lval, lvalpc, pc, todo); if (*xval != '\0') { bool xml = (JOF_OPMODE(lastop) == JOF_XMLNAME); - SprintCString(&ss->sprinter, xml ? "." : "["); + ss->sprinter.put(xml ? "." : "["); SprintOpcode(ss, xval, xvalpc, pc, todo); - SprintCString(&ss->sprinter, xml ? "" : "]"); + ss->sprinter.put(xml ? "" : "]"); } break; @@ -4690,9 +4677,9 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb) &lastlvalpc, &lastrvalpc); todo = ss->sprinter.getOffset(); SprintOpcode(ss, lval, lvalpc, pc, todo); - SprintCString(&ss->sprinter, xml ? "." : "["); + ss->sprinter.put(xml ? "." : "["); SprintOpcode(ss, xval, xvalpc, pc, todo); - SprintCString(&ss->sprinter, xml ? "" : "]"); + ss->sprinter.put(xml ? "" : "]"); Sprint(&ss->sprinter, " %s= ", token); SprintOpcode(ss, rval, rvalpc, pc, todo); break; @@ -4899,7 +4886,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb) las.releaseEarly(); if (!rval) return NULL; - todo = SprintCString(&ss->sprinter, rval); + todo = ss->sprinter.put(rval); cx->free_((void *)rval); break; } @@ -4923,12 +4910,12 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb) return NULL; } sprint_string: - todo = SprintString(&ss->sprinter, str); + todo = ss->sprinter.putString(str); break; case JSOP_CALLEE: JS_ASSERT(jp->fun && jp->fun->atom); - todo = SprintString(&ss->sprinter, jp->fun->atom); + todo = ss->sprinter.putString(jp->fun->atom); break; case JSOP_OBJECT: @@ -5140,7 +5127,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb) goto do_function; case JSOP_HOLE: - todo = SprintPut(&ss->sprinter, "", 0); + todo = ss->sprinter.put("", 0); break; case JSOP_NEWINIT: @@ -5151,10 +5138,10 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb) todo = ss->sprinter.getOffset(); if (i == JSProto_Array) { ++ss->inArrayInit; - if (SprintCString(&ss->sprinter, "[") < 0) + if (ss->sprinter.put("[") < 0) return NULL; } else { - if (SprintCString(&ss->sprinter, "{") < 0) + if (ss->sprinter.put("{") < 0) return NULL; } break; @@ -5164,7 +5151,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb) { todo = ss->sprinter.getOffset(); ++ss->inArrayInit; - if (SprintCString(&ss->sprinter, "[") < 0) + if (ss->sprinter.put("[") < 0) return NULL; break; } @@ -5172,7 +5159,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb) case JSOP_NEWOBJECT: { todo = ss->sprinter.getOffset(); - if (SprintCString(&ss->sprinter, "{") < 0) + if (ss->sprinter.put("{") < 0) return NULL; break; } @@ -5283,9 +5270,9 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb) case JSOP_ANYNAME: if (pc[JSOP_ANYNAME_LENGTH] == JSOP_TOATTRNAME) { len += JSOP_TOATTRNAME_LENGTH; - todo = SprintPut(&ss->sprinter, "@*", 2); + todo = ss->sprinter.put("@*", 2); } else { - todo = SprintPut(&ss->sprinter, "*", 1); + todo = ss->sprinter.put("*", 1); } break; @@ -5393,18 +5380,18 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb) case JSOP_XMLCDATA: LOAD_ATOM(0); - todo = SprintPut(&ss->sprinter, "<![CDATA[", 9); + todo = ss->sprinter.put("<![CDATA[", 9); if (!QuoteString(&ss->sprinter, atom, DONT_ESCAPE)) return NULL; - SprintPut(&ss->sprinter, "]]>", 3); + ss->sprinter.put("]]>", 3); break; case JSOP_XMLCOMMENT: LOAD_ATOM(0); - todo = SprintPut(&ss->sprinter, "<!--", 4); + todo = ss->sprinter.put("<!--", 4); if (!QuoteString(&ss->sprinter, atom, DONT_ESCAPE)) return NULL; - SprintPut(&ss->sprinter, "-->", 3); + ss->sprinter.put("-->", 3); break; case JSOP_XMLPI: @@ -5412,19 +5399,19 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb) rval = JS_strdup(cx, POP_STR()); if (!rval) return NULL; - todo = SprintPut(&ss->sprinter, "<?", 2); + todo = ss->sprinter.put("<?", 2); ok = QuoteString(&ss->sprinter, atom, 0) && (*rval == '\0' || - (SprintPut(&ss->sprinter, " ", 1) >= 0 && - SprintCString(&ss->sprinter, rval))); + (ss->sprinter.put(" ", 1) >= 0 && + ss->sprinter.put(rval))); cx->free_((char *)rval); if (!ok) return NULL; - SprintPut(&ss->sprinter, "?>", 2); + ss->sprinter.put("?>", 2); break; case JSOP_GETFUNNS: - todo = SprintPut(&ss->sprinter, js_function_str, 8); + todo = ss->sprinter.put(js_function_str, 8); break; #endif /* JS_HAS_XML_SUPPORT */ @@ -5673,7 +5660,7 @@ js_DecompileFunction(JSPrinter *jp) LOCAL_ASSERT(*pc == JSOP_POP); pc += JSOP_POP_LENGTH; lval = PopStr(&ss, JSOP_NOP); - todo = SprintCString(&jp->sprinter, lval); + todo = jp->sprinter.put(lval); if (todo < 0) { ok = JS_FALSE; break; diff --git a/js/src/jsopcode.h b/js/src/jsopcode.h index fa6134b53124..e931ab029290 100644 --- a/js/src/jsopcode.h +++ b/js/src/jsopcode.h @@ -504,6 +504,7 @@ class Sprinter * the beginning of this new data */ ptrdiff_t put(const char *s, size_t len); + ptrdiff_t put(const char *s); ptrdiff_t putString(JSString *str); /* Prints a formatted string into the buffer */ @@ -518,15 +519,6 @@ class Sprinter ptrdiff_t getOffsetOf(const char *string) const; }; -extern ptrdiff_t -SprintPut(Sprinter *sp, const char *s, size_t len); - -extern ptrdiff_t -SprintCString(Sprinter *sp, const char *s); - -extern ptrdiff_t -SprintString(Sprinter *sp, JSString *str); - extern ptrdiff_t Sprint(Sprinter *sp, const char *format, ...); diff --git a/js/src/methodjit/StubCalls.cpp b/js/src/methodjit/StubCalls.cpp index 8de50b4f1901..c9a8d113432c 100644 --- a/js/src/methodjit/StubCalls.cpp +++ b/js/src/methodjit/StubCalls.cpp @@ -1665,7 +1665,15 @@ stubs::DelElem(VMFrame &f) void JS_FASTCALL stubs::DefVarOrConst(VMFrame &f, PropertyName *dn) { - if (!DefVarOrConstOperation(f.cx, JSOp(*f.regs.pc), dn, f.fp())) + uintN attrs = JSPROP_ENUMERATE; + if (!f.fp()->isEvalFrame()) + attrs |= JSPROP_PERMANENT; + if (JSOp(*f.regs.pc) == JSOP_DEFCONST) + attrs |= JSPROP_READONLY; + + JSObject &obj = f.fp()->varObj(); + + if (!DefVarOrConstOperation(f.cx, obj, dn, attrs)) THROW(); } diff --git a/js/src/shell/js.cpp b/js/src/shell/js.cpp index 442556f14a9f..dfebcb24af9c 100644 --- a/js/src/shell/js.cpp +++ b/js/src/shell/js.cpp @@ -1447,11 +1447,12 @@ typedef struct JSCountHeapTracer { } JSCountHeapTracer; static void -CountHeapNotify(JSTracer *trc, void *thing, JSGCTraceKind kind) +CountHeapNotify(JSTracer *trc, void **thingp, JSGCTraceKind kind) { JSCountHeapTracer *countTracer; JSDHashEntryStub *entry; JSCountHeapNode *node; + void *thing = *thingp; JS_ASSERT(trc->callback == CountHeapNotify); countTracer = (JSCountHeapTracer *)trc; diff --git a/js/src/shell/jsheaptools.cpp b/js/src/shell/jsheaptools.cpp index eda952c94ea5..04ed84d0c729 100644 --- a/js/src/shell/jsheaptools.cpp +++ b/js/src/shell/jsheaptools.cpp @@ -232,7 +232,7 @@ class HeapReverser : public JSTracer { * A stack of work items. We represent the stack explicitly to avoid * overflowing the C++ stack when traversing long chains of objects. */ - Vector<Child> work; + Vector<Child> work; /* When traverseEdge is called, the Cell and kind at which the edge originated. */ void *parent; @@ -249,19 +249,17 @@ class HeapReverser : public JSTracer { bool traversalStatus; /* Static member function wrapping 'traverseEdge'. */ - static void traverseEdgeWithThis(JSTracer *tracer, void *cell, JSGCTraceKind kind) { + static void traverseEdgeWithThis(JSTracer *tracer, void **thingp, JSGCTraceKind kind) { HeapReverser *reverser = static_cast<HeapReverser *>(tracer); - reverser->traversalStatus = reverser->traverseEdge(cell, kind); + reverser->traversalStatus = reverser->traverseEdge(*thingp, kind); } /* Return a jsval representing a node, if possible; otherwise, return JSVAL_VOID. */ jsval nodeToValue(void *cell, int kind) { - if (kind == JSTRACE_OBJECT) { - JSObject *object = static_cast<JSObject *>(cell); - return OBJECT_TO_JSVAL(object); - } else { + if (kind != JSTRACE_OBJECT) return JSVAL_VOID; - } + JSObject *object = static_cast<JSObject *>(cell); + return OBJECT_TO_JSVAL(object); } }; diff --git a/js/src/tests/ecma_5/String/string-upper-lower-mapping.js b/js/src/tests/ecma_5/String/string-upper-lower-mapping.js index 93a7deef4617..35ea051c0115 100644 --- a/js/src/tests/ecma_5/String/string-upper-lower-mapping.js +++ b/js/src/tests/ecma_5/String/string-upper-lower-mapping.js @@ -619,7 +619,7 @@ var mapping = [ [0x194, 0x263], /* LATIN SMALL LETTER GAMMA */ [0x264, 0x264], /* LATIN SMALL LETTER RAMS HORN (LATIN SMALL LETTER BABY GAMMA) */ [0xa78d, 0x265], /* LATIN SMALL LETTER TURNED H */ - [0x266, 0x266], /* LATIN SMALL LETTER H WITH HOOK (LATIN SMALL LETTER H HOOK) */ + [0xa7aa, 0x266], /* LATIN SMALL LETTER H WITH HOOK (LATIN SMALL LETTER H HOOK) */ [0x267, 0x267], /* LATIN SMALL LETTER HENG WITH HOOK (LATIN SMALL LETTER HENG HOOK) */ [0x197, 0x268], /* LATIN SMALL LETTER I WITH STROKE (LATIN SMALL LETTER BARRED I) */ [0x196, 0x269], /* LATIN SMALL LETTER IOTA */ @@ -1428,7 +1428,7 @@ var mapping = [ [0x58c, 0x58c], [0x58d, 0x58d], [0x58e, 0x58e], - [0x58f, 0x58f], + [0x58f, 0x58f], /* ARMENIAN DRAM SIGN */ [0x590, 0x590], [0x591, 0x591], /* HEBREW ACCENT ETNAHTA */ [0x592, 0x592], /* HEBREW ACCENT SEGOL */ @@ -1545,7 +1545,7 @@ var mapping = [ [0x601, 0x601], /* ARABIC SIGN SANAH */ [0x602, 0x602], /* ARABIC FOOTNOTE MARKER */ [0x603, 0x603], /* ARABIC SIGN SAFHA */ - [0x604, 0x604], + [0x604, 0x604], /* ARABIC SIGN SAMVAT */ [0x605, 0x605], [0x606, 0x606], /* ARABIC-INDIC CUBE ROOT */ [0x607, 0x607], /* ARABIC-INDIC FOURTH ROOT */ @@ -2213,19 +2213,19 @@ var mapping = [ [0x89d, 0x89d], [0x89e, 0x89e], [0x89f, 0x89f], - [0x8a0, 0x8a0], + [0x8a0, 0x8a0], /* ARABIC LETTER BEH WITH SMALL V BELOW */ [0x8a1, 0x8a1], - [0x8a2, 0x8a2], - [0x8a3, 0x8a3], - [0x8a4, 0x8a4], - [0x8a5, 0x8a5], - [0x8a6, 0x8a6], - [0x8a7, 0x8a7], - [0x8a8, 0x8a8], - [0x8a9, 0x8a9], - [0x8aa, 0x8aa], - [0x8ab, 0x8ab], - [0x8ac, 0x8ac], + [0x8a2, 0x8a2], /* ARABIC LETTER JEEM WITH TWO DOTS ABOVE */ + [0x8a3, 0x8a3], /* ARABIC LETTER TAH WITH TWO DOTS ABOVE */ + [0x8a4, 0x8a4], /* ARABIC LETTER FEH WITH DOT BELOW AND THREE DOTS ABOVE */ + [0x8a5, 0x8a5], /* ARABIC LETTER QAF WITH DOT BELOW */ + [0x8a6, 0x8a6], /* ARABIC LETTER LAM WITH DOUBLE BAR */ + [0x8a7, 0x8a7], /* ARABIC LETTER MEEM WITH THREE DOTS ABOVE */ + [0x8a8, 0x8a8], /* ARABIC LETTER YEH WITH TWO DOTS BELOW AND HAMZA ABOVE */ + [0x8a9, 0x8a9], /* ARABIC LETTER YEH WITH TWO DOTS BELOW AND DOT ABOVE */ + [0x8aa, 0x8aa], /* ARABIC LETTER REH WITH LOOP */ + [0x8ab, 0x8ab], /* ARABIC LETTER WAW WITH DOT WITHIN */ + [0x8ac, 0x8ac], /* ARABIC LETTER ROHINGYA YEH */ [0x8ad, 0x8ad], [0x8ae, 0x8ae], [0x8af, 0x8af], @@ -2281,33 +2281,33 @@ var mapping = [ [0x8e1, 0x8e1], [0x8e2, 0x8e2], [0x8e3, 0x8e3], - [0x8e4, 0x8e4], - [0x8e5, 0x8e5], - [0x8e6, 0x8e6], - [0x8e7, 0x8e7], - [0x8e8, 0x8e8], - [0x8e9, 0x8e9], - [0x8ea, 0x8ea], - [0x8eb, 0x8eb], - [0x8ec, 0x8ec], - [0x8ed, 0x8ed], - [0x8ee, 0x8ee], - [0x8ef, 0x8ef], - [0x8f0, 0x8f0], - [0x8f1, 0x8f1], - [0x8f2, 0x8f2], - [0x8f3, 0x8f3], - [0x8f4, 0x8f4], - [0x8f5, 0x8f5], - [0x8f6, 0x8f6], - [0x8f7, 0x8f7], - [0x8f8, 0x8f8], - [0x8f9, 0x8f9], - [0x8fa, 0x8fa], - [0x8fb, 0x8fb], - [0x8fc, 0x8fc], - [0x8fd, 0x8fd], - [0x8fe, 0x8fe], + [0x8e4, 0x8e4], /* ARABIC CURLY FATHA */ + [0x8e5, 0x8e5], /* ARABIC CURLY DAMMA */ + [0x8e6, 0x8e6], /* ARABIC CURLY KASRA */ + [0x8e7, 0x8e7], /* ARABIC CURLY FATHATAN */ + [0x8e8, 0x8e8], /* ARABIC CURLY DAMMATAN */ + [0x8e9, 0x8e9], /* ARABIC CURLY KASRATAN */ + [0x8ea, 0x8ea], /* ARABIC TONE ONE DOT ABOVE */ + [0x8eb, 0x8eb], /* ARABIC TONE TWO DOTS ABOVE */ + [0x8ec, 0x8ec], /* ARABIC TONE LOOP ABOVE */ + [0x8ed, 0x8ed], /* ARABIC TONE ONE DOT BELOW */ + [0x8ee, 0x8ee], /* ARABIC TONE TWO DOTS BELOW */ + [0x8ef, 0x8ef], /* ARABIC TONE LOOP BELOW */ + [0x8f0, 0x8f0], /* ARABIC OPEN FATHATAN */ + [0x8f1, 0x8f1], /* ARABIC OPEN DAMMATAN */ + [0x8f2, 0x8f2], /* ARABIC OPEN KASRATAN */ + [0x8f3, 0x8f3], /* ARABIC SMALL HIGH WAW */ + [0x8f4, 0x8f4], /* ARABIC FATHA WITH RING */ + [0x8f5, 0x8f5], /* ARABIC FATHA WITH DOT ABOVE */ + [0x8f6, 0x8f6], /* ARABIC KASRA WITH DOT BELOW */ + [0x8f7, 0x8f7], /* ARABIC LEFT ARROWHEAD ABOVE */ + [0x8f8, 0x8f8], /* ARABIC RIGHT ARROWHEAD ABOVE */ + [0x8f9, 0x8f9], /* ARABIC LEFT ARROWHEAD BELOW */ + [0x8fa, 0x8fa], /* ARABIC RIGHT ARROWHEAD BELOW */ + [0x8fb, 0x8fb], /* ARABIC DOUBLE RIGHT ARROWHEAD ABOVE */ + [0x8fc, 0x8fc], /* ARABIC DOUBLE RIGHT ARROWHEAD ABOVE WITH DOT */ + [0x8fd, 0x8fd], /* ARABIC RIGHT ARROWHEAD ABOVE WITH DOT */ + [0x8fe, 0x8fe], /* ARABIC DAMMA WITH DOT */ [0x8ff, 0x8ff], [0x900, 0x900], /* DEVANAGARI SIGN INVERTED CANDRABINDU */ [0x901, 0x901], /* DEVANAGARI SIGN CANDRABINDU */ @@ -2805,7 +2805,7 @@ var mapping = [ [0xaed, 0xaed], /* GUJARATI DIGIT SEVEN */ [0xaee, 0xaee], /* GUJARATI DIGIT EIGHT */ [0xaef, 0xaef], /* GUJARATI DIGIT NINE */ - [0xaf0, 0xaf0], + [0xaf0, 0xaf0], /* GUJARATI ABBREVIATION SIGN */ [0xaf1, 0xaf1], /* GUJARATI RUPEE SIGN */ [0xaf2, 0xaf2], [0xaf3, 0xaf3], @@ -3811,8 +3811,8 @@ var mapping = [ [0xedb, 0xedb], [0xedc, 0xedc], /* LAO HO NO */ [0xedd, 0xedd], /* LAO HO MO */ - [0xede, 0xede], - [0xedf, 0xedf], + [0xede, 0xede], /* LAO LETTER KHMU GO */ + [0xedf, 0xedf], /* LAO LETTER KHMU NYO */ [0xee0, 0xee0], [0xee1, 0xee1], [0xee2, 0xee2], @@ -4300,13 +4300,13 @@ var mapping = [ [0x10c4, 0x2d24], /* GEORGIAN CAPITAL LETTER HAR */ [0x10c5, 0x2d25], /* GEORGIAN CAPITAL LETTER HOE */ [0x10c6, 0x10c6], - [0x10c7, 0x10c7], + [0x10c7, 0x2d27], /* GEORGIAN CAPITAL LETTER YN */ [0x10c8, 0x10c8], [0x10c9, 0x10c9], [0x10ca, 0x10ca], [0x10cb, 0x10cb], [0x10cc, 0x10cc], - [0x10cd, 0x10cd], + [0x10cd, 0x2d2d], /* GEORGIAN CAPITAL LETTER AEN */ [0x10ce, 0x10ce], [0x10cf, 0x10cf], [0x10d0, 0x10d0], /* GEORGIAN LETTER AN (GEORGIAN SMALL LETTER AN) */ @@ -4354,9 +4354,9 @@ var mapping = [ [0x10fa, 0x10fa], /* GEORGIAN LETTER AIN */ [0x10fb, 0x10fb], /* GEORGIAN PARAGRAPH SEPARATOR */ [0x10fc, 0x10fc], /* MODIFIER LETTER GEORGIAN NAR */ - [0x10fd, 0x10fd], - [0x10fe, 0x10fe], - [0x10ff, 0x10ff], + [0x10fd, 0x10fd], /* GEORGIAN LETTER AEN */ + [0x10fe, 0x10fe], /* GEORGIAN LETTER HARD SIGN */ + [0x10ff, 0x10ff], /* GEORGIAN LETTER LABIAL SIGN */ [0x1100, 0x1100], /* HANGUL CHOSEONG KIYEOK */ [0x1101, 0x1101], /* HANGUL CHOSEONG SSANGKIYEOK */ [0x1102, 0x1102], /* HANGUL CHOSEONG NIEUN */ @@ -7088,9 +7088,9 @@ var mapping = [ [0x1ba8, 0x1ba8], /* SUNDANESE VOWEL SIGN PAMEPET */ [0x1ba9, 0x1ba9], /* SUNDANESE VOWEL SIGN PANEULEUNG */ [0x1baa, 0x1baa], /* SUNDANESE SIGN PAMAAEH */ - [0x1bab, 0x1bab], - [0x1bac, 0x1bac], - [0x1bad, 0x1bad], + [0x1bab, 0x1bab], /* SUNDANESE SIGN VIRAMA */ + [0x1bac, 0x1bac], /* SUNDANESE CONSONANT SIGN PASANGAN MA */ + [0x1bad, 0x1bad], /* SUNDANESE CONSONANT SIGN PASANGAN WA */ [0x1bae, 0x1bae], /* SUNDANESE LETTER KHA */ [0x1baf, 0x1baf], /* SUNDANESE LETTER SYA */ [0x1bb0, 0x1bb0], /* SUNDANESE DIGIT ZERO */ @@ -7103,12 +7103,12 @@ var mapping = [ [0x1bb7, 0x1bb7], /* SUNDANESE DIGIT SEVEN */ [0x1bb8, 0x1bb8], /* SUNDANESE DIGIT EIGHT */ [0x1bb9, 0x1bb9], /* SUNDANESE DIGIT NINE */ - [0x1bba, 0x1bba], - [0x1bbb, 0x1bbb], - [0x1bbc, 0x1bbc], - [0x1bbd, 0x1bbd], - [0x1bbe, 0x1bbe], - [0x1bbf, 0x1bbf], + [0x1bba, 0x1bba], /* SUNDANESE AVAGRAHA */ + [0x1bbb, 0x1bbb], /* SUNDANESE LETTER REU */ + [0x1bbc, 0x1bbc], /* SUNDANESE LETTER LEU */ + [0x1bbd, 0x1bbd], /* SUNDANESE LETTER BHA */ + [0x1bbe, 0x1bbe], /* SUNDANESE LETTER FINAL K */ + [0x1bbf, 0x1bbf], /* SUNDANESE LETTER FINAL M */ [0x1bc0, 0x1bc0], /* BATAK LETTER A */ [0x1bc1, 0x1bc1], /* BATAK LETTER SIMALUNGUN A */ [0x1bc2, 0x1bc2], /* BATAK LETTER HA */ @@ -7365,14 +7365,14 @@ var mapping = [ [0x1cbd, 0x1cbd], [0x1cbe, 0x1cbe], [0x1cbf, 0x1cbf], - [0x1cc0, 0x1cc0], - [0x1cc1, 0x1cc1], - [0x1cc2, 0x1cc2], - [0x1cc3, 0x1cc3], - [0x1cc4, 0x1cc4], - [0x1cc5, 0x1cc5], - [0x1cc6, 0x1cc6], - [0x1cc7, 0x1cc7], + [0x1cc0, 0x1cc0], /* SUNDANESE PUNCTUATION BINDU SURYA */ + [0x1cc1, 0x1cc1], /* SUNDANESE PUNCTUATION BINDU PANGLONG */ + [0x1cc2, 0x1cc2], /* SUNDANESE PUNCTUATION BINDU PURNAMA */ + [0x1cc3, 0x1cc3], /* SUNDANESE PUNCTUATION BINDU CAKRA */ + [0x1cc4, 0x1cc4], /* SUNDANESE PUNCTUATION BINDU LEU SATANGA */ + [0x1cc5, 0x1cc5], /* SUNDANESE PUNCTUATION BINDU KA SATANGA */ + [0x1cc6, 0x1cc6], /* SUNDANESE PUNCTUATION BINDU DA SATANGA */ + [0x1cc7, 0x1cc7], /* SUNDANESE PUNCTUATION BINDU BA SATANGA */ [0x1cc8, 0x1cc8], [0x1cc9, 0x1cc9], [0x1cca, 0x1cca], @@ -7416,10 +7416,10 @@ var mapping = [ [0x1cf0, 0x1cf0], /* VEDIC SIGN RTHANG LONG ANUSVARA */ [0x1cf1, 0x1cf1], /* VEDIC SIGN ANUSVARA UBHAYATO MUKHA */ [0x1cf2, 0x1cf2], /* VEDIC SIGN ARDHAVISARGA */ - [0x1cf3, 0x1cf3], - [0x1cf4, 0x1cf4], - [0x1cf5, 0x1cf5], - [0x1cf6, 0x1cf6], + [0x1cf3, 0x1cf3], /* VEDIC SIGN ROTATED ARDHAVISARGA */ + [0x1cf4, 0x1cf4], /* VEDIC TONE CANDRA ABOVE */ + [0x1cf5, 0x1cf5], /* VEDIC SIGN JIHVAMULIYA */ + [0x1cf6, 0x1cf6], /* VEDIC SIGN UPADHMANIYA */ [0x1cf7, 0x1cf7], [0x1cf8, 0x1cf8], [0x1cf9, 0x1cf9], @@ -10192,9 +10192,9 @@ var mapping = [ [0x27c8, 0x27c8], /* REVERSE SOLIDUS PRECEDING SUBSET */ [0x27c9, 0x27c9], /* SUPERSET PRECEDING SOLIDUS */ [0x27ca, 0x27ca], /* VERTICAL BAR WITH HORIZONTAL STROKE */ - [0x27cb, 0x27cb], + [0x27cb, 0x27cb], /* MATHEMATICAL RISING DIAGONAL */ [0x27cc, 0x27cc], /* LONG DIVISION */ - [0x27cd, 0x27cd], + [0x27cd, 0x27cd], /* MATHEMATICAL FALLING DIAGONAL */ [0x27ce, 0x27ce], /* SQUARED LOGICAL AND */ [0x27cf, 0x27cf], /* SQUARED LOGICAL OR */ [0x27d0, 0x27d0], /* WHITE DIAMOND WITH CENTRED DOT */ @@ -11511,8 +11511,8 @@ var mapping = [ [0x2cef, 0x2cef], /* COPTIC COMBINING NI ABOVE */ [0x2cf0, 0x2cf0], /* COPTIC COMBINING SPIRITUS ASPER */ [0x2cf1, 0x2cf1], /* COPTIC COMBINING SPIRITUS LENIS */ - [0x2cf2, 0x2cf2], - [0x2cf3, 0x2cf3], + [0x2cf2, 0x2cf3], /* COPTIC CAPITAL LETTER BOHAIRIC KHEI */ + [0x2cf2, 0x2cf3], /* COPTIC SMALL LETTER BOHAIRIC KHEI */ [0x2cf4, 0x2cf4], [0x2cf5, 0x2cf5], [0x2cf6, 0x2cf6], @@ -11564,13 +11564,13 @@ var mapping = [ [0x10c4, 0x2d24], /* GEORGIAN SMALL LETTER HAR */ [0x10c5, 0x2d25], /* GEORGIAN SMALL LETTER HOE */ [0x2d26, 0x2d26], - [0x2d27, 0x2d27], + [0x10c7, 0x2d27], /* GEORGIAN SMALL LETTER YN */ [0x2d28, 0x2d28], [0x2d29, 0x2d29], [0x2d2a, 0x2d2a], [0x2d2b, 0x2d2b], [0x2d2c, 0x2d2c], - [0x2d2d, 0x2d2d], + [0x10cd, 0x2d2d], /* GEORGIAN SMALL LETTER AEN */ [0x2d2e, 0x2d2e], [0x2d2f, 0x2d2f], [0x2d30, 0x2d30], /* TIFINAGH LETTER YA */ @@ -11627,8 +11627,8 @@ var mapping = [ [0x2d63, 0x2d63], /* TIFINAGH LETTER YAZ */ [0x2d64, 0x2d64], /* TIFINAGH LETTER TAWELLEMET YAZ */ [0x2d65, 0x2d65], /* TIFINAGH LETTER YAZZ */ - [0x2d66, 0x2d66], - [0x2d67, 0x2d67], + [0x2d66, 0x2d66], /* TIFINAGH LETTER YE */ + [0x2d67, 0x2d67], /* TIFINAGH LETTER YO */ [0x2d68, 0x2d68], [0x2d69, 0x2d69], [0x2d6a, 0x2d6a], @@ -11831,16 +11831,16 @@ var mapping = [ [0x2e2f, 0x2e2f], /* VERTICAL TILDE */ [0x2e30, 0x2e30], /* RING POINT */ [0x2e31, 0x2e31], /* WORD SEPARATOR MIDDLE DOT */ - [0x2e32, 0x2e32], - [0x2e33, 0x2e33], - [0x2e34, 0x2e34], - [0x2e35, 0x2e35], - [0x2e36, 0x2e36], - [0x2e37, 0x2e37], - [0x2e38, 0x2e38], - [0x2e39, 0x2e39], - [0x2e3a, 0x2e3a], - [0x2e3b, 0x2e3b], + [0x2e32, 0x2e32], /* TURNED COMMA */ + [0x2e33, 0x2e33], /* RAISED DOT */ + [0x2e34, 0x2e34], /* RAISED COMMA */ + [0x2e35, 0x2e35], /* TURNED SEMICOLON */ + [0x2e36, 0x2e36], /* DAGGER WITH LEFT GUARD */ + [0x2e37, 0x2e37], /* DAGGER WITH RIGHT GUARD */ + [0x2e38, 0x2e38], /* TURNED DAGGER */ + [0x2e39, 0x2e39], /* TOP HALF SECTION SIGN */ + [0x2e3a, 0x2e3a], /* TWO-EM DASH */ + [0x2e3b, 0x2e3b], /* THREE-EM DASH */ [0x2e3c, 0x2e3c], [0x2e3d, 0x2e3d], [0x2e3e, 0x2e3e], @@ -40913,7 +40913,7 @@ var mapping = [ [0x9fc9, 0x9fc9], /* CJK Ideograph */ [0x9fca, 0x9fca], /* CJK Ideograph */ [0x9fcb, 0x9fcb], /* CJK Ideograph */ - [0x9fcc, 0x9fcc], + [0x9fcc, 0x9fcc], /* CJK Ideograph */ [0x9fcd, 0x9fcd], [0x9fce, 0x9fce], [0x9fcf, 0x9fcf], @@ -42617,14 +42617,14 @@ var mapping = [ [0xa671, 0xa671], /* COMBINING CYRILLIC HUNDRED MILLIONS SIGN */ [0xa672, 0xa672], /* COMBINING CYRILLIC THOUSAND MILLIONS SIGN */ [0xa673, 0xa673], /* SLAVONIC ASTERISK */ - [0xa674, 0xa674], - [0xa675, 0xa675], - [0xa676, 0xa676], - [0xa677, 0xa677], - [0xa678, 0xa678], - [0xa679, 0xa679], - [0xa67a, 0xa67a], - [0xa67b, 0xa67b], + [0xa674, 0xa674], /* COMBINING CYRILLIC LETTER UKRAINIAN IE */ + [0xa675, 0xa675], /* COMBINING CYRILLIC LETTER I */ + [0xa676, 0xa676], /* COMBINING CYRILLIC LETTER YI */ + [0xa677, 0xa677], /* COMBINING CYRILLIC LETTER U */ + [0xa678, 0xa678], /* COMBINING CYRILLIC LETTER HARD SIGN */ + [0xa679, 0xa679], /* COMBINING CYRILLIC LETTER YERU */ + [0xa67a, 0xa67a], /* COMBINING CYRILLIC LETTER SOFT SIGN */ + [0xa67b, 0xa67b], /* COMBINING CYRILLIC LETTER OMEGA */ [0xa67c, 0xa67c], /* COMBINING CYRILLIC KAVYKA */ [0xa67d, 0xa67d], /* COMBINING CYRILLIC PAYEROK */ [0xa67e, 0xa67e], /* CYRILLIC KAVYKA */ @@ -42660,7 +42660,7 @@ var mapping = [ [0xa69c, 0xa69c], [0xa69d, 0xa69d], [0xa69e, 0xa69e], - [0xa69f, 0xa69f], + [0xa69f, 0xa69f], /* COMBINING CYRILLIC LETTER IOTIFIED E */ [0xa6a0, 0xa6a0], /* BAMUM LETTER A */ [0xa6a1, 0xa6a1], /* BAMUM LETTER KA */ [0xa6a2, 0xa6a2], /* BAMUM LETTER U */ @@ -42903,8 +42903,8 @@ var mapping = [ [0xa78f, 0xa78f], [0xa790, 0xa791], /* LATIN CAPITAL LETTER N WITH DESCENDER */ [0xa790, 0xa791], /* LATIN SMALL LETTER N WITH DESCENDER */ - [0xa792, 0xa792], - [0xa793, 0xa793], + [0xa792, 0xa793], /* LATIN CAPITAL LETTER C WITH BAR */ + [0xa792, 0xa793], /* LATIN SMALL LETTER C WITH BAR */ [0xa794, 0xa794], [0xa795, 0xa795], [0xa796, 0xa796], @@ -42927,7 +42927,7 @@ var mapping = [ [0xa7a6, 0xa7a7], /* LATIN SMALL LETTER R WITH OBLIQUE STROKE */ [0xa7a8, 0xa7a9], /* LATIN CAPITAL LETTER S WITH OBLIQUE STROKE */ [0xa7a8, 0xa7a9], /* LATIN SMALL LETTER S WITH OBLIQUE STROKE */ - [0xa7aa, 0xa7aa], + [0xa7aa, 0x266], /* LATIN CAPITAL LETTER H WITH HOOK */ [0xa7ab, 0xa7ab], [0xa7ac, 0xa7ac], [0xa7ad, 0xa7ad], @@ -43005,8 +43005,8 @@ var mapping = [ [0xa7f5, 0xa7f5], [0xa7f6, 0xa7f6], [0xa7f7, 0xa7f7], - [0xa7f8, 0xa7f8], - [0xa7f9, 0xa7f9], + [0xa7f8, 0xa7f8], /* MODIFIER LETTER CAPITAL H WITH STROKE */ + [0xa7f9, 0xa7f9], /* MODIFIER LETTER SMALL LIGATURE OE */ [0xa7fa, 0xa7fa], /* LATIN LETTER SMALL CAPITAL TURNED M */ [0xa7fb, 0xa7fb], /* LATIN EPIGRAPHIC LETTER REVERSED F */ [0xa7fc, 0xa7fc], /* LATIN EPIGRAPHIC LETTER REVERSED P */ @@ -43749,29 +43749,29 @@ var mapping = [ [0xaadd, 0xaadd], /* TAI VIET SYMBOL SAM */ [0xaade, 0xaade], /* TAI VIET SYMBOL HO HOI */ [0xaadf, 0xaadf], /* TAI VIET SYMBOL KOI KOI */ - [0xaae0, 0xaae0], - [0xaae1, 0xaae1], - [0xaae2, 0xaae2], - [0xaae3, 0xaae3], - [0xaae4, 0xaae4], - [0xaae5, 0xaae5], - [0xaae6, 0xaae6], - [0xaae7, 0xaae7], - [0xaae8, 0xaae8], - [0xaae9, 0xaae9], - [0xaaea, 0xaaea], - [0xaaeb, 0xaaeb], - [0xaaec, 0xaaec], - [0xaaed, 0xaaed], - [0xaaee, 0xaaee], - [0xaaef, 0xaaef], - [0xaaf0, 0xaaf0], - [0xaaf1, 0xaaf1], - [0xaaf2, 0xaaf2], - [0xaaf3, 0xaaf3], - [0xaaf4, 0xaaf4], - [0xaaf5, 0xaaf5], - [0xaaf6, 0xaaf6], + [0xaae0, 0xaae0], /* MEETEI MAYEK LETTER E */ + [0xaae1, 0xaae1], /* MEETEI MAYEK LETTER O */ + [0xaae2, 0xaae2], /* MEETEI MAYEK LETTER CHA */ + [0xaae3, 0xaae3], /* MEETEI MAYEK LETTER NYA */ + [0xaae4, 0xaae4], /* MEETEI MAYEK LETTER TTA */ + [0xaae5, 0xaae5], /* MEETEI MAYEK LETTER TTHA */ + [0xaae6, 0xaae6], /* MEETEI MAYEK LETTER DDA */ + [0xaae7, 0xaae7], /* MEETEI MAYEK LETTER DDHA */ + [0xaae8, 0xaae8], /* MEETEI MAYEK LETTER NNA */ + [0xaae9, 0xaae9], /* MEETEI MAYEK LETTER SHA */ + [0xaaea, 0xaaea], /* MEETEI MAYEK LETTER SSA */ + [0xaaeb, 0xaaeb], /* MEETEI MAYEK VOWEL SIGN II */ + [0xaaec, 0xaaec], /* MEETEI MAYEK VOWEL SIGN UU */ + [0xaaed, 0xaaed], /* MEETEI MAYEK VOWEL SIGN AAI */ + [0xaaee, 0xaaee], /* MEETEI MAYEK VOWEL SIGN AU */ + [0xaaef, 0xaaef], /* MEETEI MAYEK VOWEL SIGN AAU */ + [0xaaf0, 0xaaf0], /* MEETEI MAYEK CHEIKHAN */ + [0xaaf1, 0xaaf1], /* MEETEI MAYEK AHANG KHUDAM */ + [0xaaf2, 0xaaf2], /* MEETEI MAYEK ANJI */ + [0xaaf3, 0xaaf3], /* MEETEI MAYEK SYLLABLE REPETITION MARK */ + [0xaaf4, 0xaaf4], /* MEETEI MAYEK WORD REPETITION MARK */ + [0xaaf5, 0xaaf5], /* MEETEI MAYEK VOWEL SIGN VISARGA */ + [0xaaf6, 0xaaf6], /* MEETEI MAYEK VIRAMA */ [0xaaf7, 0xaaf7], [0xaaf8, 0xaaf8], [0xaaf9, 0xaaf9], @@ -64051,8 +64051,8 @@ var mapping = [ [0xfa2b, 0xfa2b], /* CJK COMPATIBILITY IDEOGRAPH-FA2B */ [0xfa2c, 0xfa2c], /* CJK COMPATIBILITY IDEOGRAPH-FA2C */ [0xfa2d, 0xfa2d], /* CJK COMPATIBILITY IDEOGRAPH-FA2D */ - [0xfa2e, 0xfa2e], - [0xfa2f, 0xfa2f], + [0xfa2e, 0xfa2e], /* CJK COMPATIBILITY IDEOGRAPH-FA2E */ + [0xfa2f, 0xfa2f], /* CJK COMPATIBILITY IDEOGRAPH-FA2F */ [0xfa30, 0xfa30], /* CJK COMPATIBILITY IDEOGRAPH-FA30 */ [0xfa31, 0xfa31], /* CJK COMPATIBILITY IDEOGRAPH-FA31 */ [0xfa32, 0xfa32], /* CJK COMPATIBILITY IDEOGRAPH-FA32 */ diff --git a/js/src/tests/js1_5/Regress/regress-343713.js b/js/src/tests/js1_5/Regress/regress-343713.js index 0b2082a32728..1320a7774a83 100644 --- a/js/src/tests/js1_5/Regress/regress-343713.js +++ b/js/src/tests/js1_5/Regress/regress-343713.js @@ -37,7 +37,7 @@ //----------------------------------------------------------------------------- var BUGNUMBER = 343713; -var summary = 'Do not JS_Assert with nested function evaluation'; +var summary = 'Do not assert with nested function evaluation'; var actual = 'No Crash'; var expect = 'No Crash'; diff --git a/js/src/vm/Unicode.cpp b/js/src/vm/Unicode.cpp index 55e335752416..8d92a0678262 100644 --- a/js/src/vm/Unicode.cpp +++ b/js/src/vm/Unicode.cpp @@ -111,6 +111,7 @@ const CharacterInfo js_charinfo[] = { {65333, 0, 2}, {65329, 0, 2}, {42893, 613, 10}, + {42922, 614, 10}, {65327, 0, 2}, {65325, 0, 2}, {10743, 0, 2}, @@ -198,23 +199,23 @@ const CharacterInfo js_charinfo[] = { const uint8_t index1[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, - 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 34, - 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, - 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 26, 26, 26, 26, - 26, 67, 68, 69, 70, 71, 72, 73, 74, 26, 26, 26, 26, 26, 26, 26, 26, 75, - 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 34, - 93, 94, 95, 96, 97, 98, 34, 99, 26, 100, 26, 101, 102, 102, 103, 102, 104, 105, - 106, 107, 108, 109, 110, 111, 112, 113, 114, 34, 34, 34, 34, 34, 34, 34, 34, 34, - 34, 34, 115, 116, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, - 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 117, 118, 102, 119, - 120, 121, 122, 123, 124, 34, 34, 34, 34, 34, 34, 34, 125, 74, 126, 127, 128, 26, - 129, 130, 34, 34, 34, 34, 34, 34, 34, 34, 26, 26, 26, 26, 26, 26, 26, 26, + 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, + 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, + 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 26, 26, 26, 26, + 26, 68, 69, 70, 71, 72, 73, 74, 75, 26, 26, 26, 26, 26, 26, 26, 26, 76, + 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, + 95, 96, 97, 98, 99, 100, 94, 101, 26, 102, 26, 103, 104, 104, 105, 104, 106, 107, + 108, 109, 110, 111, 112, 113, 114, 115, 116, 94, 94, 94, 94, 94, 94, 94, 94, 94, + 94, 94, 117, 118, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, + 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 119, 120, 104, 121, + 122, 123, 124, 125, 126, 94, 94, 94, 94, 94, 94, 94, 127, 75, 128, 129, 130, 26, + 131, 132, 94, 94, 94, 94, 94, 94, 94, 94, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 85, 34, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 86, 94, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, @@ -232,10 +233,10 @@ const uint8_t index1[] = { 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 131, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 132, 133, 26, 26, 26, 26, 134, 135, - 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, - 154, 34, 34, 155, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 133, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 133, 134, 26, 26, 26, 26, 135, 136, + 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, + 155, 94, 94, 156, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, @@ -244,16 +245,16 @@ const uint8_t index1[] = { 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 156, 157, - 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, - 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, - 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, - 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, - 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, - 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, - 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, - 34, 34, 34, 34, 34, 34, 26, 26, 26, 26, 158, 158, 26, 159, 160, 161, 162, 163, - 26, 26, 26, 26, 164, 165, 166, 167, 168, 169, 26, 170, 171, 172, 173, 174, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 157, 158, + 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, + 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, + 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, + 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, + 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, + 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, + 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, + 94, 94, 94, 94, 94, 94, 26, 26, 26, 26, 26, 159, 26, 160, 161, 162, 163, 164, + 26, 26, 26, 26, 165, 166, 167, 168, 169, 170, 26, 171, 172, 173, 174, 175, }; const uint8_t index2[] = { @@ -291,9 +292,9 @@ const uint8_t index2[] = { 8, 9, 8, 9, 8, 9, 5, 5, 5, 5, 5, 5, 40, 8, 9, 41, 42, 43, 43, 8, 9, 44, 45, 46, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 47, 48, 49, 50, 51, 5, 52, 52, 5, 53, 5, 54, 5, 5, 5, 5, 52, 5, 5, 55, - 5, 56, 5, 5, 57, 58, 5, 59, 5, 5, 5, 58, 5, 60, 61, 5, 5, 62, - 5, 5, 5, 5, 5, 5, 5, 63, 5, 5, 64, 5, 5, 64, 5, 5, 5, 5, - 64, 65, 66, 66, 67, 5, 5, 5, 5, 5, 68, 5, 5, 5, 5, 5, 5, 5, + 5, 56, 57, 5, 58, 59, 5, 60, 5, 5, 5, 59, 5, 61, 62, 5, 5, 63, + 5, 5, 5, 5, 5, 5, 5, 64, 5, 5, 65, 5, 5, 65, 5, 5, 5, 5, + 65, 66, 67, 67, 68, 5, 5, 5, 5, 5, 69, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, @@ -303,39 +304,39 @@ const uint8_t index2[] = { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 69, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 70, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 8, 9, 8, 9, 5, 0, 8, 9, 0, 0, 5, 27, 27, 27, 0, 0, 0, 0, 0, 0, - 0, 0, 70, 0, 71, 71, 71, 0, 72, 0, 73, 73, 5, 3, 3, 3, 3, 3, + 0, 0, 71, 0, 72, 72, 72, 0, 73, 0, 74, 74, 5, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 74, 75, 75, 75, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 76, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 77, 78, 78, 79, 80, 81, 5, 5, 5, 82, 83, 84, 8, 9, 8, 9, 8, 9, + 3, 3, 3, 3, 75, 76, 76, 76, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 77, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 78, 79, 79, 80, 81, 82, 5, 5, 5, 83, 84, 85, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, - 85, 86, 87, 5, 88, 89, 0, 8, 9, 90, 8, 9, 5, 39, 39, 39, 91, 91, - 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 3, 3, 3, 3, + 86, 87, 88, 5, 89, 90, 0, 8, 9, 91, 8, 9, 5, 39, 39, 39, 92, 92, + 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, - 86, 86, 86, 86, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, + 4, 4, 4, 4, 4, 4, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, + 87, 87, 87, 87, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, - 8, 9, 0, 2, 2, 2, 2, 2, 92, 92, 8, 9, 8, 9, 8, 9, 8, 9, + 8, 9, 0, 2, 2, 2, 2, 2, 93, 93, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, - 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 93, 8, 9, 8, 9, 8, 9, 8, - 9, 8, 9, 8, 9, 8, 9, 94, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, + 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 94, 8, 9, 8, 9, 8, 9, 8, + 9, 8, 9, 8, 9, 8, 9, 95, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, - 8, 9, 8, 9, 8, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 95, 95, 95, - 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, - 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 0, - 0, 5, 0, 0, 0, 0, 0, 0, 0, 96, 96, 96, 96, 96, 96, 96, 96, 96, + 8, 9, 8, 9, 8, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, - 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 5, 0, 0, 0, 0, 0, 0, + 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 0, + 0, 5, 0, 0, 0, 0, 0, 0, 0, 97, 97, 97, 97, 97, 97, 97, 97, 97, + 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, + 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 2, 0, 2, 2, 0, @@ -379,507 +380,510 @@ const uint8_t index2[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 97, 5, 5, 5, 5, 5, 5, + 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, + 2, 2, 2, 98, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 2, 97, 2, 5, 97, 97, - 97, 2, 2, 2, 2, 2, 2, 2, 2, 97, 97, 97, 97, 2, 97, 97, 5, 2, - 2, 2, 2, 2, 2, 2, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 2, 2, - 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 5, 5, 5, 5, 5, - 5, 5, 0, 5, 5, 5, 5, 5, 5, 5, 0, 2, 97, 97, 0, 5, 5, 5, - 5, 5, 5, 5, 5, 0, 0, 5, 5, 0, 0, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 5, 5, - 5, 5, 5, 5, 5, 0, 5, 0, 0, 0, 5, 5, 5, 5, 0, 0, 2, 5, - 97, 97, 97, 2, 2, 2, 2, 0, 0, 97, 97, 0, 0, 97, 97, 2, 5, 0, - 0, 0, 0, 0, 0, 0, 0, 97, 0, 0, 0, 0, 5, 5, 0, 5, 5, 5, - 2, 2, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 5, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 97, 0, 5, - 5, 5, 5, 5, 5, 0, 0, 0, 0, 5, 5, 0, 0, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 2, 98, 2, 5, 98, 98, 98, 2, 2, 2, 2, 2, 2, 2, + 2, 98, 98, 98, 98, 2, 98, 98, 5, 2, 2, 2, 2, 2, 2, 2, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 2, 2, 0, 0, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 0, 5, 5, 5, 5, 5, 5, 5, 0, 5, 5, 5, 5, 5, + 5, 5, 0, 2, 98, 98, 0, 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, 5, + 5, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 0, 5, 5, 5, 5, 5, 5, 5, 0, 5, 0, + 0, 0, 5, 5, 5, 5, 0, 0, 2, 5, 98, 98, 98, 2, 2, 2, 2, 0, + 0, 98, 98, 0, 0, 98, 98, 2, 5, 0, 0, 0, 0, 0, 0, 0, 0, 98, + 0, 0, 0, 0, 5, 5, 0, 5, 5, 5, 2, 2, 0, 0, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 2, 2, 98, 0, 5, 5, 5, 5, 5, 5, 0, 0, 0, + 0, 5, 5, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 5, 5, 5, 5, 5, 5, 5, 0, + 5, 5, 0, 5, 5, 0, 5, 5, 0, 0, 2, 0, 98, 98, 98, 2, 2, 0, + 0, 0, 0, 2, 2, 0, 0, 2, 2, 2, 0, 0, 0, 2, 0, 0, 0, 0, + 0, 0, 0, 5, 5, 5, 5, 0, 5, 0, 0, 0, 0, 0, 0, 0, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 5, 5, 2, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 2, 2, 98, 0, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 5, 5, 5, 5, 5, 5, + 5, 0, 5, 5, 0, 5, 5, 5, 5, 5, 0, 0, 2, 5, 98, 98, 98, 2, + 2, 2, 2, 2, 0, 2, 2, 98, 0, 98, 98, 2, 0, 0, 5, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 2, 2, 0, 0, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 98, 98, 0, 5, 5, 5, 5, 5, + 5, 5, 5, 0, 0, 5, 5, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 5, 5, 5, 5, + 5, 5, 5, 0, 5, 5, 0, 5, 5, 5, 5, 5, 0, 0, 2, 5, 98, 2, + 98, 2, 2, 2, 2, 0, 0, 98, 98, 0, 0, 98, 98, 2, 0, 0, 0, 0, + 0, 0, 0, 0, 2, 98, 0, 0, 0, 0, 5, 5, 0, 5, 5, 5, 2, 2, + 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 5, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 5, 0, 5, 5, 5, + 5, 5, 5, 0, 0, 0, 5, 5, 5, 0, 5, 5, 5, 5, 0, 0, 0, 5, + 5, 0, 5, 0, 5, 5, 0, 0, 0, 5, 5, 0, 0, 0, 5, 5, 5, 0, + 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, 0, 0, + 98, 98, 2, 98, 98, 0, 0, 0, 98, 98, 98, 0, 98, 98, 98, 2, 0, 0, + 5, 0, 0, 0, 0, 0, 0, 98, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 98, 98, 98, 0, 5, + 5, 5, 5, 5, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, - 5, 5, 5, 5, 5, 5, 5, 0, 5, 5, 0, 5, 5, 0, 5, 5, 0, 0, - 2, 0, 97, 97, 97, 2, 2, 0, 0, 0, 0, 2, 2, 0, 0, 2, 2, 2, - 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 0, 5, 0, - 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 5, 5, 5, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 97, - 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 5, 5, 5, 5, 5, 0, 0, + 0, 5, 2, 2, 2, 98, 98, 98, 98, 0, 2, 2, 2, 0, 2, 2, 2, 2, + 0, 0, 0, 0, 0, 0, 0, 2, 2, 0, 5, 5, 0, 0, 0, 0, 0, 0, + 5, 5, 2, 2, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 98, 98, + 0, 5, 5, 5, 5, 5, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 0, 5, 5, 5, 5, 5, 5, 5, 0, 5, 5, 0, 5, 5, 5, 5, 5, - 0, 0, 2, 5, 97, 97, 97, 2, 2, 2, 2, 2, 0, 2, 2, 97, 0, 97, - 97, 2, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 5, 5, 2, 2, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, - 97, 97, 0, 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, 5, 5, 0, 0, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 0, 5, 5, 5, 5, 5, 5, 5, 0, 5, 5, 0, 5, 5, 5, - 5, 5, 0, 0, 2, 5, 97, 2, 97, 2, 2, 2, 2, 0, 0, 97, 97, 0, - 0, 97, 97, 2, 0, 0, 0, 0, 0, 0, 0, 0, 2, 97, 0, 0, 0, 0, - 5, 5, 0, 5, 5, 5, 2, 2, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 2, 5, 0, 5, 5, 5, 5, 5, 5, 0, 0, 0, 5, 5, 5, 0, - 5, 5, 5, 5, 0, 0, 0, 5, 5, 0, 5, 0, 5, 5, 0, 0, 0, 5, - 5, 0, 0, 0, 5, 5, 5, 0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 0, 0, 0, 0, 97, 97, 2, 97, 97, 0, 0, 0, 97, 97, - 97, 0, 97, 97, 97, 2, 0, 0, 5, 0, 0, 0, 0, 0, 0, 97, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 97, 97, 97, 0, 5, 5, 5, 5, 5, 5, 5, 5, 0, 5, 5, - 5, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 0, 5, 5, 5, 5, 5, 0, 0, 0, 5, 2, 2, 2, 97, 97, 97, 97, 0, - 2, 2, 2, 0, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 2, 2, 0, - 5, 5, 0, 0, 0, 0, 0, 0, 5, 5, 2, 2, 0, 0, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 97, 97, 0, 5, 5, 5, 5, 5, 5, 5, 5, 0, - 5, 5, 5, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 0, 5, 5, 5, 5, 5, 0, 0, 2, 5, 97, 2, 97, 97, 97, 97, - 97, 0, 2, 97, 97, 0, 97, 97, 2, 2, 0, 0, 0, 0, 0, 0, 0, 97, - 97, 0, 0, 0, 0, 0, 0, 0, 5, 0, 5, 5, 2, 2, 0, 0, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 0, 5, 5, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 97, 97, 0, 5, 5, 5, 5, 5, 5, 5, - 5, 0, 5, 5, 5, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, 5, 97, 97, 97, 2, - 2, 2, 2, 0, 97, 97, 97, 0, 97, 97, 97, 2, 5, 0, 0, 0, 0, 0, - 0, 0, 0, 97, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 2, 2, 0, 0, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 5, 5, 5, 5, 5, 5, 0, 0, 97, 97, 0, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, 0, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 5, 0, 0, - 5, 5, 5, 5, 5, 5, 5, 0, 0, 0, 2, 0, 0, 0, 0, 97, 97, 97, - 2, 2, 2, 0, 2, 0, 97, 97, 97, 97, 97, 97, 97, 97, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 97, 97, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 5, + 5, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 5, 5, 5, 5, 5, + 0, 0, 2, 5, 98, 2, 98, 98, 98, 98, 98, 0, 2, 98, 98, 0, 98, 98, + 2, 2, 0, 0, 0, 0, 0, 0, 0, 98, 98, 0, 0, 0, 0, 0, 0, 0, + 5, 0, 5, 5, 2, 2, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 0, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 98, 98, 0, 5, 5, 5, 5, 5, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 2, 5, 5, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, - 0, 0, 5, 5, 5, 5, 5, 5, 5, 2, 2, 2, 2, 2, 2, 2, 2, 0, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, + 5, 5, 5, 0, 0, 5, 98, 98, 98, 2, 2, 2, 2, 0, 98, 98, 98, 0, + 98, 98, 98, 2, 5, 0, 0, 0, 0, 0, 0, 0, 0, 98, 0, 0, 0, 0, + 0, 0, 0, 0, 5, 5, 2, 2, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, + 0, 0, 98, 98, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 0, 5, 0, 0, 5, 5, 5, 5, 5, 5, 5, 0, + 0, 0, 2, 0, 0, 0, 0, 98, 98, 98, 2, 2, 2, 0, 2, 0, 98, 98, + 98, 98, 98, 98, 98, 98, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 98, 98, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 2, 5, 5, + 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, + 5, 2, 2, 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 0, 5, 0, - 0, 5, 5, 0, 5, 0, 0, 5, 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, - 0, 5, 5, 5, 5, 5, 5, 5, 0, 5, 5, 5, 0, 5, 0, 5, 0, 0, - 5, 5, 0, 5, 5, 5, 5, 2, 5, 5, 2, 2, 2, 2, 2, 2, 0, 2, - 2, 5, 0, 0, 5, 5, 5, 5, 5, 0, 5, 0, 2, 2, 2, 2, 2, 2, - 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 5, 5, 0, 0, + 0, 0, 0, 0, 0, 5, 5, 0, 5, 0, 0, 5, 5, 0, 5, 0, 0, 5, + 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 0, 5, 5, 5, 5, 5, 5, 5, + 0, 5, 5, 5, 0, 5, 0, 5, 0, 0, 5, 5, 0, 5, 5, 5, 5, 2, + 5, 5, 2, 2, 2, 2, 2, 2, 0, 2, 2, 5, 0, 0, 5, 5, 5, 5, + 5, 0, 5, 0, 2, 2, 2, 2, 2, 2, 0, 0, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 0, 0, 5, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 2, 2, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 2, 0, 2, - 0, 0, 0, 0, 97, 97, 5, 5, 5, 5, 5, 5, 5, 5, 0, 5, 5, 5, + 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, + 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 2, 0, 2, 0, 2, 0, 0, 0, 0, 98, 98, 5, 5, + 5, 5, 5, 5, 5, 5, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, 0, - 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 97, 2, 2, - 2, 2, 2, 0, 2, 2, 5, 5, 5, 5, 5, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 5, 5, 5, 5, 5, 5, 5, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 98, 2, 2, 2, 2, 2, 0, 2, 2, 5, 5, + 5, 5, 5, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 97, 97, 2, 2, 2, 2, 97, 2, 2, 2, 2, - 2, 2, 97, 2, 2, 97, 97, 2, 2, 5, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 97, 97, 2, 2, - 5, 5, 5, 5, 2, 2, 2, 5, 97, 97, 97, 5, 5, 97, 97, 97, 97, 97, - 97, 97, 5, 5, 5, 2, 2, 2, 2, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 2, 97, 97, 2, 2, 97, 97, 97, 97, 97, 97, 2, 5, 97, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 97, 97, 97, 2, 0, 0, 98, 98, - 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, - 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, - 5, 0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 5, 5, 5, 5, - 0, 0, 5, 5, 5, 5, 5, 5, 5, 0, 5, 0, 5, 5, 5, 5, 0, 0, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 98, + 98, 2, 2, 2, 2, 98, 2, 2, 2, 2, 2, 2, 98, 2, 2, 98, 98, 2, + 2, 5, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, + 5, 5, 5, 5, 5, 5, 98, 98, 2, 2, 5, 5, 5, 5, 2, 2, 2, 5, + 98, 98, 98, 5, 5, 98, 98, 98, 98, 98, 98, 98, 5, 5, 5, 2, 2, 2, + 2, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 2, 98, 98, 2, + 2, 98, 98, 98, 98, 98, 98, 2, 5, 98, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 98, 98, 98, 2, 0, 0, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 0, 99, 0, 0, 0, 0, 0, 99, + 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 5, 5, 5, 5, 0, 0, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 5, 5, 5, 5, 0, 0, 5, 5, - 5, 5, 5, 5, 5, 0, 5, 0, 5, 5, 5, 5, 0, 0, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 0, 5, 0, 5, 5, 5, 5, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 5, 5, 5, 5, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 0, 5, 5, 5, 5, 0, 0, 5, 5, 5, 5, 5, 5, 5, 0, 5, 0, + 5, 5, 5, 5, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 0, 5, 5, 5, 5, 0, 0, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, 2, 2, 2, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 1, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, 0, 5, 5, + 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 5, 5, 5, 5, 2, 2, + 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 2, 2, 2, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, + 5, 5, 5, 0, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 2, 2, + 98, 2, 2, 2, 2, 2, 2, 2, 98, 98, 98, 98, 98, 98, 98, 98, 2, 98, + 98, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 5, 0, 0, + 0, 0, 5, 2, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 1, 0, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, 0, 0, + 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 2, 5, 0, 0, 0, 0, 0, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, + 0, 0, 2, 2, 2, 98, 98, 98, 98, 2, 2, 98, 98, 98, 0, 0, 0, 0, + 98, 98, 2, 98, 98, 98, 98, 98, 98, 2, 2, 2, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, 5, 5, 5, 5, 5, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, + 0, 0, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, + 98, 5, 5, 5, 5, 5, 5, 5, 98, 98, 0, 0, 0, 0, 0, 0, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 2, 2, 98, + 98, 98, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 98, 2, 98, 2, 2, 2, 2, 2, 2, 2, 0, 2, 98, + 2, 98, 98, 2, 2, 2, 2, 2, 2, 2, 2, 98, 98, 98, 98, 98, 98, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, + 98, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 2, 98, 2, 2, 2, 2, + 2, 98, 2, 98, 98, 98, 98, 98, 2, 98, 98, 5, 5, 5, 5, 5, 5, 5, + 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, + 98, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 98, 2, 2, 2, 2, + 98, 98, 2, 2, 98, 2, 98, 98, 5, 5, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 2, 98, 2, 2, 98, 98, 98, 2, + 98, 2, 2, 2, 98, 98, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 98, 98, 98, 98, 98, 98, 98, 98, 2, 2, 2, 2, 2, 2, 2, 2, 98, 98, + 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 0, 0, 0, 5, 5, 5, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 98, + 2, 2, 2, 2, 2, 2, 2, 5, 5, 5, 5, 2, 5, 5, 5, 5, 98, 98, + 2, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 100, 5, 5, + 5, 101, 5, 5, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 8, 9, 8, 9, + 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, + 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, + 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, + 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, + 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 5, 5, 5, 5, 5, 102, 5, 5, + 103, 5, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, + 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 104, 104, + 104, 104, 104, 104, 104, 104, 105, 105, 105, 105, 105, 105, 105, 105, 104, 104, 104, 104, + 104, 104, 0, 0, 105, 105, 105, 105, 105, 105, 0, 0, 104, 104, 104, 104, 104, 104, + 104, 104, 105, 105, 105, 105, 105, 105, 105, 105, 104, 104, 104, 104, 104, 104, 104, 104, + 105, 105, 105, 105, 105, 105, 105, 105, 104, 104, 104, 104, 104, 104, 0, 0, 105, 105, + 105, 105, 105, 105, 0, 0, 5, 104, 5, 104, 5, 104, 5, 104, 0, 105, 0, 105, + 0, 105, 0, 105, 104, 104, 104, 104, 104, 104, 104, 104, 105, 105, 105, 105, 105, 105, + 105, 105, 106, 106, 107, 107, 107, 107, 108, 108, 109, 109, 110, 110, 111, 111, 0, 0, + 104, 104, 104, 104, 104, 104, 104, 104, 105, 105, 105, 105, 105, 105, 105, 105, 104, 104, + 104, 104, 104, 104, 104, 104, 105, 105, 105, 105, 105, 105, 105, 105, 104, 104, 104, 104, + 104, 104, 104, 104, 105, 105, 105, 105, 105, 105, 105, 105, 104, 104, 5, 112, 5, 0, + 5, 5, 105, 105, 113, 113, 114, 0, 115, 0, 0, 0, 5, 112, 5, 0, 5, 5, + 116, 116, 116, 116, 114, 0, 0, 0, 104, 104, 5, 5, 0, 0, 5, 5, 105, 105, + 117, 117, 0, 0, 0, 0, 104, 104, 5, 5, 5, 88, 5, 5, 105, 105, 118, 118, + 91, 0, 0, 0, 0, 0, 5, 112, 5, 0, 5, 5, 119, 119, 120, 120, 114, 0, + 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 2, 2, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 93, 93, 93, 93, 2, 93, 93, 93, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 5, 0, 0, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 0, 5, 0, 0, 0, 5, 5, 5, 5, 5, + 0, 0, 0, 0, 0, 0, 5, 0, 121, 0, 5, 0, 122, 123, 5, 5, 0, 5, + 5, 5, 124, 5, 5, 5, 5, 5, 5, 5, 0, 0, 5, 5, 5, 5, 0, 0, + 0, 0, 0, 5, 5, 5, 5, 5, 0, 0, 0, 0, 125, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 126, 126, 126, 126, 126, 126, + 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 5, 5, 5, 8, 9, 5, 5, 5, 5, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, + 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, + 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, + 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 0, 97, 97, 97, 97, + 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, + 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, + 97, 97, 97, 97, 97, 97, 97, 0, 8, 9, 130, 131, 132, 133, 134, 8, 9, 8, + 9, 8, 9, 135, 136, 137, 138, 5, 8, 9, 5, 8, 9, 5, 5, 5, 5, 5, + 5, 5, 139, 139, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, + 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, + 8, 9, 8, 9, 5, 0, 0, 0, 0, 0, 0, 8, 9, 8, 9, 2, 2, 2, + 8, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 140, 140, 140, 140, + 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, + 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 0, 140, + 0, 0, 0, 0, 0, 140, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 5, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, + 5, 0, 5, 5, 5, 5, 5, 5, 5, 0, 5, 5, 5, 5, 5, 5, 5, 0, + 5, 5, 5, 5, 5, 5, 5, 0, 5, 5, 5, 5, 5, 5, 5, 0, 5, 5, + 5, 5, 5, 5, 5, 0, 5, 5, 5, 5, 5, 5, 5, 0, 5, 5, 5, 5, + 5, 5, 5, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 5, 5, 5, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 2, 2, + 2, 2, 98, 98, 0, 5, 5, 5, 5, 5, 0, 0, 5, 5, 5, 5, 5, 0, + 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 0, 0, 2, 2, 0, 0, 5, 5, 5, 0, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, - 0, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 5, 5, 5, 5, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, 0, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, 0, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 9, 8, 9, 8, 9, 8, 9, + 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, + 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, + 8, 9, 5, 2, 93, 93, 93, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 0, 5, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, + 8, 9, 8, 9, 8, 9, 8, 9, 0, 0, 0, 0, 0, 0, 0, 2, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 5, 5, 5, 5, 5, 5, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 0, 0, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 5, 5, + 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, + 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, + 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, + 8, 9, 8, 9, 8, 9, 8, 9, 5, 5, 5, 5, 5, 5, 5, 5, 5, 8, + 9, 8, 9, 100, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 5, 0, 0, 8, + 9, 56, 5, 0, 8, 9, 8, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 57, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 2, 5, 5, 5, 2, 5, 5, 5, + 5, 2, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 98, 98, 2, 2, 98, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 98, 98, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, + 98, 98, 98, 98, 98, 98, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 5, + 5, 5, 5, 5, 0, 0, 0, 5, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 2, 2, 2, 2, + 2, 2, 2, 2, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 98, 98, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, 0, 2, 2, 2, 98, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 2, 98, 98, 2, 2, 2, 2, + 98, 98, 2, 98, 98, 98, 98, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 5, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 2, 2, 2, 2, 2, 2, 98, 98, 2, 2, 98, 98, 2, 2, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 2, 5, 5, 5, 5, 5, 5, + 5, 5, 2, 98, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, + 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, 0, 5, 98, 0, 0, 0, 0, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 2, 5, 2, 2, 2, 5, + 5, 2, 2, 5, 5, 5, 5, 5, 2, 2, 5, 2, 5, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 5, 5, 5, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 98, + 2, 2, 98, 98, 0, 0, 5, 5, 5, 98, 2, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 5, 5, 5, 5, 5, 5, 0, 0, 5, 5, 5, 5, 5, 5, 0, + 0, 5, 5, 5, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, + 5, 5, 5, 5, 5, 0, 5, 5, 5, 5, 5, 5, 5, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 98, 98, 2, 98, 98, 2, 98, + 98, 0, 98, 2, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, + 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 0, 0, 0, 0, + 0, 5, 2, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 5, 5, 5, 5, 5, 0, 5, 0, + 5, 5, 0, 5, 5, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 1, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, 0, 0, 0, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 0, 0, 0, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 0, 5, 5, 5, 5, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 2, 2, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 0, 5, 5, 5, 0, 2, 2, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 0, 0, 97, 2, 2, 2, 2, 2, 2, 2, 97, 97, - 97, 97, 97, 97, 97, 97, 2, 97, 97, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 0, 0, 0, 5, 0, 0, 0, 0, 5, 2, 0, 0, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 2, 2, 2, 1, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 2, - 5, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 0, 0, 0, 2, 2, 2, 97, 97, 97, 97, 2, - 2, 97, 97, 97, 0, 0, 0, 0, 97, 97, 2, 97, 97, 97, 97, 97, 97, 2, - 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, - 5, 5, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 0, 0, 0, 0, 97, 97, 97, 97, 97, 97, 97, 97, - 97, 97, 97, 97, 97, 97, 97, 97, 97, 5, 5, 5, 5, 5, 5, 5, 97, 97, - 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 2, 2, 97, 97, 97, 0, 0, 0, 0, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 97, 2, 97, 2, 2, - 2, 2, 2, 2, 2, 0, 2, 97, 2, 97, 97, 2, 2, 2, 2, 2, 2, 2, - 2, 97, 97, 97, 97, 97, 97, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, - 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 97, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 2, 97, 2, 2, 2, 2, 2, 97, - 2, 97, 97, 97, 97, 97, 2, 97, 97, 5, 5, 5, 5, 5, 5, 5, 0, 0, - 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 97, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 97, 2, 2, 2, 2, 97, 97, - 2, 2, 97, 0, 0, 0, 5, 5, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 2, 97, 2, 2, 97, 97, 97, 2, 97, 2, - 2, 2, 97, 97, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 97, 97, - 97, 97, 97, 97, 97, 97, 2, 2, 2, 2, 2, 2, 2, 2, 97, 97, 2, 2, - 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 0, 0, 0, 5, 5, 5, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, - 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 97, 2, 2, - 2, 2, 2, 2, 2, 5, 5, 5, 5, 2, 5, 5, 5, 5, 97, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 99, 5, 5, 5, 100, - 5, 5, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 8, 9, 8, 9, 8, 9, - 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, - 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, - 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, - 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, - 8, 9, 8, 9, 8, 9, 8, 9, 5, 5, 5, 5, 5, 101, 5, 5, 102, 5, - 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, - 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 103, 103, 103, 103, - 103, 103, 103, 103, 104, 104, 104, 104, 104, 104, 104, 104, 103, 103, 103, 103, 103, 103, - 0, 0, 104, 104, 104, 104, 104, 104, 0, 0, 103, 103, 103, 103, 103, 103, 103, 103, - 104, 104, 104, 104, 104, 104, 104, 104, 103, 103, 103, 103, 103, 103, 103, 103, 104, 104, - 104, 104, 104, 104, 104, 104, 103, 103, 103, 103, 103, 103, 0, 0, 104, 104, 104, 104, - 104, 104, 0, 0, 5, 103, 5, 103, 5, 103, 5, 103, 0, 104, 0, 104, 0, 104, - 0, 104, 103, 103, 103, 103, 103, 103, 103, 103, 104, 104, 104, 104, 104, 104, 104, 104, - 105, 105, 106, 106, 106, 106, 107, 107, 108, 108, 109, 109, 110, 110, 0, 0, 103, 103, - 103, 103, 103, 103, 103, 103, 104, 104, 104, 104, 104, 104, 104, 104, 103, 103, 103, 103, - 103, 103, 103, 103, 104, 104, 104, 104, 104, 104, 104, 104, 103, 103, 103, 103, 103, 103, - 103, 103, 104, 104, 104, 104, 104, 104, 104, 104, 103, 103, 5, 111, 5, 0, 5, 5, - 104, 104, 112, 112, 113, 0, 114, 0, 0, 0, 5, 111, 5, 0, 5, 5, 115, 115, - 115, 115, 113, 0, 0, 0, 103, 103, 5, 5, 0, 0, 5, 5, 104, 104, 116, 116, - 0, 0, 0, 0, 103, 103, 5, 5, 5, 87, 5, 5, 104, 104, 117, 117, 90, 0, - 0, 0, 0, 0, 5, 111, 5, 0, 5, 5, 118, 118, 119, 119, 113, 0, 0, 0, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 2, 2, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 92, 92, 92, 92, 2, 92, 92, 92, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 5, 0, 0, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 0, 5, 0, 0, 0, 5, 5, 5, 5, 5, 0, 0, - 0, 0, 0, 0, 5, 0, 120, 0, 5, 0, 121, 122, 5, 5, 0, 5, 5, 5, - 123, 5, 5, 5, 5, 5, 5, 5, 0, 0, 5, 5, 5, 5, 0, 0, 0, 0, - 0, 5, 5, 5, 5, 5, 0, 0, 0, 0, 124, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 125, 125, 125, 125, 125, 125, 125, 125, - 125, 125, 125, 125, 125, 125, 125, 125, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, - 126, 126, 126, 126, 126, 126, 5, 5, 5, 8, 9, 5, 5, 5, 5, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 127, 127, - 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, - 127, 127, 127, 127, 127, 127, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, - 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, - 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, - 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 0, 96, 96, 96, 96, 96, 96, - 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, - 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, - 96, 96, 96, 96, 96, 0, 8, 9, 129, 130, 131, 132, 133, 8, 9, 8, 9, 8, - 9, 134, 135, 136, 137, 5, 8, 9, 5, 8, 9, 5, 5, 5, 5, 5, 5, 5, - 138, 138, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, - 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, - 8, 9, 5, 0, 0, 0, 0, 0, 0, 8, 9, 8, 9, 2, 2, 2, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 139, 139, 139, 139, 139, 139, - 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, - 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 0, - 5, 5, 5, 5, 5, 5, 5, 0, 5, 5, 5, 5, 5, 5, 5, 0, 5, 5, - 5, 5, 5, 5, 5, 0, 5, 5, 5, 5, 5, 5, 5, 0, 5, 5, 5, 5, - 5, 5, 5, 0, 5, 5, 5, 5, 5, 5, 5, 0, 5, 5, 5, 5, 5, 5, - 5, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 5, 5, 5, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 2, 2, 2, 2, - 2, 2, 0, 5, 5, 5, 5, 5, 0, 0, 5, 5, 5, 5, 5, 0, 0, 0, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 0, 0, 2, 2, 0, 0, 5, 5, 5, 0, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 5, 5, - 5, 5, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, 0, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 5, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, - 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, - 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 5, 2, 92, 92, 92, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 2, 2, 0, 5, 8, 9, 8, 9, 8, 9, 8, 9, - 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 0, 0, - 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 2, 2, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, 8, 9, 8, 9, 8, 9, 8, 9, - 8, 9, 8, 9, 8, 9, 5, 5, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, - 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, - 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, - 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 8, 9, 8, 9, 99, 8, 9, 8, 9, 8, 9, - 8, 9, 8, 9, 5, 0, 0, 8, 9, 56, 5, 0, 8, 9, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 9, 8, 9, 8, 9, 8, 9, - 8, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, - 2, 5, 5, 5, 2, 5, 5, 5, 5, 2, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 97, 97, 2, - 2, 97, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 97, 97, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 97, 97, - 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 2, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 5, 5, 5, 5, 5, 5, 0, 0, 0, 5, 0, 0, - 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 97, 97, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 0, 0, 0, 2, 2, 2, 97, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 2, 97, 97, 2, 2, 2, 2, 97, 97, 2, 97, 97, 97, 97, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 2, 2, 2, 2, 2, 2, 97, - 97, 2, 2, 97, 97, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, - 5, 2, 5, 5, 5, 5, 5, 5, 5, 5, 2, 97, 0, 0, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, - 0, 0, 5, 97, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 2, 5, 2, 2, 2, 5, 5, 2, 2, 5, 5, 5, 5, 5, 2, 2, - 5, 2, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 0, - 0, 5, 5, 5, 5, 5, 5, 0, 0, 5, 5, 5, 5, 5, 5, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 0, 5, 5, 5, 5, - 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 97, 97, 2, 97, 97, 2, 97, 97, 0, 97, 2, 0, 0, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, 0, 0, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, 0, 0, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, - 5, 5, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, - 5, 5, 5, 5, 0, 0, 0, 0, 0, 5, 2, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, - 5, 5, 5, 5, 5, 0, 5, 0, 5, 5, 0, 5, 5, 0, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 0, 0, 0, 0, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, 0, 0, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, + 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 0, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, 1, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 0, 0, 0, 0, 2, 0, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, 0, 5, 5, 5, 5, - 5, 5, 0, 0, 5, 5, 5, 5, 5, 5, 0, 0, 5, 5, 5, 5, 5, 5, - 0, 0, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, + 0, 0, 5, 5, 5, 5, 5, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, + 0, 2, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 0, 0, 0, 5, 5, 5, 5, 5, 5, 0, 0, 5, 5, 5, 5, + 5, 5, 0, 0, 5, 5, 5, 5, 5, 5, 0, 0, 5, 5, 5, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; } /* namespace unicode */ diff --git a/js/src/vm/UnicodeData.txt b/js/src/vm/UnicodeData.txt index 8d7222b13789..9f204050c6bb 100644 --- a/js/src/vm/UnicodeData.txt +++ b/js/src/vm/UnicodeData.txt @@ -165,10 +165,10 @@ 00A4;CURRENCY SIGN;Sc;0;ET;;;;;N;;;;; 00A5;YEN SIGN;Sc;0;ET;;;;;N;;;;; 00A6;BROKEN BAR;So;0;ON;;;;;N;BROKEN VERTICAL BAR;;;; -00A7;SECTION SIGN;So;0;ON;;;;;N;;;;; +00A7;SECTION SIGN;Po;0;ON;;;;;N;;;;; 00A8;DIAERESIS;Sk;0;ON;<compat> 0020 0308;;;;N;SPACING DIAERESIS;;;; 00A9;COPYRIGHT SIGN;So;0;ON;;;;;N;;;;; -00AA;FEMININE ORDINAL INDICATOR;Ll;0;L;<super> 0061;;;;N;;;;; +00AA;FEMININE ORDINAL INDICATOR;Lo;0;L;<super> 0061;;;;N;;;;; 00AB;LEFT-POINTING DOUBLE ANGLE QUOTATION MARK;Pi;0;ON;;;;;Y;LEFT POINTING GUILLEMET;;;; 00AC;NOT SIGN;Sm;0;ON;;;;;N;;;;; 00AD;SOFT HYPHEN;Cf;0;BN;;;;;N;;;;; @@ -180,11 +180,11 @@ 00B3;SUPERSCRIPT THREE;No;0;EN;<super> 0033;;3;3;N;SUPERSCRIPT DIGIT THREE;;;; 00B4;ACUTE ACCENT;Sk;0;ON;<compat> 0020 0301;;;;N;SPACING ACUTE;;;; 00B5;MICRO SIGN;Ll;0;L;<compat> 03BC;;;;N;;;039C;;039C -00B6;PILCROW SIGN;So;0;ON;;;;;N;PARAGRAPH SIGN;;;; +00B6;PILCROW SIGN;Po;0;ON;;;;;N;PARAGRAPH SIGN;;;; 00B7;MIDDLE DOT;Po;0;ON;;;;;N;;;;; 00B8;CEDILLA;Sk;0;ON;<compat> 0020 0327;;;;N;SPACING CEDILLA;;;; 00B9;SUPERSCRIPT ONE;No;0;EN;<super> 0031;;1;1;N;SUPERSCRIPT DIGIT ONE;;;; -00BA;MASCULINE ORDINAL INDICATOR;Ll;0;L;<super> 006F;;;;N;;;;; +00BA;MASCULINE ORDINAL INDICATOR;Lo;0;L;<super> 006F;;;;N;;;;; 00BB;RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK;Pf;0;ON;;;;;Y;RIGHT POINTING GUILLEMET;;;; 00BC;VULGAR FRACTION ONE QUARTER;No;0;ON;<fraction> 0031 2044 0034;;;1/4;N;FRACTION ONE QUARTER;;;; 00BD;VULGAR FRACTION ONE HALF;No;0;ON;<fraction> 0031 2044 0032;;;1/2;N;FRACTION ONE HALF;;;; @@ -612,7 +612,7 @@ 0263;LATIN SMALL LETTER GAMMA;Ll;0;L;;;;;N;;;0194;;0194 0264;LATIN SMALL LETTER RAMS HORN;Ll;0;L;;;;;N;LATIN SMALL LETTER BABY GAMMA;;;; 0265;LATIN SMALL LETTER TURNED H;Ll;0;L;;;;;N;;;A78D;;A78D -0266;LATIN SMALL LETTER H WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER H HOOK;;;; +0266;LATIN SMALL LETTER H WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER H HOOK;;A7AA;;A7AA 0267;LATIN SMALL LETTER HENG WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER HENG HOOK;;;; 0268;LATIN SMALL LETTER I WITH STROKE;Ll;0;L;;;;;N;LATIN SMALL LETTER BARRED I;;0197;;0197 0269;LATIN SMALL LETTER IOTA;Ll;0;L;;;;;N;;;0196;;0196 @@ -1394,6 +1394,7 @@ 0587;ARMENIAN SMALL LIGATURE ECH YIWN;Ll;0;L;<compat> 0565 0582;;;;N;;;;; 0589;ARMENIAN FULL STOP;Po;0;L;;;;;N;ARMENIAN PERIOD;;;; 058A;ARMENIAN HYPHEN;Pd;0;ON;;;;;N;;;;; +058F;ARMENIAN DRAM SIGN;Sc;0;ET;;;;;N;;;;; 0591;HEBREW ACCENT ETNAHTA;Mn;220;NSM;;;;;N;;;;; 0592;HEBREW ACCENT SEGOL;Mn;230;NSM;;;;;N;;;;; 0593;HEBREW ACCENT SHALSHELET;Mn;230;NSM;;;;;N;;;;; @@ -1485,6 +1486,7 @@ 0601;ARABIC SIGN SANAH;Cf;0;AN;;;;;N;;;;; 0602;ARABIC FOOTNOTE MARKER;Cf;0;AN;;;;;N;;;;; 0603;ARABIC SIGN SAFHA;Cf;0;AN;;;;;N;;;;; +0604;ARABIC SIGN SAMVAT;Cf;0;AN;;;;;N;;;;; 0606;ARABIC-INDIC CUBE ROOT;Sm;0;ON;;;;;N;;;;; 0607;ARABIC-INDIC FOURTH ROOT;Sm;0;ON;;;;;N;;;;; 0608;ARABIC RAY;Sm;0;AL;;;;;N;;;;; @@ -1747,7 +1749,7 @@ 070B;SYRIAC HARKLEAN OBELUS;Po;0;AL;;;;;N;;;;; 070C;SYRIAC HARKLEAN METOBELUS;Po;0;AL;;;;;N;;;;; 070D;SYRIAC HARKLEAN ASTERISCUS;Po;0;AL;;;;;N;;;;; -070F;SYRIAC ABBREVIATION MARK;Cf;0;AN;;;;;N;;;;; +070F;SYRIAC ABBREVIATION MARK;Cf;0;AL;;;;;N;;;;; 0710;SYRIAC LETTER ALAPH;Lo;0;AL;;;;;N;;;;; 0711;SYRIAC LETTER SUPERSCRIPT ALAPH;Mn;36;NSM;;;;;N;;;;; 0712;SYRIAC LETTER BETH;Lo;0;AL;;;;;N;;;;; @@ -2057,6 +2059,45 @@ 085A;MANDAIC VOCALIZATION MARK;Mn;220;NSM;;;;;N;;;;; 085B;MANDAIC GEMINATION MARK;Mn;220;NSM;;;;;N;;;;; 085E;MANDAIC PUNCTUATION;Po;0;R;;;;;N;;;;; +08A0;ARABIC LETTER BEH WITH SMALL V BELOW;Lo;0;AL;;;;;N;;;;; +08A2;ARABIC LETTER JEEM WITH TWO DOTS ABOVE;Lo;0;AL;;;;;N;;;;; +08A3;ARABIC LETTER TAH WITH TWO DOTS ABOVE;Lo;0;AL;;;;;N;;;;; +08A4;ARABIC LETTER FEH WITH DOT BELOW AND THREE DOTS ABOVE;Lo;0;AL;;;;;N;;;;; +08A5;ARABIC LETTER QAF WITH DOT BELOW;Lo;0;AL;;;;;N;;;;; +08A6;ARABIC LETTER LAM WITH DOUBLE BAR;Lo;0;AL;;;;;N;;;;; +08A7;ARABIC LETTER MEEM WITH THREE DOTS ABOVE;Lo;0;AL;;;;;N;;;;; +08A8;ARABIC LETTER YEH WITH TWO DOTS BELOW AND HAMZA ABOVE;Lo;0;AL;;;;;N;;;;; +08A9;ARABIC LETTER YEH WITH TWO DOTS BELOW AND DOT ABOVE;Lo;0;AL;;;;;N;;;;; +08AA;ARABIC LETTER REH WITH LOOP;Lo;0;AL;;;;;N;;;;; +08AB;ARABIC LETTER WAW WITH DOT WITHIN;Lo;0;AL;;;;;N;;;;; +08AC;ARABIC LETTER ROHINGYA YEH;Lo;0;AL;;;;;N;;;;; +08E4;ARABIC CURLY FATHA;Mn;230;NSM;;;;;N;;;;; +08E5;ARABIC CURLY DAMMA;Mn;230;NSM;;;;;N;;;;; +08E6;ARABIC CURLY KASRA;Mn;220;NSM;;;;;N;;;;; +08E7;ARABIC CURLY FATHATAN;Mn;230;NSM;;;;;N;;;;; +08E8;ARABIC CURLY DAMMATAN;Mn;230;NSM;;;;;N;;;;; +08E9;ARABIC CURLY KASRATAN;Mn;220;NSM;;;;;N;;;;; +08EA;ARABIC TONE ONE DOT ABOVE;Mn;230;NSM;;;;;N;;;;; +08EB;ARABIC TONE TWO DOTS ABOVE;Mn;230;NSM;;;;;N;;;;; +08EC;ARABIC TONE LOOP ABOVE;Mn;230;NSM;;;;;N;;;;; +08ED;ARABIC TONE ONE DOT BELOW;Mn;220;NSM;;;;;N;;;;; +08EE;ARABIC TONE TWO DOTS BELOW;Mn;220;NSM;;;;;N;;;;; +08EF;ARABIC TONE LOOP BELOW;Mn;220;NSM;;;;;N;;;;; +08F0;ARABIC OPEN FATHATAN;Mn;27;NSM;;;;;N;;;;; +08F1;ARABIC OPEN DAMMATAN;Mn;28;NSM;;;;;N;;;;; +08F2;ARABIC OPEN KASRATAN;Mn;29;NSM;;;;;N;;;;; +08F3;ARABIC SMALL HIGH WAW;Mn;230;NSM;;;;;N;;;;; +08F4;ARABIC FATHA WITH RING;Mn;230;NSM;;;;;N;;;;; +08F5;ARABIC FATHA WITH DOT ABOVE;Mn;230;NSM;;;;;N;;;;; +08F6;ARABIC KASRA WITH DOT BELOW;Mn;220;NSM;;;;;N;;;;; +08F7;ARABIC LEFT ARROWHEAD ABOVE;Mn;230;NSM;;;;;N;;;;; +08F8;ARABIC RIGHT ARROWHEAD ABOVE;Mn;230;NSM;;;;;N;;;;; +08F9;ARABIC LEFT ARROWHEAD BELOW;Mn;220;NSM;;;;;N;;;;; +08FA;ARABIC RIGHT ARROWHEAD BELOW;Mn;220;NSM;;;;;N;;;;; +08FB;ARABIC DOUBLE RIGHT ARROWHEAD ABOVE;Mn;230;NSM;;;;;N;;;;; +08FC;ARABIC DOUBLE RIGHT ARROWHEAD ABOVE WITH DOT;Mn;230;NSM;;;;;N;;;;; +08FD;ARABIC RIGHT ARROWHEAD ABOVE WITH DOT;Mn;230;NSM;;;;;N;;;;; +08FE;ARABIC DAMMA WITH DOT;Mn;230;NSM;;;;;N;;;;; 0900;DEVANAGARI SIGN INVERTED CANDRABINDU;Mn;0;NSM;;;;;N;;;;; 0901;DEVANAGARI SIGN CANDRABINDU;Mn;0;NSM;;;;;N;;;;; 0902;DEVANAGARI SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;; @@ -2437,6 +2478,7 @@ 0AED;GUJARATI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; 0AEE;GUJARATI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; 0AEF;GUJARATI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; +0AF0;GUJARATI ABBREVIATION SIGN;Po;0;L;;;;;N;;;;; 0AF1;GUJARATI RUPEE SIGN;Sc;0;ET;;;;;N;;;;; 0B01;ORIYA SIGN CANDRABINDU;Mn;0;NSM;;;;;N;;;;; 0B02;ORIYA SIGN ANUSVARA;Mc;0;L;;;;;N;;;;; @@ -3109,6 +3151,8 @@ 0ED9;LAO DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; 0EDC;LAO HO NO;Lo;0;L;<compat> 0EAB 0E99;;;;N;;;;; 0EDD;LAO HO MO;Lo;0;L;<compat> 0EAB 0EA1;;;;N;;;;; +0EDE;LAO LETTER KHMU GO;Lo;0;L;;;;;N;;;;; +0EDF;LAO LETTER KHMU NYO;Lo;0;L;;;;;N;;;;; 0F00;TIBETAN SYLLABLE OM;Lo;0;L;;;;;N;;;;; 0F01;TIBETAN MARK GTER YIG MGO TRUNCATED A;So;0;L;;;;;N;;;;; 0F02;TIBETAN MARK GTER YIG MGO -UM RNAM BCAD MA;So;0;L;;;;;N;;;;; @@ -3129,7 +3173,7 @@ 0F11;TIBETAN MARK RIN CHEN SPUNGS SHAD;Po;0;L;;;;;N;TIBETAN RINCHANPHUNGSHAD;;;; 0F12;TIBETAN MARK RGYA GRAM SHAD;Po;0;L;;;;;N;;;;; 0F13;TIBETAN MARK CARET -DZUD RTAGS ME LONG CAN;So;0;L;;;;;N;;;;; -0F14;TIBETAN MARK GTER TSHEG;So;0;L;;;;;N;TIBETAN COMMA;;;; +0F14;TIBETAN MARK GTER TSHEG;Po;0;L;;;;;N;TIBETAN COMMA;;;; 0F15;TIBETAN LOGOTYPE SIGN CHAD RTAGS;So;0;L;;;;;N;;;;; 0F16;TIBETAN LOGOTYPE SIGN LHAG RTAGS;So;0;L;;;;;N;;;;; 0F17;TIBETAN ASTROLOGICAL SIGN SGRA GCAN -CHAR RTAGS;So;0;L;;;;;N;;;;; @@ -3518,6 +3562,8 @@ 10C3;GEORGIAN CAPITAL LETTER WE;Lu;0;L;;;;;N;;;;2D23; 10C4;GEORGIAN CAPITAL LETTER HAR;Lu;0;L;;;;;N;;;;2D24; 10C5;GEORGIAN CAPITAL LETTER HOE;Lu;0;L;;;;;N;;;;2D25; +10C7;GEORGIAN CAPITAL LETTER YN;Lu;0;L;;;;;N;;;;2D27; +10CD;GEORGIAN CAPITAL LETTER AEN;Lu;0;L;;;;;N;;;;2D2D; 10D0;GEORGIAN LETTER AN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER AN;;;; 10D1;GEORGIAN LETTER BAN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER BAN;;;; 10D2;GEORGIAN LETTER GAN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER GAN;;;; @@ -3563,6 +3609,9 @@ 10FA;GEORGIAN LETTER AIN;Lo;0;L;;;;;N;;;;; 10FB;GEORGIAN PARAGRAPH SEPARATOR;Po;0;L;;;;;N;;;;; 10FC;MODIFIER LETTER GEORGIAN NAR;Lm;0;L;<super> 10DC;;;;N;;;;; +10FD;GEORGIAN LETTER AEN;Lo;0;L;;;;;N;;;;; +10FE;GEORGIAN LETTER HARD SIGN;Lo;0;L;;;;;N;;;;; +10FF;GEORGIAN LETTER LABIAL SIGN;Lo;0;L;;;;;N;;;;; 1100;HANGUL CHOSEONG KIYEOK;Lo;0;L;;;;;N;;;;; 1101;HANGUL CHOSEONG SSANGKIYEOK;Lo;0;L;;;;;N;;;;; 1102;HANGUL CHOSEONG NIEUN;Lo;0;L;;;;;N;;;;; @@ -4148,7 +4197,7 @@ 135D;ETHIOPIC COMBINING GEMINATION AND VOWEL LENGTH MARK;Mn;230;NSM;;;;;N;;;;; 135E;ETHIOPIC COMBINING VOWEL LENGTH MARK;Mn;230;NSM;;;;;N;;;;; 135F;ETHIOPIC COMBINING GEMINATION MARK;Mn;230;NSM;;;;;N;;;;; -1360;ETHIOPIC SECTION MARK;So;0;L;;;;;N;;;;; +1360;ETHIOPIC SECTION MARK;Po;0;L;;;;;N;;;;; 1361;ETHIOPIC WORDSPACE;Po;0;L;;;;;N;;;;; 1362;ETHIOPIC FULL STOP;Po;0;L;;;;;N;;;;; 1363;ETHIOPIC COMMA;Po;0;L;;;;;N;;;;; @@ -5171,8 +5220,8 @@ 17B1;KHMER INDEPENDENT VOWEL QOO TYPE ONE;Lo;0;L;;;;;N;;;;; 17B2;KHMER INDEPENDENT VOWEL QOO TYPE TWO;Lo;0;L;;;;;N;;;;; 17B3;KHMER INDEPENDENT VOWEL QAU;Lo;0;L;;;;;N;;;;; -17B4;KHMER VOWEL INHERENT AQ;Cf;0;L;;;;;N;;;;; -17B5;KHMER VOWEL INHERENT AA;Cf;0;L;;;;;N;;;;; +17B4;KHMER VOWEL INHERENT AQ;Mn;0;NSM;;;;;N;;;;; +17B5;KHMER VOWEL INHERENT AA;Mn;0;NSM;;;;;N;;;;; 17B6;KHMER VOWEL SIGN AA;Mc;0;L;;;;;N;;;;; 17B7;KHMER VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;; 17B8;KHMER VOWEL SIGN II;Mn;0;NSM;;;;;N;;;;; @@ -5996,6 +6045,9 @@ 1BA8;SUNDANESE VOWEL SIGN PAMEPET;Mn;0;NSM;;;;;N;;;;; 1BA9;SUNDANESE VOWEL SIGN PANEULEUNG;Mn;0;NSM;;;;;N;;;;; 1BAA;SUNDANESE SIGN PAMAAEH;Mc;9;L;;;;;N;;;;; +1BAB;SUNDANESE SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;; +1BAC;SUNDANESE CONSONANT SIGN PASANGAN MA;Mc;0;L;;;;;N;;;;; +1BAD;SUNDANESE CONSONANT SIGN PASANGAN WA;Mc;0;L;;;;;N;;;;; 1BAE;SUNDANESE LETTER KHA;Lo;0;L;;;;;N;;;;; 1BAF;SUNDANESE LETTER SYA;Lo;0;L;;;;;N;;;;; 1BB0;SUNDANESE DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; @@ -6008,6 +6060,12 @@ 1BB7;SUNDANESE DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; 1BB8;SUNDANESE DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; 1BB9;SUNDANESE DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; +1BBA;SUNDANESE AVAGRAHA;Lo;0;L;;;;;N;;;;; +1BBB;SUNDANESE LETTER REU;Lo;0;L;;;;;N;;;;; +1BBC;SUNDANESE LETTER LEU;Lo;0;L;;;;;N;;;;; +1BBD;SUNDANESE LETTER BHA;Lo;0;L;;;;;N;;;;; +1BBE;SUNDANESE LETTER FINAL K;Lo;0;L;;;;;N;;;;; +1BBF;SUNDANESE LETTER FINAL M;Lo;0;L;;;;;N;;;;; 1BC0;BATAK LETTER A;Lo;0;L;;;;;N;;;;; 1BC1;BATAK LETTER SIMALUNGUN A;Lo;0;L;;;;;N;;;;; 1BC2;BATAK LETTER HA;Lo;0;L;;;;;N;;;;; @@ -6186,6 +6244,14 @@ 1C7D;OL CHIKI AHAD;Lm;0;L;;;;;N;;;;; 1C7E;OL CHIKI PUNCTUATION MUCAAD;Po;0;L;;;;;N;;;;; 1C7F;OL CHIKI PUNCTUATION DOUBLE MUCAAD;Po;0;L;;;;;N;;;;; +1CC0;SUNDANESE PUNCTUATION BINDU SURYA;Po;0;L;;;;;N;;;;; +1CC1;SUNDANESE PUNCTUATION BINDU PANGLONG;Po;0;L;;;;;N;;;;; +1CC2;SUNDANESE PUNCTUATION BINDU PURNAMA;Po;0;L;;;;;N;;;;; +1CC3;SUNDANESE PUNCTUATION BINDU CAKRA;Po;0;L;;;;;N;;;;; +1CC4;SUNDANESE PUNCTUATION BINDU LEU SATANGA;Po;0;L;;;;;N;;;;; +1CC5;SUNDANESE PUNCTUATION BINDU KA SATANGA;Po;0;L;;;;;N;;;;; +1CC6;SUNDANESE PUNCTUATION BINDU DA SATANGA;Po;0;L;;;;;N;;;;; +1CC7;SUNDANESE PUNCTUATION BINDU BA SATANGA;Po;0;L;;;;;N;;;;; 1CD0;VEDIC TONE KARSHANA;Mn;230;NSM;;;;;N;;;;; 1CD1;VEDIC TONE SHARA;Mn;230;NSM;;;;;N;;;;; 1CD2;VEDIC TONE PRENKHA;Mn;230;NSM;;;;;N;;;;; @@ -6221,6 +6287,10 @@ 1CF0;VEDIC SIGN RTHANG LONG ANUSVARA;Lo;0;L;;;;;N;;;;; 1CF1;VEDIC SIGN ANUSVARA UBHAYATO MUKHA;Lo;0;L;;;;;N;;;;; 1CF2;VEDIC SIGN ARDHAVISARGA;Mc;0;L;;;;;N;;;;; +1CF3;VEDIC SIGN ROTATED ARDHAVISARGA;Mc;0;L;;;;;N;;;;; +1CF4;VEDIC TONE CANDRA ABOVE;Mn;230;NSM;;;;;N;;;;; +1CF5;VEDIC SIGN JIHVAMULIYA;Lo;0;L;;;;;N;;;;; +1CF6;VEDIC SIGN UPADHMANIYA;Lo;0;L;;;;;N;;;;; 1D00;LATIN LETTER SMALL CAPITAL A;Ll;0;L;;;;;N;;;;; 1D01;LATIN LETTER SMALL CAPITAL AE;Ll;0;L;;;;;N;;;;; 1D02;LATIN SMALL LETTER TURNED AE;Ll;0;L;;;;;N;;;;; @@ -6319,15 +6389,15 @@ 1D5F;MODIFIER LETTER SMALL DELTA;Lm;0;L;<super> 03B4;;;;N;;;;; 1D60;MODIFIER LETTER SMALL GREEK PHI;Lm;0;L;<super> 03C6;;;;N;;;;; 1D61;MODIFIER LETTER SMALL CHI;Lm;0;L;<super> 03C7;;;;N;;;;; -1D62;LATIN SUBSCRIPT SMALL LETTER I;Ll;0;L;<sub> 0069;;;;N;;;;; -1D63;LATIN SUBSCRIPT SMALL LETTER R;Ll;0;L;<sub> 0072;;;;N;;;;; -1D64;LATIN SUBSCRIPT SMALL LETTER U;Ll;0;L;<sub> 0075;;;;N;;;;; -1D65;LATIN SUBSCRIPT SMALL LETTER V;Ll;0;L;<sub> 0076;;;;N;;;;; -1D66;GREEK SUBSCRIPT SMALL LETTER BETA;Ll;0;L;<sub> 03B2;;;;N;;;;; -1D67;GREEK SUBSCRIPT SMALL LETTER GAMMA;Ll;0;L;<sub> 03B3;;;;N;;;;; -1D68;GREEK SUBSCRIPT SMALL LETTER RHO;Ll;0;L;<sub> 03C1;;;;N;;;;; -1D69;GREEK SUBSCRIPT SMALL LETTER PHI;Ll;0;L;<sub> 03C6;;;;N;;;;; -1D6A;GREEK SUBSCRIPT SMALL LETTER CHI;Ll;0;L;<sub> 03C7;;;;N;;;;; +1D62;LATIN SUBSCRIPT SMALL LETTER I;Lm;0;L;<sub> 0069;;;;N;;;;; +1D63;LATIN SUBSCRIPT SMALL LETTER R;Lm;0;L;<sub> 0072;;;;N;;;;; +1D64;LATIN SUBSCRIPT SMALL LETTER U;Lm;0;L;<sub> 0075;;;;N;;;;; +1D65;LATIN SUBSCRIPT SMALL LETTER V;Lm;0;L;<sub> 0076;;;;N;;;;; +1D66;GREEK SUBSCRIPT SMALL LETTER BETA;Lm;0;L;<sub> 03B2;;;;N;;;;; +1D67;GREEK SUBSCRIPT SMALL LETTER GAMMA;Lm;0;L;<sub> 03B3;;;;N;;;;; +1D68;GREEK SUBSCRIPT SMALL LETTER RHO;Lm;0;L;<sub> 03C1;;;;N;;;;; +1D69;GREEK SUBSCRIPT SMALL LETTER PHI;Lm;0;L;<sub> 03C6;;;;N;;;;; +1D6A;GREEK SUBSCRIPT SMALL LETTER CHI;Lm;0;L;<sub> 03C7;;;;N;;;;; 1D6B;LATIN SMALL LETTER UE;Ll;0;L;;;;;N;;;;; 1D6C;LATIN SMALL LETTER B WITH MIDDLE TILDE;Ll;0;L;;;;;N;;;;; 1D6D;LATIN SMALL LETTER D WITH MIDDLE TILDE;Ll;0;L;;;;;N;;;;; @@ -8827,7 +8897,9 @@ 27C8;REVERSE SOLIDUS PRECEDING SUBSET;Sm;0;ON;;;;;Y;;;;; 27C9;SUPERSET PRECEDING SOLIDUS;Sm;0;ON;;;;;Y;;;;; 27CA;VERTICAL BAR WITH HORIZONTAL STROKE;Sm;0;ON;;;;;N;;;;; +27CB;MATHEMATICAL RISING DIAGONAL;Sm;0;ON;;;;;Y;;;;; 27CC;LONG DIVISION;Sm;0;ON;;;;;Y;;;;; +27CD;MATHEMATICAL FALLING DIAGONAL;Sm;0;ON;;;;;Y;;;;; 27CE;SQUARED LOGICAL AND;Sm;0;ON;;;;;N;;;;; 27CF;SQUARED LOGICAL OR;Sm;0;ON;;;;;N;;;;; 27D0;WHITE DIAMOND WITH CENTRED DOT;Sm;0;ON;;;;;N;;;;; @@ -9855,7 +9927,7 @@ 2C79;LATIN SMALL LETTER TURNED R WITH TAIL;Ll;0;L;;;;;N;;;;; 2C7A;LATIN SMALL LETTER O WITH LOW RING INSIDE;Ll;0;L;;;;;N;;;;; 2C7B;LATIN LETTER SMALL CAPITAL TURNED E;Ll;0;L;;;;;N;;;;; -2C7C;LATIN SUBSCRIPT SMALL LETTER J;Ll;0;L;<sub> 006A;;;;N;;;;; +2C7C;LATIN SUBSCRIPT SMALL LETTER J;Lm;0;L;<sub> 006A;;;;N;;;;; 2C7D;MODIFIER LETTER CAPITAL V;Lm;0;L;<super> 0056;;;;N;;;;; 2C7E;LATIN CAPITAL LETTER S WITH SWASH TAIL;Lu;0;L;;;;;N;;;;023F; 2C7F;LATIN CAPITAL LETTER Z WITH SWASH TAIL;Lu;0;L;;;;;N;;;;0240; @@ -9973,6 +10045,8 @@ 2CEF;COPTIC COMBINING NI ABOVE;Mn;230;NSM;;;;;N;;;;; 2CF0;COPTIC COMBINING SPIRITUS ASPER;Mn;230;NSM;;;;;N;;;;; 2CF1;COPTIC COMBINING SPIRITUS LENIS;Mn;230;NSM;;;;;N;;;;; +2CF2;COPTIC CAPITAL LETTER BOHAIRIC KHEI;Lu;0;L;;;;;N;;;;2CF3; +2CF3;COPTIC SMALL LETTER BOHAIRIC KHEI;Ll;0;L;;;;;N;;;2CF2;;2CF2 2CF9;COPTIC OLD NUBIAN FULL STOP;Po;0;ON;;;;;N;;;;; 2CFA;COPTIC OLD NUBIAN DIRECT QUESTION MARK;Po;0;ON;;;;;N;;;;; 2CFB;COPTIC OLD NUBIAN INDIRECT QUESTION MARK;Po;0;ON;;;;;N;;;;; @@ -10018,6 +10092,8 @@ 2D23;GEORGIAN SMALL LETTER WE;Ll;0;L;;;;;N;;;10C3;;10C3 2D24;GEORGIAN SMALL LETTER HAR;Ll;0;L;;;;;N;;;10C4;;10C4 2D25;GEORGIAN SMALL LETTER HOE;Ll;0;L;;;;;N;;;10C5;;10C5 +2D27;GEORGIAN SMALL LETTER YN;Ll;0;L;;;;;N;;;10C7;;10C7 +2D2D;GEORGIAN SMALL LETTER AEN;Ll;0;L;;;;;N;;;10CD;;10CD 2D30;TIFINAGH LETTER YA;Lo;0;L;;;;;N;;;;; 2D31;TIFINAGH LETTER YAB;Lo;0;L;;;;;N;;;;; 2D32;TIFINAGH LETTER YABH;Lo;0;L;;;;;N;;;;; @@ -10072,6 +10148,8 @@ 2D63;TIFINAGH LETTER YAZ;Lo;0;L;;;;;N;;;;; 2D64;TIFINAGH LETTER TAWELLEMET YAZ;Lo;0;L;;;;;N;;;;; 2D65;TIFINAGH LETTER YAZZ;Lo;0;L;;;;;N;;;;; +2D66;TIFINAGH LETTER YE;Lo;0;L;;;;;N;;;;; +2D67;TIFINAGH LETTER YO;Lo;0;L;;;;;N;;;;; 2D6F;TIFINAGH MODIFIER LETTER LABIALIZATION MARK;Lm;0;L;<super> 2D61;;;;N;;;;; 2D70;TIFINAGH SEPARATOR MARK;Po;0;L;;;;;N;;;;; 2D7F;TIFINAGH CONSONANT JOINER;Mn;9;NSM;;;;;N;;;;; @@ -10236,6 +10314,16 @@ 2E2F;VERTICAL TILDE;Lm;0;ON;;;;;N;;;;; 2E30;RING POINT;Po;0;ON;;;;;N;;;;; 2E31;WORD SEPARATOR MIDDLE DOT;Po;0;ON;;;;;N;;;;; +2E32;TURNED COMMA;Po;0;ON;;;;;N;;;;; +2E33;RAISED DOT;Po;0;ON;;;;;N;;;;; +2E34;RAISED COMMA;Po;0;ON;;;;;N;;;;; +2E35;TURNED SEMICOLON;Po;0;ON;;;;;N;;;;; +2E36;DAGGER WITH LEFT GUARD;Po;0;ON;;;;;N;;;;; +2E37;DAGGER WITH RIGHT GUARD;Po;0;ON;;;;;N;;;;; +2E38;TURNED DAGGER;Po;0;ON;;;;;N;;;;; +2E39;TOP HALF SECTION SIGN;Po;0;ON;;;;;N;;;;; +2E3A;TWO-EM DASH;Pd;0;ON;;;;;N;;;;; +2E3B;THREE-EM DASH;Pd;0;ON;;;;;N;;;;; 2E80;CJK RADICAL REPEAT;So;0;ON;;;;;N;;;;; 2E81;CJK RADICAL CLIFF;So;0;ON;;;;;N;;;;; 2E82;CJK RADICAL SECOND ONE;So;0;ON;;;;;N;;;;; @@ -10623,8 +10711,8 @@ 302B;IDEOGRAPHIC RISING TONE MARK;Mn;228;NSM;;;;;N;;;;; 302C;IDEOGRAPHIC DEPARTING TONE MARK;Mn;232;NSM;;;;;N;;;;; 302D;IDEOGRAPHIC ENTERING TONE MARK;Mn;222;NSM;;;;;N;;;;; -302E;HANGUL SINGLE DOT TONE MARK;Mn;224;NSM;;;;;N;;;;; -302F;HANGUL DOUBLE DOT TONE MARK;Mn;224;NSM;;;;;N;;;;; +302E;HANGUL SINGLE DOT TONE MARK;Mc;224;L;;;;;N;;;;; +302F;HANGUL DOUBLE DOT TONE MARK;Mc;224;L;;;;;N;;;;; 3030;WAVY DASH;Pd;0;ON;;;;;N;;;;; 3031;VERTICAL KANA REPEAT MARK;Lm;0;L;;;;;N;;;;; 3032;VERTICAL KANA REPEAT WITH VOICED SOUND MARK;Lm;0;L;;;;;N;;;;; @@ -11131,14 +11219,14 @@ 3245;CIRCLED IDEOGRAPH KINDERGARTEN;So;0;L;<circle> 5E7C;;;;N;;;;; 3246;CIRCLED IDEOGRAPH SCHOOL;So;0;L;<circle> 6587;;;;N;;;;; 3247;CIRCLED IDEOGRAPH KOTO;So;0;L;<circle> 7B8F;;;;N;;;;; -3248;CIRCLED NUMBER TEN ON BLACK SQUARE;So;0;L;;;;;N;;;;; -3249;CIRCLED NUMBER TWENTY ON BLACK SQUARE;So;0;L;;;;;N;;;;; -324A;CIRCLED NUMBER THIRTY ON BLACK SQUARE;So;0;L;;;;;N;;;;; -324B;CIRCLED NUMBER FORTY ON BLACK SQUARE;So;0;L;;;;;N;;;;; -324C;CIRCLED NUMBER FIFTY ON BLACK SQUARE;So;0;L;;;;;N;;;;; -324D;CIRCLED NUMBER SIXTY ON BLACK SQUARE;So;0;L;;;;;N;;;;; -324E;CIRCLED NUMBER SEVENTY ON BLACK SQUARE;So;0;L;;;;;N;;;;; -324F;CIRCLED NUMBER EIGHTY ON BLACK SQUARE;So;0;L;;;;;N;;;;; +3248;CIRCLED NUMBER TEN ON BLACK SQUARE;No;0;L;;;;10;N;;;;; +3249;CIRCLED NUMBER TWENTY ON BLACK SQUARE;No;0;L;;;;20;N;;;;; +324A;CIRCLED NUMBER THIRTY ON BLACK SQUARE;No;0;L;;;;30;N;;;;; +324B;CIRCLED NUMBER FORTY ON BLACK SQUARE;No;0;L;;;;40;N;;;;; +324C;CIRCLED NUMBER FIFTY ON BLACK SQUARE;No;0;L;;;;50;N;;;;; +324D;CIRCLED NUMBER SIXTY ON BLACK SQUARE;No;0;L;;;;60;N;;;;; +324E;CIRCLED NUMBER SEVENTY ON BLACK SQUARE;No;0;L;;;;70;N;;;;; +324F;CIRCLED NUMBER EIGHTY ON BLACK SQUARE;No;0;L;;;;80;N;;;;; 3250;PARTNERSHIP SIGN;So;0;ON;<square> 0050 0054 0045;;;;N;;;;; 3251;CIRCLED NUMBER TWENTY ONE;No;0;ON;<circle> 0032 0031;;;21;N;;;;; 3252;CIRCLED NUMBER TWENTY TWO;No;0;ON;<circle> 0032 0032;;;22;N;;;;; @@ -11637,7 +11725,7 @@ 4DFE;HEXAGRAM FOR AFTER COMPLETION;So;0;ON;;;;;N;;;;; 4DFF;HEXAGRAM FOR BEFORE COMPLETION;So;0;ON;;;;;N;;;;; 4E00;<CJK Ideograph, First>;Lo;0;L;;;;;N;;;;; -9FCB;<CJK Ideograph, Last>;Lo;0;L;;;;;N;;;;; +9FCC;<CJK Ideograph, Last>;Lo;0;L;;;;;N;;;;; A000;YI SYLLABLE IT;Lo;0;L;;;;;N;;;;; A001;YI SYLLABLE IX;Lo;0;L;;;;;N;;;;; A002;YI SYLLABLE I;Lo;0;L;;;;;N;;;;; @@ -13258,6 +13346,14 @@ A670;COMBINING CYRILLIC TEN MILLIONS SIGN;Me;0;NSM;;;;;N;;;;; A671;COMBINING CYRILLIC HUNDRED MILLIONS SIGN;Me;0;NSM;;;;;N;;;;; A672;COMBINING CYRILLIC THOUSAND MILLIONS SIGN;Me;0;NSM;;;;;N;;;;; A673;SLAVONIC ASTERISK;Po;0;ON;;;;;N;;;;; +A674;COMBINING CYRILLIC LETTER UKRAINIAN IE;Mn;230;NSM;;;;;N;;;;; +A675;COMBINING CYRILLIC LETTER I;Mn;230;NSM;;;;;N;;;;; +A676;COMBINING CYRILLIC LETTER YI;Mn;230;NSM;;;;;N;;;;; +A677;COMBINING CYRILLIC LETTER U;Mn;230;NSM;;;;;N;;;;; +A678;COMBINING CYRILLIC LETTER HARD SIGN;Mn;230;NSM;;;;;N;;;;; +A679;COMBINING CYRILLIC LETTER YERU;Mn;230;NSM;;;;;N;;;;; +A67A;COMBINING CYRILLIC LETTER SOFT SIGN;Mn;230;NSM;;;;;N;;;;; +A67B;COMBINING CYRILLIC LETTER OMEGA;Mn;230;NSM;;;;;N;;;;; A67C;COMBINING CYRILLIC KAVYKA;Mn;230;NSM;;;;;N;;;;; A67D;COMBINING CYRILLIC PAYEROK;Mn;230;NSM;;;;;N;;;;; A67E;CYRILLIC KAVYKA;Po;0;ON;;;;;N;;;;; @@ -13286,6 +13382,7 @@ A694;CYRILLIC CAPITAL LETTER HWE;Lu;0;L;;;;;N;;;;A695; A695;CYRILLIC SMALL LETTER HWE;Ll;0;L;;;;;N;;;A694;;A694 A696;CYRILLIC CAPITAL LETTER SHWE;Lu;0;L;;;;;N;;;;A697; A697;CYRILLIC SMALL LETTER SHWE;Ll;0;L;;;;;N;;;A696;;A696 +A69F;COMBINING CYRILLIC LETTER IOTIFIED E;Mn;230;NSM;;;;;N;;;;; A6A0;BAMUM LETTER A;Lo;0;L;;;;;N;;;;; A6A1;BAMUM LETTER KA;Lo;0;L;;;;;N;;;;; A6A2;BAMUM LETTER U;Lo;0;L;;;;;N;;;;; @@ -13519,6 +13616,8 @@ A78D;LATIN CAPITAL LETTER TURNED H;Lu;0;L;;;;;N;;;;0265; A78E;LATIN SMALL LETTER L WITH RETROFLEX HOOK AND BELT;Ll;0;L;;;;;N;;;;; A790;LATIN CAPITAL LETTER N WITH DESCENDER;Lu;0;L;;;;;N;;;;A791; A791;LATIN SMALL LETTER N WITH DESCENDER;Ll;0;L;;;;;N;;;A790;;A790 +A792;LATIN CAPITAL LETTER C WITH BAR;Lu;0;L;;;;;N;;;;A793; +A793;LATIN SMALL LETTER C WITH BAR;Ll;0;L;;;;;N;;;A792;;A792 A7A0;LATIN CAPITAL LETTER G WITH OBLIQUE STROKE;Lu;0;L;;;;;N;;;;A7A1; A7A1;LATIN SMALL LETTER G WITH OBLIQUE STROKE;Ll;0;L;;;;;N;;;A7A0;;A7A0 A7A2;LATIN CAPITAL LETTER K WITH OBLIQUE STROKE;Lu;0;L;;;;;N;;;;A7A3; @@ -13529,6 +13628,9 @@ A7A6;LATIN CAPITAL LETTER R WITH OBLIQUE STROKE;Lu;0;L;;;;;N;;;;A7A7; A7A7;LATIN SMALL LETTER R WITH OBLIQUE STROKE;Ll;0;L;;;;;N;;;A7A6;;A7A6 A7A8;LATIN CAPITAL LETTER S WITH OBLIQUE STROKE;Lu;0;L;;;;;N;;;;A7A9; A7A9;LATIN SMALL LETTER S WITH OBLIQUE STROKE;Ll;0;L;;;;;N;;;A7A8;;A7A8 +A7AA;LATIN CAPITAL LETTER H WITH HOOK;Lu;0;L;;;;;N;;;;0266; +A7F8;MODIFIER LETTER CAPITAL H WITH STROKE;Lm;0;L;<super> 0126;;;;N;;;;; +A7F9;MODIFIER LETTER SMALL LIGATURE OE;Lm;0;L;<super> 0153;;;;N;;;;; A7FA;LATIN LETTER SMALL CAPITAL TURNED M;Ll;0;L;;;;;N;;;;; A7FB;LATIN EPIGRAPHIC LETTER REVERSED F;Lo;0;L;;;;;N;;;;; A7FC;LATIN EPIGRAPHIC LETTER REVERSED P;Lo;0;L;;;;;N;;;;; @@ -14142,6 +14244,29 @@ AADC;TAI VIET SYMBOL NUENG;Lo;0;L;;;;;N;;;;; AADD;TAI VIET SYMBOL SAM;Lm;0;L;;;;;N;;;;; AADE;TAI VIET SYMBOL HO HOI;Po;0;L;;;;;N;;;;; AADF;TAI VIET SYMBOL KOI KOI;Po;0;L;;;;;N;;;;; +AAE0;MEETEI MAYEK LETTER E;Lo;0;L;;;;;N;;;;; +AAE1;MEETEI MAYEK LETTER O;Lo;0;L;;;;;N;;;;; +AAE2;MEETEI MAYEK LETTER CHA;Lo;0;L;;;;;N;;;;; +AAE3;MEETEI MAYEK LETTER NYA;Lo;0;L;;;;;N;;;;; +AAE4;MEETEI MAYEK LETTER TTA;Lo;0;L;;;;;N;;;;; +AAE5;MEETEI MAYEK LETTER TTHA;Lo;0;L;;;;;N;;;;; +AAE6;MEETEI MAYEK LETTER DDA;Lo;0;L;;;;;N;;;;; +AAE7;MEETEI MAYEK LETTER DDHA;Lo;0;L;;;;;N;;;;; +AAE8;MEETEI MAYEK LETTER NNA;Lo;0;L;;;;;N;;;;; +AAE9;MEETEI MAYEK LETTER SHA;Lo;0;L;;;;;N;;;;; +AAEA;MEETEI MAYEK LETTER SSA;Lo;0;L;;;;;N;;;;; +AAEB;MEETEI MAYEK VOWEL SIGN II;Mc;0;L;;;;;N;;;;; +AAEC;MEETEI MAYEK VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;; +AAED;MEETEI MAYEK VOWEL SIGN AAI;Mn;0;NSM;;;;;N;;;;; +AAEE;MEETEI MAYEK VOWEL SIGN AU;Mc;0;L;;;;;N;;;;; +AAEF;MEETEI MAYEK VOWEL SIGN AAU;Mc;0;L;;;;;N;;;;; +AAF0;MEETEI MAYEK CHEIKHAN;Po;0;L;;;;;N;;;;; +AAF1;MEETEI MAYEK AHANG KHUDAM;Po;0;L;;;;;N;;;;; +AAF2;MEETEI MAYEK ANJI;Lo;0;L;;;;;N;;;;; +AAF3;MEETEI MAYEK SYLLABLE REPETITION MARK;Lm;0;L;;;;;N;;;;; +AAF4;MEETEI MAYEK WORD REPETITION MARK;Lm;0;L;;;;;N;;;;; +AAF5;MEETEI MAYEK VOWEL SIGN VISARGA;Mc;0;L;;;;;N;;;;; +AAF6;MEETEI MAYEK VIRAMA;Mn;9;NSM;;;;;N;;;;; AB01;ETHIOPIC SYLLABLE TTHU;Lo;0;L;;;;;N;;;;; AB02;ETHIOPIC SYLLABLE TTHI;Lo;0;L;;;;;N;;;;; AB03;ETHIOPIC SYLLABLE TTHAA;Lo;0;L;;;;;N;;;;; @@ -14614,6 +14739,8 @@ FA2A;CJK COMPATIBILITY IDEOGRAPH-FA2A;Lo;0;L;98EF;;;;N;;;;; FA2B;CJK COMPATIBILITY IDEOGRAPH-FA2B;Lo;0;L;98FC;;;;N;;;;; FA2C;CJK COMPATIBILITY IDEOGRAPH-FA2C;Lo;0;L;9928;;;;N;;;;; FA2D;CJK COMPATIBILITY IDEOGRAPH-FA2D;Lo;0;L;9DB4;;;;N;;;;; +FA2E;CJK COMPATIBILITY IDEOGRAPH-FA2E;Lo;0;L;90DE;;;;N;;;;; +FA2F;CJK COMPATIBILITY IDEOGRAPH-FA2F;Lo;0;L;96B7;;;;N;;;;; FA30;CJK COMPATIBILITY IDEOGRAPH-FA30;Lo;0;L;4FAE;;;;N;;;;; FA31;CJK COMPATIBILITY IDEOGRAPH-FA31;Lo;0;L;50E7;;;;N;;;;; FA32;CJK COMPATIBILITY IDEOGRAPH-FA32;Lo;0;L;514D;;;;N;;;;; @@ -16126,7 +16253,7 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 100FA;LINEAR B IDEOGRAM VESSEL B305;Lo;0;L;;;;;N;;;;; 10100;AEGEAN WORD SEPARATOR LINE;Po;0;L;;;;;N;;;;; 10101;AEGEAN WORD SEPARATOR DOT;Po;0;ON;;;;;N;;;;; -10102;AEGEAN CHECK MARK;So;0;L;;;;;N;;;;; +10102;AEGEAN CHECK MARK;Po;0;L;;;;;N;;;;; 10107;AEGEAN NUMBER ONE;No;0;L;;;;1;N;;;;; 10108;AEGEAN NUMBER TWO;No;0;L;;;;2;N;;;;; 10109;AEGEAN NUMBER THREE;No;0;L;;;;3;N;;;;; @@ -16845,6 +16972,64 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 10938;LYDIAN LETTER NN;Lo;0;R;;;;;N;;;;; 10939;LYDIAN LETTER C;Lo;0;R;;;;;N;;;;; 1093F;LYDIAN TRIANGULAR MARK;Po;0;R;;;;;N;;;;; +10980;MEROITIC HIEROGLYPHIC LETTER A;Lo;0;R;;;;;N;;;;; +10981;MEROITIC HIEROGLYPHIC LETTER E;Lo;0;R;;;;;N;;;;; +10982;MEROITIC HIEROGLYPHIC LETTER I;Lo;0;R;;;;;N;;;;; +10983;MEROITIC HIEROGLYPHIC LETTER O;Lo;0;R;;;;;N;;;;; +10984;MEROITIC HIEROGLYPHIC LETTER YA;Lo;0;R;;;;;N;;;;; +10985;MEROITIC HIEROGLYPHIC LETTER WA;Lo;0;R;;;;;N;;;;; +10986;MEROITIC HIEROGLYPHIC LETTER BA;Lo;0;R;;;;;N;;;;; +10987;MEROITIC HIEROGLYPHIC LETTER BA-2;Lo;0;R;;;;;N;;;;; +10988;MEROITIC HIEROGLYPHIC LETTER PA;Lo;0;R;;;;;N;;;;; +10989;MEROITIC HIEROGLYPHIC LETTER MA;Lo;0;R;;;;;N;;;;; +1098A;MEROITIC HIEROGLYPHIC LETTER NA;Lo;0;R;;;;;N;;;;; +1098B;MEROITIC HIEROGLYPHIC LETTER NA-2;Lo;0;R;;;;;N;;;;; +1098C;MEROITIC HIEROGLYPHIC LETTER NE;Lo;0;R;;;;;N;;;;; +1098D;MEROITIC HIEROGLYPHIC LETTER NE-2;Lo;0;R;;;;;N;;;;; +1098E;MEROITIC HIEROGLYPHIC LETTER RA;Lo;0;R;;;;;N;;;;; +1098F;MEROITIC HIEROGLYPHIC LETTER RA-2;Lo;0;R;;;;;N;;;;; +10990;MEROITIC HIEROGLYPHIC LETTER LA;Lo;0;R;;;;;N;;;;; +10991;MEROITIC HIEROGLYPHIC LETTER KHA;Lo;0;R;;;;;N;;;;; +10992;MEROITIC HIEROGLYPHIC LETTER HHA;Lo;0;R;;;;;N;;;;; +10993;MEROITIC HIEROGLYPHIC LETTER SA;Lo;0;R;;;;;N;;;;; +10994;MEROITIC HIEROGLYPHIC LETTER SA-2;Lo;0;R;;;;;N;;;;; +10995;MEROITIC HIEROGLYPHIC LETTER SE;Lo;0;R;;;;;N;;;;; +10996;MEROITIC HIEROGLYPHIC LETTER KA;Lo;0;R;;;;;N;;;;; +10997;MEROITIC HIEROGLYPHIC LETTER QA;Lo;0;R;;;;;N;;;;; +10998;MEROITIC HIEROGLYPHIC LETTER TA;Lo;0;R;;;;;N;;;;; +10999;MEROITIC HIEROGLYPHIC LETTER TA-2;Lo;0;R;;;;;N;;;;; +1099A;MEROITIC HIEROGLYPHIC LETTER TE;Lo;0;R;;;;;N;;;;; +1099B;MEROITIC HIEROGLYPHIC LETTER TE-2;Lo;0;R;;;;;N;;;;; +1099C;MEROITIC HIEROGLYPHIC LETTER TO;Lo;0;R;;;;;N;;;;; +1099D;MEROITIC HIEROGLYPHIC LETTER DA;Lo;0;R;;;;;N;;;;; +1099E;MEROITIC HIEROGLYPHIC SYMBOL VIDJ;Lo;0;R;;;;;N;;;;; +1099F;MEROITIC HIEROGLYPHIC SYMBOL VIDJ-2;Lo;0;R;;;;;N;;;;; +109A0;MEROITIC CURSIVE LETTER A;Lo;0;R;;;;;N;;;;; +109A1;MEROITIC CURSIVE LETTER E;Lo;0;R;;;;;N;;;;; +109A2;MEROITIC CURSIVE LETTER I;Lo;0;R;;;;;N;;;;; +109A3;MEROITIC CURSIVE LETTER O;Lo;0;R;;;;;N;;;;; +109A4;MEROITIC CURSIVE LETTER YA;Lo;0;R;;;;;N;;;;; +109A5;MEROITIC CURSIVE LETTER WA;Lo;0;R;;;;;N;;;;; +109A6;MEROITIC CURSIVE LETTER BA;Lo;0;R;;;;;N;;;;; +109A7;MEROITIC CURSIVE LETTER PA;Lo;0;R;;;;;N;;;;; +109A8;MEROITIC CURSIVE LETTER MA;Lo;0;R;;;;;N;;;;; +109A9;MEROITIC CURSIVE LETTER NA;Lo;0;R;;;;;N;;;;; +109AA;MEROITIC CURSIVE LETTER NE;Lo;0;R;;;;;N;;;;; +109AB;MEROITIC CURSIVE LETTER RA;Lo;0;R;;;;;N;;;;; +109AC;MEROITIC CURSIVE LETTER LA;Lo;0;R;;;;;N;;;;; +109AD;MEROITIC CURSIVE LETTER KHA;Lo;0;R;;;;;N;;;;; +109AE;MEROITIC CURSIVE LETTER HHA;Lo;0;R;;;;;N;;;;; +109AF;MEROITIC CURSIVE LETTER SA;Lo;0;R;;;;;N;;;;; +109B0;MEROITIC CURSIVE LETTER ARCHAIC SA;Lo;0;R;;;;;N;;;;; +109B1;MEROITIC CURSIVE LETTER SE;Lo;0;R;;;;;N;;;;; +109B2;MEROITIC CURSIVE LETTER KA;Lo;0;R;;;;;N;;;;; +109B3;MEROITIC CURSIVE LETTER QA;Lo;0;R;;;;;N;;;;; +109B4;MEROITIC CURSIVE LETTER TA;Lo;0;R;;;;;N;;;;; +109B5;MEROITIC CURSIVE LETTER TE;Lo;0;R;;;;;N;;;;; +109B6;MEROITIC CURSIVE LETTER TO;Lo;0;R;;;;;N;;;;; +109B7;MEROITIC CURSIVE LETTER DA;Lo;0;R;;;;;N;;;;; +109BE;MEROITIC CURSIVE LOGOGRAM RMT;Lo;0;R;;;;;N;;;;; +109BF;MEROITIC CURSIVE LOGOGRAM IMN;Lo;0;R;;;;;N;;;;; 10A00;KHAROSHTHI LETTER A;Lo;0;R;;;;;N;;;;; 10A01;KHAROSHTHI VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;; 10A02;KHAROSHTHI VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;; @@ -17338,6 +17523,257 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 110BF;KAITHI DOUBLE SECTION MARK;Po;0;L;;;;;N;;;;; 110C0;KAITHI DANDA;Po;0;L;;;;;N;;;;; 110C1;KAITHI DOUBLE DANDA;Po;0;L;;;;;N;;;;; +110D0;SORA SOMPENG LETTER SAH;Lo;0;L;;;;;N;;;;; +110D1;SORA SOMPENG LETTER TAH;Lo;0;L;;;;;N;;;;; +110D2;SORA SOMPENG LETTER BAH;Lo;0;L;;;;;N;;;;; +110D3;SORA SOMPENG LETTER CAH;Lo;0;L;;;;;N;;;;; +110D4;SORA SOMPENG LETTER DAH;Lo;0;L;;;;;N;;;;; +110D5;SORA SOMPENG LETTER GAH;Lo;0;L;;;;;N;;;;; +110D6;SORA SOMPENG LETTER MAH;Lo;0;L;;;;;N;;;;; +110D7;SORA SOMPENG LETTER NGAH;Lo;0;L;;;;;N;;;;; +110D8;SORA SOMPENG LETTER LAH;Lo;0;L;;;;;N;;;;; +110D9;SORA SOMPENG LETTER NAH;Lo;0;L;;;;;N;;;;; +110DA;SORA SOMPENG LETTER VAH;Lo;0;L;;;;;N;;;;; +110DB;SORA SOMPENG LETTER PAH;Lo;0;L;;;;;N;;;;; +110DC;SORA SOMPENG LETTER YAH;Lo;0;L;;;;;N;;;;; +110DD;SORA SOMPENG LETTER RAH;Lo;0;L;;;;;N;;;;; +110DE;SORA SOMPENG LETTER HAH;Lo;0;L;;;;;N;;;;; +110DF;SORA SOMPENG LETTER KAH;Lo;0;L;;;;;N;;;;; +110E0;SORA SOMPENG LETTER JAH;Lo;0;L;;;;;N;;;;; +110E1;SORA SOMPENG LETTER NYAH;Lo;0;L;;;;;N;;;;; +110E2;SORA SOMPENG LETTER AH;Lo;0;L;;;;;N;;;;; +110E3;SORA SOMPENG LETTER EEH;Lo;0;L;;;;;N;;;;; +110E4;SORA SOMPENG LETTER IH;Lo;0;L;;;;;N;;;;; +110E5;SORA SOMPENG LETTER UH;Lo;0;L;;;;;N;;;;; +110E6;SORA SOMPENG LETTER OH;Lo;0;L;;;;;N;;;;; +110E7;SORA SOMPENG LETTER EH;Lo;0;L;;;;;N;;;;; +110E8;SORA SOMPENG LETTER MAE;Lo;0;L;;;;;N;;;;; +110F0;SORA SOMPENG DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; +110F1;SORA SOMPENG DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; +110F2;SORA SOMPENG DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; +110F3;SORA SOMPENG DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; +110F4;SORA SOMPENG DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; +110F5;SORA SOMPENG DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; +110F6;SORA SOMPENG DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; +110F7;SORA SOMPENG DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; +110F8;SORA SOMPENG DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; +110F9;SORA SOMPENG DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; +11100;CHAKMA SIGN CANDRABINDU;Mn;230;NSM;;;;;N;;;;; +11101;CHAKMA SIGN ANUSVARA;Mn;230;NSM;;;;;N;;;;; +11102;CHAKMA SIGN VISARGA;Mn;230;NSM;;;;;N;;;;; +11103;CHAKMA LETTER AA;Lo;0;L;;;;;N;;;;; +11104;CHAKMA LETTER I;Lo;0;L;;;;;N;;;;; +11105;CHAKMA LETTER U;Lo;0;L;;;;;N;;;;; +11106;CHAKMA LETTER E;Lo;0;L;;;;;N;;;;; +11107;CHAKMA LETTER KAA;Lo;0;L;;;;;N;;;;; +11108;CHAKMA LETTER KHAA;Lo;0;L;;;;;N;;;;; +11109;CHAKMA LETTER GAA;Lo;0;L;;;;;N;;;;; +1110A;CHAKMA LETTER GHAA;Lo;0;L;;;;;N;;;;; +1110B;CHAKMA LETTER NGAA;Lo;0;L;;;;;N;;;;; +1110C;CHAKMA LETTER CAA;Lo;0;L;;;;;N;;;;; +1110D;CHAKMA LETTER CHAA;Lo;0;L;;;;;N;;;;; +1110E;CHAKMA LETTER JAA;Lo;0;L;;;;;N;;;;; +1110F;CHAKMA LETTER JHAA;Lo;0;L;;;;;N;;;;; +11110;CHAKMA LETTER NYAA;Lo;0;L;;;;;N;;;;; +11111;CHAKMA LETTER TTAA;Lo;0;L;;;;;N;;;;; +11112;CHAKMA LETTER TTHAA;Lo;0;L;;;;;N;;;;; +11113;CHAKMA LETTER DDAA;Lo;0;L;;;;;N;;;;; +11114;CHAKMA LETTER DDHAA;Lo;0;L;;;;;N;;;;; +11115;CHAKMA LETTER NNAA;Lo;0;L;;;;;N;;;;; +11116;CHAKMA LETTER TAA;Lo;0;L;;;;;N;;;;; +11117;CHAKMA LETTER THAA;Lo;0;L;;;;;N;;;;; +11118;CHAKMA LETTER DAA;Lo;0;L;;;;;N;;;;; +11119;CHAKMA LETTER DHAA;Lo;0;L;;;;;N;;;;; +1111A;CHAKMA LETTER NAA;Lo;0;L;;;;;N;;;;; +1111B;CHAKMA LETTER PAA;Lo;0;L;;;;;N;;;;; +1111C;CHAKMA LETTER PHAA;Lo;0;L;;;;;N;;;;; +1111D;CHAKMA LETTER BAA;Lo;0;L;;;;;N;;;;; +1111E;CHAKMA LETTER BHAA;Lo;0;L;;;;;N;;;;; +1111F;CHAKMA LETTER MAA;Lo;0;L;;;;;N;;;;; +11120;CHAKMA LETTER YYAA;Lo;0;L;;;;;N;;;;; +11121;CHAKMA LETTER YAA;Lo;0;L;;;;;N;;;;; +11122;CHAKMA LETTER RAA;Lo;0;L;;;;;N;;;;; +11123;CHAKMA LETTER LAA;Lo;0;L;;;;;N;;;;; +11124;CHAKMA LETTER WAA;Lo;0;L;;;;;N;;;;; +11125;CHAKMA LETTER SAA;Lo;0;L;;;;;N;;;;; +11126;CHAKMA LETTER HAA;Lo;0;L;;;;;N;;;;; +11127;CHAKMA VOWEL SIGN A;Mn;0;NSM;;;;;N;;;;; +11128;CHAKMA VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;; +11129;CHAKMA VOWEL SIGN II;Mn;0;NSM;;;;;N;;;;; +1112A;CHAKMA VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;; +1112B;CHAKMA VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;; +1112C;CHAKMA VOWEL SIGN E;Mc;0;L;;;;;N;;;;; +1112D;CHAKMA VOWEL SIGN AI;Mn;0;NSM;;;;;N;;;;; +1112E;CHAKMA VOWEL SIGN O;Mn;0;NSM;11131 11127;;;;N;;;;; +1112F;CHAKMA VOWEL SIGN AU;Mn;0;NSM;11132 11127;;;;N;;;;; +11130;CHAKMA VOWEL SIGN OI;Mn;0;NSM;;;;;N;;;;; +11131;CHAKMA O MARK;Mn;0;NSM;;;;;N;;;;; +11132;CHAKMA AU MARK;Mn;0;NSM;;;;;N;;;;; +11133;CHAKMA VIRAMA;Mn;9;NSM;;;;;N;;;;; +11134;CHAKMA MAAYYAA;Mn;9;NSM;;;;;N;;;;; +11136;CHAKMA DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; +11137;CHAKMA DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; +11138;CHAKMA DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; +11139;CHAKMA DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; +1113A;CHAKMA DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; +1113B;CHAKMA DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; +1113C;CHAKMA DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; +1113D;CHAKMA DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; +1113E;CHAKMA DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; +1113F;CHAKMA DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; +11140;CHAKMA SECTION MARK;Po;0;L;;;;;N;;;;; +11141;CHAKMA DANDA;Po;0;L;;;;;N;;;;; +11142;CHAKMA DOUBLE DANDA;Po;0;L;;;;;N;;;;; +11143;CHAKMA QUESTION MARK;Po;0;L;;;;;N;;;;; +11180;SHARADA SIGN CANDRABINDU;Mn;0;NSM;;;;;N;;;;; +11181;SHARADA SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;; +11182;SHARADA SIGN VISARGA;Mc;0;L;;;;;N;;;;; +11183;SHARADA LETTER A;Lo;0;L;;;;;N;;;;; +11184;SHARADA LETTER AA;Lo;0;L;;;;;N;;;;; +11185;SHARADA LETTER I;Lo;0;L;;;;;N;;;;; +11186;SHARADA LETTER II;Lo;0;L;;;;;N;;;;; +11187;SHARADA LETTER U;Lo;0;L;;;;;N;;;;; +11188;SHARADA LETTER UU;Lo;0;L;;;;;N;;;;; +11189;SHARADA LETTER VOCALIC R;Lo;0;L;;;;;N;;;;; +1118A;SHARADA LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;; +1118B;SHARADA LETTER VOCALIC L;Lo;0;L;;;;;N;;;;; +1118C;SHARADA LETTER VOCALIC LL;Lo;0;L;;;;;N;;;;; +1118D;SHARADA LETTER E;Lo;0;L;;;;;N;;;;; +1118E;SHARADA LETTER AI;Lo;0;L;;;;;N;;;;; +1118F;SHARADA LETTER O;Lo;0;L;;;;;N;;;;; +11190;SHARADA LETTER AU;Lo;0;L;;;;;N;;;;; +11191;SHARADA LETTER KA;Lo;0;L;;;;;N;;;;; +11192;SHARADA LETTER KHA;Lo;0;L;;;;;N;;;;; +11193;SHARADA LETTER GA;Lo;0;L;;;;;N;;;;; +11194;SHARADA LETTER GHA;Lo;0;L;;;;;N;;;;; +11195;SHARADA LETTER NGA;Lo;0;L;;;;;N;;;;; +11196;SHARADA LETTER CA;Lo;0;L;;;;;N;;;;; +11197;SHARADA LETTER CHA;Lo;0;L;;;;;N;;;;; +11198;SHARADA LETTER JA;Lo;0;L;;;;;N;;;;; +11199;SHARADA LETTER JHA;Lo;0;L;;;;;N;;;;; +1119A;SHARADA LETTER NYA;Lo;0;L;;;;;N;;;;; +1119B;SHARADA LETTER TTA;Lo;0;L;;;;;N;;;;; +1119C;SHARADA LETTER TTHA;Lo;0;L;;;;;N;;;;; +1119D;SHARADA LETTER DDA;Lo;0;L;;;;;N;;;;; +1119E;SHARADA LETTER DDHA;Lo;0;L;;;;;N;;;;; +1119F;SHARADA LETTER NNA;Lo;0;L;;;;;N;;;;; +111A0;SHARADA LETTER TA;Lo;0;L;;;;;N;;;;; +111A1;SHARADA LETTER THA;Lo;0;L;;;;;N;;;;; +111A2;SHARADA LETTER DA;Lo;0;L;;;;;N;;;;; +111A3;SHARADA LETTER DHA;Lo;0;L;;;;;N;;;;; +111A4;SHARADA LETTER NA;Lo;0;L;;;;;N;;;;; +111A5;SHARADA LETTER PA;Lo;0;L;;;;;N;;;;; +111A6;SHARADA LETTER PHA;Lo;0;L;;;;;N;;;;; +111A7;SHARADA LETTER BA;Lo;0;L;;;;;N;;;;; +111A8;SHARADA LETTER BHA;Lo;0;L;;;;;N;;;;; +111A9;SHARADA LETTER MA;Lo;0;L;;;;;N;;;;; +111AA;SHARADA LETTER YA;Lo;0;L;;;;;N;;;;; +111AB;SHARADA LETTER RA;Lo;0;L;;;;;N;;;;; +111AC;SHARADA LETTER LA;Lo;0;L;;;;;N;;;;; +111AD;SHARADA LETTER LLA;Lo;0;L;;;;;N;;;;; +111AE;SHARADA LETTER VA;Lo;0;L;;;;;N;;;;; +111AF;SHARADA LETTER SHA;Lo;0;L;;;;;N;;;;; +111B0;SHARADA LETTER SSA;Lo;0;L;;;;;N;;;;; +111B1;SHARADA LETTER SA;Lo;0;L;;;;;N;;;;; +111B2;SHARADA LETTER HA;Lo;0;L;;;;;N;;;;; +111B3;SHARADA VOWEL SIGN AA;Mc;0;L;;;;;N;;;;; +111B4;SHARADA VOWEL SIGN I;Mc;0;L;;;;;N;;;;; +111B5;SHARADA VOWEL SIGN II;Mc;0;L;;;;;N;;;;; +111B6;SHARADA VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;; +111B7;SHARADA VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;; +111B8;SHARADA VOWEL SIGN VOCALIC R;Mn;0;NSM;;;;;N;;;;; +111B9;SHARADA VOWEL SIGN VOCALIC RR;Mn;0;NSM;;;;;N;;;;; +111BA;SHARADA VOWEL SIGN VOCALIC L;Mn;0;NSM;;;;;N;;;;; +111BB;SHARADA VOWEL SIGN VOCALIC LL;Mn;0;NSM;;;;;N;;;;; +111BC;SHARADA VOWEL SIGN E;Mn;0;NSM;;;;;N;;;;; +111BD;SHARADA VOWEL SIGN AI;Mn;0;NSM;;;;;N;;;;; +111BE;SHARADA VOWEL SIGN O;Mn;0;NSM;;;;;N;;;;; +111BF;SHARADA VOWEL SIGN AU;Mc;0;L;;;;;N;;;;; +111C0;SHARADA SIGN VIRAMA;Mc;9;L;;;;;N;;;;; +111C1;SHARADA SIGN AVAGRAHA;Lo;0;L;;;;;N;;;;; +111C2;SHARADA SIGN JIHVAMULIYA;Lo;0;L;;;;;N;;;;; +111C3;SHARADA SIGN UPADHMANIYA;Lo;0;L;;;;;N;;;;; +111C4;SHARADA OM;Lo;0;L;;;;;N;;;;; +111C5;SHARADA DANDA;Po;0;L;;;;;N;;;;; +111C6;SHARADA DOUBLE DANDA;Po;0;L;;;;;N;;;;; +111C7;SHARADA ABBREVIATION SIGN;Po;0;L;;;;;N;;;;; +111C8;SHARADA SEPARATOR;Po;0;L;;;;;N;;;;; +111D0;SHARADA DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; +111D1;SHARADA DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; +111D2;SHARADA DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; +111D3;SHARADA DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; +111D4;SHARADA DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; +111D5;SHARADA DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; +111D6;SHARADA DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; +111D7;SHARADA DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; +111D8;SHARADA DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; +111D9;SHARADA DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; +11680;TAKRI LETTER A;Lo;0;L;;;;;N;;;;; +11681;TAKRI LETTER AA;Lo;0;L;;;;;N;;;;; +11682;TAKRI LETTER I;Lo;0;L;;;;;N;;;;; +11683;TAKRI LETTER II;Lo;0;L;;;;;N;;;;; +11684;TAKRI LETTER U;Lo;0;L;;;;;N;;;;; +11685;TAKRI LETTER UU;Lo;0;L;;;;;N;;;;; +11686;TAKRI LETTER E;Lo;0;L;;;;;N;;;;; +11687;TAKRI LETTER AI;Lo;0;L;;;;;N;;;;; +11688;TAKRI LETTER O;Lo;0;L;;;;;N;;;;; +11689;TAKRI LETTER AU;Lo;0;L;;;;;N;;;;; +1168A;TAKRI LETTER KA;Lo;0;L;;;;;N;;;;; +1168B;TAKRI LETTER KHA;Lo;0;L;;;;;N;;;;; +1168C;TAKRI LETTER GA;Lo;0;L;;;;;N;;;;; +1168D;TAKRI LETTER GHA;Lo;0;L;;;;;N;;;;; +1168E;TAKRI LETTER NGA;Lo;0;L;;;;;N;;;;; +1168F;TAKRI LETTER CA;Lo;0;L;;;;;N;;;;; +11690;TAKRI LETTER CHA;Lo;0;L;;;;;N;;;;; +11691;TAKRI LETTER JA;Lo;0;L;;;;;N;;;;; +11692;TAKRI LETTER JHA;Lo;0;L;;;;;N;;;;; +11693;TAKRI LETTER NYA;Lo;0;L;;;;;N;;;;; +11694;TAKRI LETTER TTA;Lo;0;L;;;;;N;;;;; +11695;TAKRI LETTER TTHA;Lo;0;L;;;;;N;;;;; +11696;TAKRI LETTER DDA;Lo;0;L;;;;;N;;;;; +11697;TAKRI LETTER DDHA;Lo;0;L;;;;;N;;;;; +11698;TAKRI LETTER NNA;Lo;0;L;;;;;N;;;;; +11699;TAKRI LETTER TA;Lo;0;L;;;;;N;;;;; +1169A;TAKRI LETTER THA;Lo;0;L;;;;;N;;;;; +1169B;TAKRI LETTER DA;Lo;0;L;;;;;N;;;;; +1169C;TAKRI LETTER DHA;Lo;0;L;;;;;N;;;;; +1169D;TAKRI LETTER NA;Lo;0;L;;;;;N;;;;; +1169E;TAKRI LETTER PA;Lo;0;L;;;;;N;;;;; +1169F;TAKRI LETTER PHA;Lo;0;L;;;;;N;;;;; +116A0;TAKRI LETTER BA;Lo;0;L;;;;;N;;;;; +116A1;TAKRI LETTER BHA;Lo;0;L;;;;;N;;;;; +116A2;TAKRI LETTER MA;Lo;0;L;;;;;N;;;;; +116A3;TAKRI LETTER YA;Lo;0;L;;;;;N;;;;; +116A4;TAKRI LETTER RA;Lo;0;L;;;;;N;;;;; +116A5;TAKRI LETTER LA;Lo;0;L;;;;;N;;;;; +116A6;TAKRI LETTER VA;Lo;0;L;;;;;N;;;;; +116A7;TAKRI LETTER SHA;Lo;0;L;;;;;N;;;;; +116A8;TAKRI LETTER SA;Lo;0;L;;;;;N;;;;; +116A9;TAKRI LETTER HA;Lo;0;L;;;;;N;;;;; +116AA;TAKRI LETTER RRA;Lo;0;L;;;;;N;;;;; +116AB;TAKRI SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;; +116AC;TAKRI SIGN VISARGA;Mc;0;L;;;;;N;;;;; +116AD;TAKRI VOWEL SIGN AA;Mn;0;NSM;;;;;N;;;;; +116AE;TAKRI VOWEL SIGN I;Mc;0;L;;;;;N;;;;; +116AF;TAKRI VOWEL SIGN II;Mc;0;L;;;;;N;;;;; +116B0;TAKRI VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;; +116B1;TAKRI VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;; +116B2;TAKRI VOWEL SIGN E;Mn;0;NSM;;;;;N;;;;; +116B3;TAKRI VOWEL SIGN AI;Mn;0;NSM;;;;;N;;;;; +116B4;TAKRI VOWEL SIGN O;Mn;0;NSM;;;;;N;;;;; +116B5;TAKRI VOWEL SIGN AU;Mn;0;NSM;;;;;N;;;;; +116B6;TAKRI SIGN VIRAMA;Mc;9;L;;;;;N;;;;; +116B7;TAKRI SIGN NUKTA;Mn;7;NSM;;;;;N;;;;; +116C0;TAKRI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; +116C1;TAKRI DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; +116C2;TAKRI DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; +116C3;TAKRI DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; +116C4;TAKRI DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; +116C5;TAKRI DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; +116C6;TAKRI DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; +116C7;TAKRI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; +116C8;TAKRI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; +116C9;TAKRI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; 12000;CUNEIFORM SIGN A;Lo;0;L;;;;;N;;;;; 12001;CUNEIFORM SIGN A TIMES A;Lo;0;L;;;;;N;;;;; 12002;CUNEIFORM SIGN A TIMES BAD;Lo;0;L;;;;;N;;;;; @@ -19960,6 +20396,139 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 16A36;BAMUM LETTER PHASE-F KPA;Lo;0;L;;;;;N;;;;; 16A37;BAMUM LETTER PHASE-F SAMBA;Lo;0;L;;;;;N;;;;; 16A38;BAMUM LETTER PHASE-F VUEQ;Lo;0;L;;;;;N;;;;; +16F00;MIAO LETTER PA;Lo;0;L;;;;;N;;;;; +16F01;MIAO LETTER BA;Lo;0;L;;;;;N;;;;; +16F02;MIAO LETTER YI PA;Lo;0;L;;;;;N;;;;; +16F03;MIAO LETTER PLA;Lo;0;L;;;;;N;;;;; +16F04;MIAO LETTER MA;Lo;0;L;;;;;N;;;;; +16F05;MIAO LETTER MHA;Lo;0;L;;;;;N;;;;; +16F06;MIAO LETTER ARCHAIC MA;Lo;0;L;;;;;N;;;;; +16F07;MIAO LETTER FA;Lo;0;L;;;;;N;;;;; +16F08;MIAO LETTER VA;Lo;0;L;;;;;N;;;;; +16F09;MIAO LETTER VFA;Lo;0;L;;;;;N;;;;; +16F0A;MIAO LETTER TA;Lo;0;L;;;;;N;;;;; +16F0B;MIAO LETTER DA;Lo;0;L;;;;;N;;;;; +16F0C;MIAO LETTER YI TTA;Lo;0;L;;;;;N;;;;; +16F0D;MIAO LETTER YI TA;Lo;0;L;;;;;N;;;;; +16F0E;MIAO LETTER TTA;Lo;0;L;;;;;N;;;;; +16F0F;MIAO LETTER DDA;Lo;0;L;;;;;N;;;;; +16F10;MIAO LETTER NA;Lo;0;L;;;;;N;;;;; +16F11;MIAO LETTER NHA;Lo;0;L;;;;;N;;;;; +16F12;MIAO LETTER YI NNA;Lo;0;L;;;;;N;;;;; +16F13;MIAO LETTER ARCHAIC NA;Lo;0;L;;;;;N;;;;; +16F14;MIAO LETTER NNA;Lo;0;L;;;;;N;;;;; +16F15;MIAO LETTER NNHA;Lo;0;L;;;;;N;;;;; +16F16;MIAO LETTER LA;Lo;0;L;;;;;N;;;;; +16F17;MIAO LETTER LYA;Lo;0;L;;;;;N;;;;; +16F18;MIAO LETTER LHA;Lo;0;L;;;;;N;;;;; +16F19;MIAO LETTER LHYA;Lo;0;L;;;;;N;;;;; +16F1A;MIAO LETTER TLHA;Lo;0;L;;;;;N;;;;; +16F1B;MIAO LETTER DLHA;Lo;0;L;;;;;N;;;;; +16F1C;MIAO LETTER TLHYA;Lo;0;L;;;;;N;;;;; +16F1D;MIAO LETTER DLHYA;Lo;0;L;;;;;N;;;;; +16F1E;MIAO LETTER KA;Lo;0;L;;;;;N;;;;; +16F1F;MIAO LETTER GA;Lo;0;L;;;;;N;;;;; +16F20;MIAO LETTER YI KA;Lo;0;L;;;;;N;;;;; +16F21;MIAO LETTER QA;Lo;0;L;;;;;N;;;;; +16F22;MIAO LETTER QGA;Lo;0;L;;;;;N;;;;; +16F23;MIAO LETTER NGA;Lo;0;L;;;;;N;;;;; +16F24;MIAO LETTER NGHA;Lo;0;L;;;;;N;;;;; +16F25;MIAO LETTER ARCHAIC NGA;Lo;0;L;;;;;N;;;;; +16F26;MIAO LETTER HA;Lo;0;L;;;;;N;;;;; +16F27;MIAO LETTER XA;Lo;0;L;;;;;N;;;;; +16F28;MIAO LETTER GHA;Lo;0;L;;;;;N;;;;; +16F29;MIAO LETTER GHHA;Lo;0;L;;;;;N;;;;; +16F2A;MIAO LETTER TSSA;Lo;0;L;;;;;N;;;;; +16F2B;MIAO LETTER DZZA;Lo;0;L;;;;;N;;;;; +16F2C;MIAO LETTER NYA;Lo;0;L;;;;;N;;;;; +16F2D;MIAO LETTER NYHA;Lo;0;L;;;;;N;;;;; +16F2E;MIAO LETTER TSHA;Lo;0;L;;;;;N;;;;; +16F2F;MIAO LETTER DZHA;Lo;0;L;;;;;N;;;;; +16F30;MIAO LETTER YI TSHA;Lo;0;L;;;;;N;;;;; +16F31;MIAO LETTER YI DZHA;Lo;0;L;;;;;N;;;;; +16F32;MIAO LETTER REFORMED TSHA;Lo;0;L;;;;;N;;;;; +16F33;MIAO LETTER SHA;Lo;0;L;;;;;N;;;;; +16F34;MIAO LETTER SSA;Lo;0;L;;;;;N;;;;; +16F35;MIAO LETTER ZHA;Lo;0;L;;;;;N;;;;; +16F36;MIAO LETTER ZSHA;Lo;0;L;;;;;N;;;;; +16F37;MIAO LETTER TSA;Lo;0;L;;;;;N;;;;; +16F38;MIAO LETTER DZA;Lo;0;L;;;;;N;;;;; +16F39;MIAO LETTER YI TSA;Lo;0;L;;;;;N;;;;; +16F3A;MIAO LETTER SA;Lo;0;L;;;;;N;;;;; +16F3B;MIAO LETTER ZA;Lo;0;L;;;;;N;;;;; +16F3C;MIAO LETTER ZSA;Lo;0;L;;;;;N;;;;; +16F3D;MIAO LETTER ZZA;Lo;0;L;;;;;N;;;;; +16F3E;MIAO LETTER ZZSA;Lo;0;L;;;;;N;;;;; +16F3F;MIAO LETTER ARCHAIC ZZA;Lo;0;L;;;;;N;;;;; +16F40;MIAO LETTER ZZYA;Lo;0;L;;;;;N;;;;; +16F41;MIAO LETTER ZZSYA;Lo;0;L;;;;;N;;;;; +16F42;MIAO LETTER WA;Lo;0;L;;;;;N;;;;; +16F43;MIAO LETTER AH;Lo;0;L;;;;;N;;;;; +16F44;MIAO LETTER HHA;Lo;0;L;;;;;N;;;;; +16F50;MIAO LETTER NASALIZATION;Lo;0;L;;;;;N;;;;; +16F51;MIAO SIGN ASPIRATION;Mc;0;L;;;;;N;;;;; +16F52;MIAO SIGN REFORMED VOICING;Mc;0;L;;;;;N;;;;; +16F53;MIAO SIGN REFORMED ASPIRATION;Mc;0;L;;;;;N;;;;; +16F54;MIAO VOWEL SIGN A;Mc;0;L;;;;;N;;;;; +16F55;MIAO VOWEL SIGN AA;Mc;0;L;;;;;N;;;;; +16F56;MIAO VOWEL SIGN AHH;Mc;0;L;;;;;N;;;;; +16F57;MIAO VOWEL SIGN AN;Mc;0;L;;;;;N;;;;; +16F58;MIAO VOWEL SIGN ANG;Mc;0;L;;;;;N;;;;; +16F59;MIAO VOWEL SIGN O;Mc;0;L;;;;;N;;;;; +16F5A;MIAO VOWEL SIGN OO;Mc;0;L;;;;;N;;;;; +16F5B;MIAO VOWEL SIGN WO;Mc;0;L;;;;;N;;;;; +16F5C;MIAO VOWEL SIGN W;Mc;0;L;;;;;N;;;;; +16F5D;MIAO VOWEL SIGN E;Mc;0;L;;;;;N;;;;; +16F5E;MIAO VOWEL SIGN EN;Mc;0;L;;;;;N;;;;; +16F5F;MIAO VOWEL SIGN ENG;Mc;0;L;;;;;N;;;;; +16F60;MIAO VOWEL SIGN OEY;Mc;0;L;;;;;N;;;;; +16F61;MIAO VOWEL SIGN I;Mc;0;L;;;;;N;;;;; +16F62;MIAO VOWEL SIGN IA;Mc;0;L;;;;;N;;;;; +16F63;MIAO VOWEL SIGN IAN;Mc;0;L;;;;;N;;;;; +16F64;MIAO VOWEL SIGN IANG;Mc;0;L;;;;;N;;;;; +16F65;MIAO VOWEL SIGN IO;Mc;0;L;;;;;N;;;;; +16F66;MIAO VOWEL SIGN IE;Mc;0;L;;;;;N;;;;; +16F67;MIAO VOWEL SIGN II;Mc;0;L;;;;;N;;;;; +16F68;MIAO VOWEL SIGN IU;Mc;0;L;;;;;N;;;;; +16F69;MIAO VOWEL SIGN ING;Mc;0;L;;;;;N;;;;; +16F6A;MIAO VOWEL SIGN U;Mc;0;L;;;;;N;;;;; +16F6B;MIAO VOWEL SIGN UA;Mc;0;L;;;;;N;;;;; +16F6C;MIAO VOWEL SIGN UAN;Mc;0;L;;;;;N;;;;; +16F6D;MIAO VOWEL SIGN UANG;Mc;0;L;;;;;N;;;;; +16F6E;MIAO VOWEL SIGN UU;Mc;0;L;;;;;N;;;;; +16F6F;MIAO VOWEL SIGN UEI;Mc;0;L;;;;;N;;;;; +16F70;MIAO VOWEL SIGN UNG;Mc;0;L;;;;;N;;;;; +16F71;MIAO VOWEL SIGN Y;Mc;0;L;;;;;N;;;;; +16F72;MIAO VOWEL SIGN YI;Mc;0;L;;;;;N;;;;; +16F73;MIAO VOWEL SIGN AE;Mc;0;L;;;;;N;;;;; +16F74;MIAO VOWEL SIGN AEE;Mc;0;L;;;;;N;;;;; +16F75;MIAO VOWEL SIGN ERR;Mc;0;L;;;;;N;;;;; +16F76;MIAO VOWEL SIGN ROUNDED ERR;Mc;0;L;;;;;N;;;;; +16F77;MIAO VOWEL SIGN ER;Mc;0;L;;;;;N;;;;; +16F78;MIAO VOWEL SIGN ROUNDED ER;Mc;0;L;;;;;N;;;;; +16F79;MIAO VOWEL SIGN AI;Mc;0;L;;;;;N;;;;; +16F7A;MIAO VOWEL SIGN EI;Mc;0;L;;;;;N;;;;; +16F7B;MIAO VOWEL SIGN AU;Mc;0;L;;;;;N;;;;; +16F7C;MIAO VOWEL SIGN OU;Mc;0;L;;;;;N;;;;; +16F7D;MIAO VOWEL SIGN N;Mc;0;L;;;;;N;;;;; +16F7E;MIAO VOWEL SIGN NG;Mc;0;L;;;;;N;;;;; +16F8F;MIAO TONE RIGHT;Mn;0;NSM;;;;;N;;;;; +16F90;MIAO TONE TOP RIGHT;Mn;0;NSM;;;;;N;;;;; +16F91;MIAO TONE ABOVE;Mn;0;NSM;;;;;N;;;;; +16F92;MIAO TONE BELOW;Mn;0;NSM;;;;;N;;;;; +16F93;MIAO LETTER TONE-2;Lm;0;L;;;;;N;;;;; +16F94;MIAO LETTER TONE-3;Lm;0;L;;;;;N;;;;; +16F95;MIAO LETTER TONE-4;Lm;0;L;;;;;N;;;;; +16F96;MIAO LETTER TONE-5;Lm;0;L;;;;;N;;;;; +16F97;MIAO LETTER TONE-6;Lm;0;L;;;;;N;;;;; +16F98;MIAO LETTER TONE-7;Lm;0;L;;;;;N;;;;; +16F99;MIAO LETTER TONE-8;Lm;0;L;;;;;N;;;;; +16F9A;MIAO LETTER REFORMED TONE-1;Lm;0;L;;;;;N;;;;; +16F9B;MIAO LETTER REFORMED TONE-2;Lm;0;L;;;;;N;;;;; +16F9C;MIAO LETTER REFORMED TONE-4;Lm;0;L;;;;;N;;;;; +16F9D;MIAO LETTER REFORMED TONE-5;Lm;0;L;;;;;N;;;;; +16F9E;MIAO LETTER REFORMED TONE-6;Lm;0;L;;;;;N;;;;; +16F9F;MIAO LETTER REFORMED TONE-8;Lm;0;L;;;;;N;;;;; 1B000;KATAKANA LETTER ARCHAIC E;Lo;0;L;;;;;N;;;;; 1B001;HIRAGANA LETTER ARCHAIC YE;Lo;0;L;;;;;N;;;;; 1D000;BYZANTINE MUSICAL SYMBOL PSILI;So;0;L;;;;;N;;;;; @@ -21599,6 +22168,149 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 1D7FD;MATHEMATICAL MONOSPACE DIGIT SEVEN;Nd;0;EN;<font> 0037;7;7;7;N;;;;; 1D7FE;MATHEMATICAL MONOSPACE DIGIT EIGHT;Nd;0;EN;<font> 0038;8;8;8;N;;;;; 1D7FF;MATHEMATICAL MONOSPACE DIGIT NINE;Nd;0;EN;<font> 0039;9;9;9;N;;;;; +1EE00;ARABIC MATHEMATICAL ALEF;Lo;0;AL;<font> 0627;;;;N;;;;; +1EE01;ARABIC MATHEMATICAL BEH;Lo;0;AL;<font> 0628;;;;N;;;;; +1EE02;ARABIC MATHEMATICAL JEEM;Lo;0;AL;<font> 062C;;;;N;;;;; +1EE03;ARABIC MATHEMATICAL DAL;Lo;0;AL;<font> 062F;;;;N;;;;; +1EE05;ARABIC MATHEMATICAL WAW;Lo;0;AL;<font> 0648;;;;N;;;;; +1EE06;ARABIC MATHEMATICAL ZAIN;Lo;0;AL;<font> 0632;;;;N;;;;; +1EE07;ARABIC MATHEMATICAL HAH;Lo;0;AL;<font> 062D;;;;N;;;;; +1EE08;ARABIC MATHEMATICAL TAH;Lo;0;AL;<font> 0637;;;;N;;;;; +1EE09;ARABIC MATHEMATICAL YEH;Lo;0;AL;<font> 064A;;;;N;;;;; +1EE0A;ARABIC MATHEMATICAL KAF;Lo;0;AL;<font> 0643;;;;N;;;;; +1EE0B;ARABIC MATHEMATICAL LAM;Lo;0;AL;<font> 0644;;;;N;;;;; +1EE0C;ARABIC MATHEMATICAL MEEM;Lo;0;AL;<font> 0645;;;;N;;;;; +1EE0D;ARABIC MATHEMATICAL NOON;Lo;0;AL;<font> 0646;;;;N;;;;; +1EE0E;ARABIC MATHEMATICAL SEEN;Lo;0;AL;<font> 0633;;;;N;;;;; +1EE0F;ARABIC MATHEMATICAL AIN;Lo;0;AL;<font> 0639;;;;N;;;;; +1EE10;ARABIC MATHEMATICAL FEH;Lo;0;AL;<font> 0641;;;;N;;;;; +1EE11;ARABIC MATHEMATICAL SAD;Lo;0;AL;<font> 0635;;;;N;;;;; +1EE12;ARABIC MATHEMATICAL QAF;Lo;0;AL;<font> 0642;;;;N;;;;; +1EE13;ARABIC MATHEMATICAL REH;Lo;0;AL;<font> 0631;;;;N;;;;; +1EE14;ARABIC MATHEMATICAL SHEEN;Lo;0;AL;<font> 0634;;;;N;;;;; +1EE15;ARABIC MATHEMATICAL TEH;Lo;0;AL;<font> 062A;;;;N;;;;; +1EE16;ARABIC MATHEMATICAL THEH;Lo;0;AL;<font> 062B;;;;N;;;;; +1EE17;ARABIC MATHEMATICAL KHAH;Lo;0;AL;<font> 062E;;;;N;;;;; +1EE18;ARABIC MATHEMATICAL THAL;Lo;0;AL;<font> 0630;;;;N;;;;; +1EE19;ARABIC MATHEMATICAL DAD;Lo;0;AL;<font> 0636;;;;N;;;;; +1EE1A;ARABIC MATHEMATICAL ZAH;Lo;0;AL;<font> 0638;;;;N;;;;; +1EE1B;ARABIC MATHEMATICAL GHAIN;Lo;0;AL;<font> 063A;;;;N;;;;; +1EE1C;ARABIC MATHEMATICAL DOTLESS BEH;Lo;0;AL;<font> 066E;;;;N;;;;; +1EE1D;ARABIC MATHEMATICAL DOTLESS NOON;Lo;0;AL;<font> 06BA;;;;N;;;;; +1EE1E;ARABIC MATHEMATICAL DOTLESS FEH;Lo;0;AL;<font> 06A1;;;;N;;;;; +1EE1F;ARABIC MATHEMATICAL DOTLESS QAF;Lo;0;AL;<font> 066F;;;;N;;;;; +1EE21;ARABIC MATHEMATICAL INITIAL BEH;Lo;0;AL;<font> 0628;;;;N;;;;; +1EE22;ARABIC MATHEMATICAL INITIAL JEEM;Lo;0;AL;<font> 062C;;;;N;;;;; +1EE24;ARABIC MATHEMATICAL INITIAL HEH;Lo;0;AL;<font> 0647;;;;N;;;;; +1EE27;ARABIC MATHEMATICAL INITIAL HAH;Lo;0;AL;<font> 062D;;;;N;;;;; +1EE29;ARABIC MATHEMATICAL INITIAL YEH;Lo;0;AL;<font> 064A;;;;N;;;;; +1EE2A;ARABIC MATHEMATICAL INITIAL KAF;Lo;0;AL;<font> 0643;;;;N;;;;; +1EE2B;ARABIC MATHEMATICAL INITIAL LAM;Lo;0;AL;<font> 0644;;;;N;;;;; +1EE2C;ARABIC MATHEMATICAL INITIAL MEEM;Lo;0;AL;<font> 0645;;;;N;;;;; +1EE2D;ARABIC MATHEMATICAL INITIAL NOON;Lo;0;AL;<font> 0646;;;;N;;;;; +1EE2E;ARABIC MATHEMATICAL INITIAL SEEN;Lo;0;AL;<font> 0633;;;;N;;;;; +1EE2F;ARABIC MATHEMATICAL INITIAL AIN;Lo;0;AL;<font> 0639;;;;N;;;;; +1EE30;ARABIC MATHEMATICAL INITIAL FEH;Lo;0;AL;<font> 0641;;;;N;;;;; +1EE31;ARABIC MATHEMATICAL INITIAL SAD;Lo;0;AL;<font> 0635;;;;N;;;;; +1EE32;ARABIC MATHEMATICAL INITIAL QAF;Lo;0;AL;<font> 0642;;;;N;;;;; +1EE34;ARABIC MATHEMATICAL INITIAL SHEEN;Lo;0;AL;<font> 0634;;;;N;;;;; +1EE35;ARABIC MATHEMATICAL INITIAL TEH;Lo;0;AL;<font> 062A;;;;N;;;;; +1EE36;ARABIC MATHEMATICAL INITIAL THEH;Lo;0;AL;<font> 062B;;;;N;;;;; +1EE37;ARABIC MATHEMATICAL INITIAL KHAH;Lo;0;AL;<font> 062E;;;;N;;;;; +1EE39;ARABIC MATHEMATICAL INITIAL DAD;Lo;0;AL;<font> 0636;;;;N;;;;; +1EE3B;ARABIC MATHEMATICAL INITIAL GHAIN;Lo;0;AL;<font> 063A;;;;N;;;;; +1EE42;ARABIC MATHEMATICAL TAILED JEEM;Lo;0;AL;<font> 062C;;;;N;;;;; +1EE47;ARABIC MATHEMATICAL TAILED HAH;Lo;0;AL;<font> 062D;;;;N;;;;; +1EE49;ARABIC MATHEMATICAL TAILED YEH;Lo;0;AL;<font> 064A;;;;N;;;;; +1EE4B;ARABIC MATHEMATICAL TAILED LAM;Lo;0;AL;<font> 0644;;;;N;;;;; +1EE4D;ARABIC MATHEMATICAL TAILED NOON;Lo;0;AL;<font> 0646;;;;N;;;;; +1EE4E;ARABIC MATHEMATICAL TAILED SEEN;Lo;0;AL;<font> 0633;;;;N;;;;; +1EE4F;ARABIC MATHEMATICAL TAILED AIN;Lo;0;AL;<font> 0639;;;;N;;;;; +1EE51;ARABIC MATHEMATICAL TAILED SAD;Lo;0;AL;<font> 0635;;;;N;;;;; +1EE52;ARABIC MATHEMATICAL TAILED QAF;Lo;0;AL;<font> 0642;;;;N;;;;; +1EE54;ARABIC MATHEMATICAL TAILED SHEEN;Lo;0;AL;<font> 0634;;;;N;;;;; +1EE57;ARABIC MATHEMATICAL TAILED KHAH;Lo;0;AL;<font> 062E;;;;N;;;;; +1EE59;ARABIC MATHEMATICAL TAILED DAD;Lo;0;AL;<font> 0636;;;;N;;;;; +1EE5B;ARABIC MATHEMATICAL TAILED GHAIN;Lo;0;AL;<font> 063A;;;;N;;;;; +1EE5D;ARABIC MATHEMATICAL TAILED DOTLESS NOON;Lo;0;AL;<font> 06BA;;;;N;;;;; +1EE5F;ARABIC MATHEMATICAL TAILED DOTLESS QAF;Lo;0;AL;<font> 066F;;;;N;;;;; +1EE61;ARABIC MATHEMATICAL STRETCHED BEH;Lo;0;AL;<font> 0628;;;;N;;;;; +1EE62;ARABIC MATHEMATICAL STRETCHED JEEM;Lo;0;AL;<font> 062C;;;;N;;;;; +1EE64;ARABIC MATHEMATICAL STRETCHED HEH;Lo;0;AL;<font> 0647;;;;N;;;;; +1EE67;ARABIC MATHEMATICAL STRETCHED HAH;Lo;0;AL;<font> 062D;;;;N;;;;; +1EE68;ARABIC MATHEMATICAL STRETCHED TAH;Lo;0;AL;<font> 0637;;;;N;;;;; +1EE69;ARABIC MATHEMATICAL STRETCHED YEH;Lo;0;AL;<font> 064A;;;;N;;;;; +1EE6A;ARABIC MATHEMATICAL STRETCHED KAF;Lo;0;AL;<font> 0643;;;;N;;;;; +1EE6C;ARABIC MATHEMATICAL STRETCHED MEEM;Lo;0;AL;<font> 0645;;;;N;;;;; +1EE6D;ARABIC MATHEMATICAL STRETCHED NOON;Lo;0;AL;<font> 0646;;;;N;;;;; +1EE6E;ARABIC MATHEMATICAL STRETCHED SEEN;Lo;0;AL;<font> 0633;;;;N;;;;; +1EE6F;ARABIC MATHEMATICAL STRETCHED AIN;Lo;0;AL;<font> 0639;;;;N;;;;; +1EE70;ARABIC MATHEMATICAL STRETCHED FEH;Lo;0;AL;<font> 0641;;;;N;;;;; +1EE71;ARABIC MATHEMATICAL STRETCHED SAD;Lo;0;AL;<font> 0635;;;;N;;;;; +1EE72;ARABIC MATHEMATICAL STRETCHED QAF;Lo;0;AL;<font> 0642;;;;N;;;;; +1EE74;ARABIC MATHEMATICAL STRETCHED SHEEN;Lo;0;AL;<font> 0634;;;;N;;;;; +1EE75;ARABIC MATHEMATICAL STRETCHED TEH;Lo;0;AL;<font> 062A;;;;N;;;;; +1EE76;ARABIC MATHEMATICAL STRETCHED THEH;Lo;0;AL;<font> 062B;;;;N;;;;; +1EE77;ARABIC MATHEMATICAL STRETCHED KHAH;Lo;0;AL;<font> 062E;;;;N;;;;; +1EE79;ARABIC MATHEMATICAL STRETCHED DAD;Lo;0;AL;<font> 0636;;;;N;;;;; +1EE7A;ARABIC MATHEMATICAL STRETCHED ZAH;Lo;0;AL;<font> 0638;;;;N;;;;; +1EE7B;ARABIC MATHEMATICAL STRETCHED GHAIN;Lo;0;AL;<font> 063A;;;;N;;;;; +1EE7C;ARABIC MATHEMATICAL STRETCHED DOTLESS BEH;Lo;0;AL;<font> 066E;;;;N;;;;; +1EE7E;ARABIC MATHEMATICAL STRETCHED DOTLESS FEH;Lo;0;AL;<font> 06A1;;;;N;;;;; +1EE80;ARABIC MATHEMATICAL LOOPED ALEF;Lo;0;AL;<font> 0627;;;;N;;;;; +1EE81;ARABIC MATHEMATICAL LOOPED BEH;Lo;0;AL;<font> 0628;;;;N;;;;; +1EE82;ARABIC MATHEMATICAL LOOPED JEEM;Lo;0;AL;<font> 062C;;;;N;;;;; +1EE83;ARABIC MATHEMATICAL LOOPED DAL;Lo;0;AL;<font> 062F;;;;N;;;;; +1EE84;ARABIC MATHEMATICAL LOOPED HEH;Lo;0;AL;<font> 0647;;;;N;;;;; +1EE85;ARABIC MATHEMATICAL LOOPED WAW;Lo;0;AL;<font> 0648;;;;N;;;;; +1EE86;ARABIC MATHEMATICAL LOOPED ZAIN;Lo;0;AL;<font> 0632;;;;N;;;;; +1EE87;ARABIC MATHEMATICAL LOOPED HAH;Lo;0;AL;<font> 062D;;;;N;;;;; +1EE88;ARABIC MATHEMATICAL LOOPED TAH;Lo;0;AL;<font> 0637;;;;N;;;;; +1EE89;ARABIC MATHEMATICAL LOOPED YEH;Lo;0;AL;<font> 064A;;;;N;;;;; +1EE8B;ARABIC MATHEMATICAL LOOPED LAM;Lo;0;AL;<font> 0644;;;;N;;;;; +1EE8C;ARABIC MATHEMATICAL LOOPED MEEM;Lo;0;AL;<font> 0645;;;;N;;;;; +1EE8D;ARABIC MATHEMATICAL LOOPED NOON;Lo;0;AL;<font> 0646;;;;N;;;;; +1EE8E;ARABIC MATHEMATICAL LOOPED SEEN;Lo;0;AL;<font> 0633;;;;N;;;;; +1EE8F;ARABIC MATHEMATICAL LOOPED AIN;Lo;0;AL;<font> 0639;;;;N;;;;; +1EE90;ARABIC MATHEMATICAL LOOPED FEH;Lo;0;AL;<font> 0641;;;;N;;;;; +1EE91;ARABIC MATHEMATICAL LOOPED SAD;Lo;0;AL;<font> 0635;;;;N;;;;; +1EE92;ARABIC MATHEMATICAL LOOPED QAF;Lo;0;AL;<font> 0642;;;;N;;;;; +1EE93;ARABIC MATHEMATICAL LOOPED REH;Lo;0;AL;<font> 0631;;;;N;;;;; +1EE94;ARABIC MATHEMATICAL LOOPED SHEEN;Lo;0;AL;<font> 0634;;;;N;;;;; +1EE95;ARABIC MATHEMATICAL LOOPED TEH;Lo;0;AL;<font> 062A;;;;N;;;;; +1EE96;ARABIC MATHEMATICAL LOOPED THEH;Lo;0;AL;<font> 062B;;;;N;;;;; +1EE97;ARABIC MATHEMATICAL LOOPED KHAH;Lo;0;AL;<font> 062E;;;;N;;;;; +1EE98;ARABIC MATHEMATICAL LOOPED THAL;Lo;0;AL;<font> 0630;;;;N;;;;; +1EE99;ARABIC MATHEMATICAL LOOPED DAD;Lo;0;AL;<font> 0636;;;;N;;;;; +1EE9A;ARABIC MATHEMATICAL LOOPED ZAH;Lo;0;AL;<font> 0638;;;;N;;;;; +1EE9B;ARABIC MATHEMATICAL LOOPED GHAIN;Lo;0;AL;<font> 063A;;;;N;;;;; +1EEA1;ARABIC MATHEMATICAL DOUBLE-STRUCK BEH;Lo;0;AL;<font> 0628;;;;N;;;;; +1EEA2;ARABIC MATHEMATICAL DOUBLE-STRUCK JEEM;Lo;0;AL;<font> 062C;;;;N;;;;; +1EEA3;ARABIC MATHEMATICAL DOUBLE-STRUCK DAL;Lo;0;AL;<font> 062F;;;;N;;;;; +1EEA5;ARABIC MATHEMATICAL DOUBLE-STRUCK WAW;Lo;0;AL;<font> 0648;;;;N;;;;; +1EEA6;ARABIC MATHEMATICAL DOUBLE-STRUCK ZAIN;Lo;0;AL;<font> 0632;;;;N;;;;; +1EEA7;ARABIC MATHEMATICAL DOUBLE-STRUCK HAH;Lo;0;AL;<font> 062D;;;;N;;;;; +1EEA8;ARABIC MATHEMATICAL DOUBLE-STRUCK TAH;Lo;0;AL;<font> 0637;;;;N;;;;; +1EEA9;ARABIC MATHEMATICAL DOUBLE-STRUCK YEH;Lo;0;AL;<font> 064A;;;;N;;;;; +1EEAB;ARABIC MATHEMATICAL DOUBLE-STRUCK LAM;Lo;0;AL;<font> 0644;;;;N;;;;; +1EEAC;ARABIC MATHEMATICAL DOUBLE-STRUCK MEEM;Lo;0;AL;<font> 0645;;;;N;;;;; +1EEAD;ARABIC MATHEMATICAL DOUBLE-STRUCK NOON;Lo;0;AL;<font> 0646;;;;N;;;;; +1EEAE;ARABIC MATHEMATICAL DOUBLE-STRUCK SEEN;Lo;0;AL;<font> 0633;;;;N;;;;; +1EEAF;ARABIC MATHEMATICAL DOUBLE-STRUCK AIN;Lo;0;AL;<font> 0639;;;;N;;;;; +1EEB0;ARABIC MATHEMATICAL DOUBLE-STRUCK FEH;Lo;0;AL;<font> 0641;;;;N;;;;; +1EEB1;ARABIC MATHEMATICAL DOUBLE-STRUCK SAD;Lo;0;AL;<font> 0635;;;;N;;;;; +1EEB2;ARABIC MATHEMATICAL DOUBLE-STRUCK QAF;Lo;0;AL;<font> 0642;;;;N;;;;; +1EEB3;ARABIC MATHEMATICAL DOUBLE-STRUCK REH;Lo;0;AL;<font> 0631;;;;N;;;;; +1EEB4;ARABIC MATHEMATICAL DOUBLE-STRUCK SHEEN;Lo;0;AL;<font> 0634;;;;N;;;;; +1EEB5;ARABIC MATHEMATICAL DOUBLE-STRUCK TEH;Lo;0;AL;<font> 062A;;;;N;;;;; +1EEB6;ARABIC MATHEMATICAL DOUBLE-STRUCK THEH;Lo;0;AL;<font> 062B;;;;N;;;;; +1EEB7;ARABIC MATHEMATICAL DOUBLE-STRUCK KHAH;Lo;0;AL;<font> 062E;;;;N;;;;; +1EEB8;ARABIC MATHEMATICAL DOUBLE-STRUCK THAL;Lo;0;AL;<font> 0630;;;;N;;;;; +1EEB9;ARABIC MATHEMATICAL DOUBLE-STRUCK DAD;Lo;0;AL;<font> 0636;;;;N;;;;; +1EEBA;ARABIC MATHEMATICAL DOUBLE-STRUCK ZAH;Lo;0;AL;<font> 0638;;;;N;;;;; +1EEBB;ARABIC MATHEMATICAL DOUBLE-STRUCK GHAIN;Lo;0;AL;<font> 063A;;;;N;;;;; +1EEF0;ARABIC MATHEMATICAL OPERATOR MEEM WITH HAH WITH TATWEEL;Sm;0;ON;;;;;N;;;;; +1EEF1;ARABIC MATHEMATICAL OPERATOR HAH WITH DAL;Sm;0;ON;;;;;N;;;;; 1F000;MAHJONG TILE EAST WIND;So;0;ON;;;;;N;;;;; 1F001;MAHJONG TILE SOUTH WIND;So;0;ON;;;;;N;;;;; 1F002;MAHJONG TILE WEST WIND;So;0;ON;;;;;N;;;;; @@ -21902,6 +22614,8 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 1F167;NEGATIVE CIRCLED LATIN CAPITAL LETTER X;So;0;L;;;;;N;;;;; 1F168;NEGATIVE CIRCLED LATIN CAPITAL LETTER Y;So;0;L;;;;;N;;;;; 1F169;NEGATIVE CIRCLED LATIN CAPITAL LETTER Z;So;0;L;;;;;N;;;;; +1F16A;RAISED MC SIGN;So;0;ON;<super> 004D 0043;;;;N;;;;; +1F16B;RAISED MD SIGN;So;0;ON;<super> 004D 0044;;;;N;;;;; 1F170;NEGATIVE SQUARED LATIN CAPITAL LETTER A;So;0;L;;;;;N;;;;; 1F171;NEGATIVE SQUARED LATIN CAPITAL LETTER B;So;0;L;;;;;N;;;;; 1F172;NEGATIVE SQUARED LATIN CAPITAL LETTER C;So;0;L;;;;;N;;;;; @@ -22354,7 +23068,7 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 1F489;SYRINGE;So;0;ON;;;;;N;;;;; 1F48A;PILL;So;0;ON;;;;;N;;;;; 1F48B;KISS MARK;So;0;ON;;;;;N;;;;; -1F48C;LOVE LETTER;So;0;L;;;;;N;;;;; +1F48C;LOVE LETTER;So;0;ON;;;;;N;;;;; 1F48D;RING;So;0;ON;;;;;N;;;;; 1F48E;GEM STONE;So;0;ON;;;;;N;;;;; 1F48F;KISS;So;0;ON;;;;;N;;;;; @@ -22502,7 +23216,7 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 1F521;INPUT SYMBOL FOR LATIN SMALL LETTERS;So;0;ON;;;;;N;;;;; 1F522;INPUT SYMBOL FOR NUMBERS;So;0;ON;;;;;N;;;;; 1F523;INPUT SYMBOL FOR SYMBOLS;So;0;ON;;;;;N;;;;; -1F524;INPUT SYMBOL FOR LATIN LETTERS;So;0;L;;;;;N;;;;; +1F524;INPUT SYMBOL FOR LATIN LETTERS;So;0;ON;;;;;N;;;;; 1F525;FIRE;So;0;ON;;;;;N;;;;; 1F526;ELECTRIC TORCH;So;0;ON;;;;;N;;;;; 1F527;WRENCH;So;0;ON;;;;;N;;;;; @@ -22528,6 +23242,10 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 1F53B;DOWN-POINTING RED TRIANGLE;So;0;ON;;;;;N;;;;; 1F53C;UP-POINTING SMALL RED TRIANGLE;So;0;ON;;;;;N;;;;; 1F53D;DOWN-POINTING SMALL RED TRIANGLE;So;0;ON;;;;;N;;;;; +1F540;CIRCLED CROSS POMMEE;So;0;ON;;;;;N;;;;; +1F541;CROSS POMMEE WITH HALF-CIRCLE BELOW;So;0;ON;;;;;N;;;;; +1F542;CROSS POMMEE;So;0;ON;;;;;N;;;;; +1F543;NOTCHED LEFT SEMICIRCLE WITH THREE DOTS;So;0;ON;;;;;N;;;;; 1F550;CLOCK FACE ONE OCLOCK;So;0;ON;;;;;N;;;;; 1F551;CLOCK FACE TWO OCLOCK;So;0;ON;;;;;N;;;;; 1F552;CLOCK FACE THREE OCLOCK;So;0;ON;;;;;N;;;;; @@ -22557,6 +23275,7 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 1F5FD;STATUE OF LIBERTY;So;0;ON;;;;;N;;;;; 1F5FE;SILHOUETTE OF JAPAN;So;0;ON;;;;;N;;;;; 1F5FF;MOYAI;So;0;ON;;;;;N;;;;; +1F600;GRINNING FACE;So;0;ON;;;;;N;;;;; 1F601;GRINNING FACE WITH SMILING EYES;So;0;ON;;;;;N;;;;; 1F602;FACE WITH TEARS OF JOY;So;0;ON;;;;;N;;;;; 1F603;SMILING FACE WITH OPEN MOUTH;So;0;ON;;;;;N;;;;; @@ -22573,30 +23292,42 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 1F60E;SMILING FACE WITH SUNGLASSES;So;0;ON;;;;;N;;;;; 1F60F;SMIRKING FACE;So;0;ON;;;;;N;;;;; 1F610;NEUTRAL FACE;So;0;ON;;;;;N;;;;; +1F611;EXPRESSIONLESS FACE;So;0;ON;;;;;N;;;;; 1F612;UNAMUSED FACE;So;0;ON;;;;;N;;;;; 1F613;FACE WITH COLD SWEAT;So;0;ON;;;;;N;;;;; 1F614;PENSIVE FACE;So;0;ON;;;;;N;;;;; +1F615;CONFUSED FACE;So;0;ON;;;;;N;;;;; 1F616;CONFOUNDED FACE;So;0;ON;;;;;N;;;;; +1F617;KISSING FACE;So;0;ON;;;;;N;;;;; 1F618;FACE THROWING A KISS;So;0;ON;;;;;N;;;;; +1F619;KISSING FACE WITH SMILING EYES;So;0;ON;;;;;N;;;;; 1F61A;KISSING FACE WITH CLOSED EYES;So;0;ON;;;;;N;;;;; +1F61B;FACE WITH STUCK-OUT TONGUE;So;0;ON;;;;;N;;;;; 1F61C;FACE WITH STUCK-OUT TONGUE AND WINKING EYE;So;0;ON;;;;;N;;;;; 1F61D;FACE WITH STUCK-OUT TONGUE AND TIGHTLY-CLOSED EYES;So;0;ON;;;;;N;;;;; 1F61E;DISAPPOINTED FACE;So;0;ON;;;;;N;;;;; +1F61F;WORRIED FACE;So;0;ON;;;;;N;;;;; 1F620;ANGRY FACE;So;0;ON;;;;;N;;;;; 1F621;POUTING FACE;So;0;ON;;;;;N;;;;; 1F622;CRYING FACE;So;0;ON;;;;;N;;;;; 1F623;PERSEVERING FACE;So;0;ON;;;;;N;;;;; 1F624;FACE WITH LOOK OF TRIUMPH;So;0;ON;;;;;N;;;;; 1F625;DISAPPOINTED BUT RELIEVED FACE;So;0;ON;;;;;N;;;;; +1F626;FROWNING FACE WITH OPEN MOUTH;So;0;ON;;;;;N;;;;; +1F627;ANGUISHED FACE;So;0;ON;;;;;N;;;;; 1F628;FEARFUL FACE;So;0;ON;;;;;N;;;;; 1F629;WEARY FACE;So;0;ON;;;;;N;;;;; 1F62A;SLEEPY FACE;So;0;ON;;;;;N;;;;; 1F62B;TIRED FACE;So;0;ON;;;;;N;;;;; +1F62C;GRIMACING FACE;So;0;ON;;;;;N;;;;; 1F62D;LOUDLY CRYING FACE;So;0;ON;;;;;N;;;;; +1F62E;FACE WITH OPEN MOUTH;So;0;ON;;;;;N;;;;; +1F62F;HUSHED FACE;So;0;ON;;;;;N;;;;; 1F630;FACE WITH OPEN MOUTH AND COLD SWEAT;So;0;ON;;;;;N;;;;; 1F631;FACE SCREAMING IN FEAR;So;0;ON;;;;;N;;;;; 1F632;ASTONISHED FACE;So;0;ON;;;;;N;;;;; 1F633;FLUSHED FACE;So;0;ON;;;;;N;;;;; +1F634;SLEEPING FACE;So;0;ON;;;;;N;;;;; 1F635;DIZZY FACE;So;0;ON;;;;;N;;;;; 1F636;FACE WITHOUT MOUTH;So;0;ON;;;;;N;;;;; 1F637;FACE WITH MEDICAL MASK;So;0;ON;;;;;N;;;;; diff --git a/js/xpconnect/src/nsXPConnect.cpp b/js/xpconnect/src/nsXPConnect.cpp index 737de67173bf..5e3d629ce945 100644 --- a/js/xpconnect/src/nsXPConnect.cpp +++ b/js/xpconnect/src/nsXPConnect.cpp @@ -42,6 +42,10 @@ /* High level class and public functions implementation. */ +#include "mozilla/Assertions.h" +#include "mozilla/Base64.h" +#include "mozilla/Util.h" + #include "xpcprivate.h" #include "XPCWrapper.h" #include "nsBaseHashtable.h" @@ -64,10 +68,6 @@ #include "XPCQuickStubs.h" #include "dombindings.h" -#include "mozilla/Assertions.h" -#include "mozilla/Base64.h" -#include "mozilla/Util.h" - #include "nsWrapperCacheInlines.h" NS_IMPL_THREADSAFE_ISUPPORTS7(nsXPConnect, @@ -166,7 +166,7 @@ nsXPConnect::GetXPConnect() // XPConnect off the main thread. If you're an extension developer hitting // this, you need to change your code. See bug 716167. if (!NS_LIKELY(NS_IsMainThread() || NS_IsCycleCollectorThread())) - JS_Assert("NS_IsMainThread()", __FILE__, __LINE__); + MOZ_Assert("NS_IsMainThread()", __FILE__, __LINE__); if (!gSelf) { if (gOnceAliveNowDead) @@ -480,9 +480,10 @@ struct NoteWeakMapChildrenTracer : public JSTracer }; static void -TraceWeakMappingChild(JSTracer *trc, void *thing, JSGCTraceKind kind) +TraceWeakMappingChild(JSTracer *trc, void **thingp, JSGCTraceKind kind) { - JS_ASSERT(trc->callback == TraceWeakMappingChild); + MOZ_ASSERT(trc->callback == TraceWeakMappingChild); + void *thing = *thingp; NoteWeakMapChildrenTracer *tracer = static_cast<NoteWeakMapChildrenTracer *>(trc); if (kind == JSTRACE_STRING) @@ -513,7 +514,7 @@ TraceWeakMapping(js::WeakMapTracer *trc, JSObject *m, void *k, JSGCTraceKind kkind, void *v, JSGCTraceKind vkind) { - JS_ASSERT(trc->callback == TraceWeakMapping); + MOZ_ASSERT(trc->callback == TraceWeakMapping); NoteWeakMapsTracer *tracer = static_cast<NoteWeakMapsTracer *>(trc); if (vkind == JSTRACE_STRING) return; @@ -524,7 +525,7 @@ TraceWeakMapping(js::WeakMapTracer *trc, JSObject *m, // reason about the liveness of their keys, which in turn requires that // the key can be represented in the cycle collector graph. All existing // uses of weak maps use either objects or scripts as keys, which are okay. - JS_ASSERT(AddToCCKind(kkind)); + MOZ_ASSERT(AddToCCKind(kkind)); // As an emergency fallback for non-debug builds, if the key is not // representable in the cycle collector graph, we treat it as marked. This @@ -721,8 +722,9 @@ xpc_GCThingIsGrayCCThing(void *thing) * re-coloring. */ static void -UnmarkGrayChildren(JSTracer *trc, void *thing, JSGCTraceKind kind) +UnmarkGrayChildren(JSTracer *trc, void **thingp, JSGCTraceKind kind) { + void *thing = *thingp; int stackDummy; if (!JS_CHECK_STACK_SIZE(js::GetContextStackLimit(trc->context), &stackDummy)) { /* @@ -776,9 +778,10 @@ struct TraversalTracer : public JSTracer }; static void -NoteJSChild(JSTracer *trc, void *thing, JSGCTraceKind kind) +NoteJSChild(JSTracer *trc, void **thingp, JSGCTraceKind kind) { TraversalTracer *tracer = static_cast<TraversalTracer*>(trc); + void *thing = *thingp; // Don't traverse non-gray objects, unless we want all traces. if (!xpc_IsGrayGCThing(thing) && !tracer->cb.WantAllTraces()) @@ -1010,7 +1013,7 @@ nsXPConnect::GetOutstandingRequests(JSContext* cx) // Ignore the contribution from the XPCCallContext we created for cycle // collection. if (context && cx == context->GetJSContext()) { - JS_ASSERT(n); + MOZ_ASSERT(n); --n; } return n; @@ -1167,7 +1170,7 @@ struct VerifyTraceXPCGlobalCalledTracer }; static void -VerifyTraceXPCGlobalCalled(JSTracer *trc, void *thing, JSGCTraceKind kind) +VerifyTraceXPCGlobalCalled(JSTracer *trc, void **thingp, JSGCTraceKind kind) { // We don't do anything here, we only want to verify that TraceXPCGlobal // was called. @@ -1302,7 +1305,7 @@ nsXPConnect::InitClassesWithNewWrappedGlobal(JSContext * aJSContext, // voodoo to fixup scoping and parenting... - JS_ASSERT(!js::GetObjectParent(globalJSObj)); + MOZ_ASSERT(!js::GetObjectParent(globalJSObj)); JSObject* oldGlobal = JS_GetGlobalObject(aJSContext); if (!oldGlobal || oldGlobal == tempGlobal) diff --git a/js/xpconnect/src/xpcprivate.h b/js/xpconnect/src/xpcprivate.h index 404704255d39..3cb76b5f23f1 100644 --- a/js/xpconnect/src/xpcprivate.h +++ b/js/xpconnect/src/xpcprivate.h @@ -46,6 +46,7 @@ #ifndef xpcprivate_h___ #define xpcprivate_h___ +#include "mozilla/Assertions.h" #include "mozilla/Attributes.h" #include <string.h> @@ -1608,7 +1609,7 @@ public: static XPCWrappedNativeScope *GetNativeScope(JSContext *cx, JSObject *obj) { - JS_ASSERT(js::GetObjectClass(obj)->flags & JSCLASS_XPCONNECT_GLOBAL); + MOZ_ASSERT(js::GetObjectClass(obj)->flags & JSCLASS_XPCONNECT_GLOBAL); const js::Value &v = js::GetObjectSlot(obj, JSCLASS_GLOBAL_SLOT_COUNT); return v.isUndefined() @@ -3020,7 +3021,10 @@ public: JSBool IsAggregatedToNative() const {return mRoot->mOuter != nsnull;} nsISupports* GetAggregatedNativeObject() const {return mRoot->mOuter;} - void SetIsMainThreadOnly() {JS_ASSERT(mMainThread); mMainThreadOnly = true;} + void SetIsMainThreadOnly() { + MOZ_ASSERT(mMainThread); + mMainThreadOnly = true; + } bool IsMainThreadOnly() const {return mMainThreadOnly;} void TraceJS(JSTracer* trc); @@ -3649,7 +3653,7 @@ public: // XPConnect off the main thread. If you're an extension developer hitting // this, you need to change your code. See bug 716167. if (!NS_LIKELY(NS_IsMainThread() || NS_IsCycleCollectorThread())) - JS_Assert("NS_IsMainThread()", __FILE__, __LINE__); + MOZ_Assert("NS_IsMainThread()", __FILE__, __LINE__); if (cx) { if (js::GetOwnerThread(cx) == sMainJSThread) diff --git a/layout/base/FrameLayerBuilder.cpp b/layout/base/FrameLayerBuilder.cpp index d68b168c60b0..bb5f594de451 100644 --- a/layout/base/FrameLayerBuilder.cpp +++ b/layout/base/FrameLayerBuilder.cpp @@ -989,7 +989,8 @@ ContainerState::PopThebesLayerData() nsRefPtr<Layer> layer; nsRefPtr<ImageContainer> imageContainer = data->CanOptimizeImageLayer(); - if (data->mIsSolidColorInVisibleRegion || imageContainer) { + if ((data->mIsSolidColorInVisibleRegion || imageContainer) && + data->mLayer->GetValidRegion().IsEmpty()) { NS_ASSERTION(!(data->mIsSolidColorInVisibleRegion && imageContainer), "Can't be a solid color as well as an image!"); if (imageContainer) { diff --git a/layout/base/tests/bug583889_inner1.html b/layout/base/tests/bug583889_inner1.html index abf4a9d6fcef..7a9cddddf39e 100644 --- a/layout/base/tests/bug583889_inner1.html +++ b/layout/base/tests/bug583889_inner1.html @@ -20,6 +20,7 @@ function postPos() { function runTest() { var inner = document.getElementById("inner"); window.onload = grabEventAndGo; + // Wait for onLoad event. yield; document.body.scrollTop = 300; @@ -29,6 +30,8 @@ function runTest() { inner.src = "bug583889_inner2.html#id1"; inner.onload = grabEventAndGo; + // Let parent process sent message. + // Wait for onLoad event from 'inner' iframe. yield; postPos(); @@ -37,17 +40,24 @@ function runTest() { dump("hi"); inner.contentWindow.location = "bug583889_inner2.html#id2" waitAsync(); + // Let parent process sent message. + // Let 'inner' iframe update itself. yield; postPos(); inner.contentWindow.location.hash = "#id3" waitAsync(); + // Let parent process sent message. + // Let 'inner' iframe update itself. yield; postPos(); parent.postMessage("done", "*"); + // Let parent process sent messages. + // "End" generator. + yield; } var gen = runTest(); diff --git a/layout/base/tests/test_bug583889.html b/layout/base/tests/test_bug583889.html index edafa33eb631..163c0f1dbb9f 100644 --- a/layout/base/tests/test_bug583889.html +++ b/layout/base/tests/test_bug583889.html @@ -23,11 +23,13 @@ function grabEventAndGo(event) { function runTest() { window.onload = grabEventAndGo; + // Wait for onLoad event. yield; var inner = $("inner"); inner.src = "bug583889_inner1.html"; window.onmessage = grabEventAndGo; + // Wait for message from 'inner' iframe. event = yield; while (event.data != "done") { @@ -35,10 +37,13 @@ function runTest() { is(data.top, 300, "should remain at same top"); is(data.left, 300, "should remain at same left"); + // Wait for message from 'inner' iframe. event = yield; } - SimpleTest.finish(); + // finish(), yet let the test actually end first, to be safe. + SimpleTest.executeSoon(SimpleTest.finish); + // "End" generator. yield; } diff --git a/layout/build/Makefile.in b/layout/build/Makefile.in index 4c42e8bd4d40..0f899c5dfac2 100644 --- a/layout/build/Makefile.in +++ b/layout/build/Makefile.in @@ -148,6 +148,10 @@ LOCAL_INCLUDES += \ $(NULL) endif +ifdef MOZ_B2G_BT #{ +SHARED_LIBRARY_LIBS += $(DEPTH)/dom/bluetooth/$(LIB_PREFIX)dombluetooth_s.$(LIB_SUFFIX) +endif #} + ifdef MOZ_B2G_RIL #{ SHARED_LIBRARY_LIBS += $(DEPTH)/dom/system/b2g/$(LIB_PREFIX)domsystemb2g_s.$(LIB_SUFFIX) endif #} @@ -272,5 +276,8 @@ ifdef MOZ_B2G_RIL #{ LOCAL_INCLUDES += -I$(topsrcdir)/dom/system/b2g endif #} +ifdef MOZ_B2G_BT #{ +LOCAL_INCLUDES += -I$(topsrcdir)/dom/bluetooth +endif #} DEFINES += -D_IMPL_NS_LAYOUT diff --git a/layout/reftests/bugs/reftest.list b/layout/reftests/bugs/reftest.list index 92886094b786..b12f6e32f372 100644 --- a/layout/reftests/bugs/reftest.list +++ b/layout/reftests/bugs/reftest.list @@ -1575,7 +1575,7 @@ asserts(0-11) == 582146-1.html about:blank == 584699-1.html 584699-1-ref.html == 585598-2.xhtml 585598-2-ref.xhtml == 586400-1.html 586400-1-ref.html -fails-if(Android) fails-if(cocoaWidget) == 586683-1.html 586683-1-ref.html +fuzzy-if(d2d,1,1051) fails-if(Android) fails-if(cocoaWidget) == 586683-1.html 586683-1-ref.html == 589615-1a.xhtml 589615-1-ref.html == 589615-1b.html 589615-1-ref.html == 589672-1.html 589672-1-ref.html @@ -1690,6 +1690,6 @@ needs-focus != 703186-1.html 703186-2.html == 714519-1-q.html 714519-1-ref.html == 714519-2-as.html 714519-2-ref.html == 714519-2-q.html 714519-2-ref.html -fuzzy-if(cocoaWidget,1,170) == 718521.html 718521-ref.html +fuzzy-if(d2d,1,19) fuzzy-if(cocoaWidget,1,170) == 718521.html 718521-ref.html == 720987.html 720987-ref.html == 722923-1.html 722923-1-ref.html diff --git a/layout/style/nsCSSParser.cpp b/layout/style/nsCSSParser.cpp index e774246eb3fc..16e9c6b14632 100644 --- a/layout/style/nsCSSParser.cpp +++ b/layout/style/nsCSSParser.cpp @@ -4331,7 +4331,7 @@ CSSParserImpl::TranslateDimension(nsCSSValue& aValue, // Must be a zero number... NS_ASSERTION(0 == aNumber, "numbers without units must be 0"); if ((VARIANT_LENGTH & aVariantMask) != 0) { - units = eCSSUnit_Point; + units = eCSSUnit_Pixel; type = VARIANT_LENGTH; } else if ((VARIANT_ANGLE & aVariantMask) != 0) { @@ -7765,6 +7765,35 @@ CSSParserImpl::ParseSingleTransform(nsCSSValue& aValue, bool& aIs3D) minElems, maxElems, variantMask, aIs3D)) return false; + // Bug 721136: Normalize the identifier to lowercase, except that things + // like scaleX should have the last character capitalized. This matches + // what other browsers do. + nsContentUtils::ASCIIToLower(mToken.mIdent); + switch (keyword) { + case eCSSKeyword_rotatex: + case eCSSKeyword_scalex: + case eCSSKeyword_skewx: + case eCSSKeyword_translatex: + mToken.mIdent.Replace(mToken.mIdent.Length() - 1, 1, PRUnichar('X')); + break; + + case eCSSKeyword_rotatey: + case eCSSKeyword_scaley: + case eCSSKeyword_skewy: + case eCSSKeyword_translatey: + mToken.mIdent.Replace(mToken.mIdent.Length() - 1, 1, PRUnichar('Y')); + break; + + case eCSSKeyword_rotatez: + case eCSSKeyword_scalez: + case eCSSKeyword_translatez: + mToken.mIdent.Replace(mToken.mIdent.Length() - 1, 1, PRUnichar('Z')); + break; + + default: + break; + } + return ParseFunction(mToken.mIdent, variantMask, minElems, maxElems, aValue); } diff --git a/layout/style/nsComputedDOMStyle.cpp b/layout/style/nsComputedDOMStyle.cpp index 5a0f3988447d..fd593bd416f6 100644 --- a/layout/style/nsComputedDOMStyle.cpp +++ b/layout/style/nsComputedDOMStyle.cpp @@ -83,6 +83,7 @@ #include "nsDisplayList.h" #include "nsDOMCSSDeclaration.h" #include "mozilla/dom/Element.h" +#include "nsGenericElement.h" #include "CSSCalc.h" using namespace mozilla; @@ -161,8 +162,26 @@ nsComputedDOMStyle::Shutdown() } +// If nsComputedDOMStyle is changed so that any additional fields are +// traversed by the cycle collector (for instance, if wrapper cache +// handling is changed) then CAN_SKIP must be updated. NS_IMPL_CYCLE_COLLECTION_1(nsComputedDOMStyle, mContent) +// nsComputedDOMStyle has only one cycle collected field, so if +// mContent is going to be skipped, the style isn't part of a garbage +// cycle. +NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(nsComputedDOMStyle) + return !tmp->mContent || nsGenericElement::CanSkip(tmp->mContent, true); +NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END + +NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_BEGIN(nsComputedDOMStyle) + return !tmp->mContent || nsGenericElement::CanSkipInCC(tmp->mContent); +NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_END + +// CanSkipThis returns false to avoid problems with incomplete unlinking. +NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_BEGIN(nsComputedDOMStyle) +NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_END + // QueryInterface implementation for nsComputedDOMStyle NS_INTERFACE_MAP_BEGIN(nsComputedDOMStyle) NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY diff --git a/layout/style/nsComputedDOMStyle.h b/layout/style/nsComputedDOMStyle.h index a5637befb2bb..cd38c9997f3b 100644 --- a/layout/style/nsComputedDOMStyle.h +++ b/layout/style/nsComputedDOMStyle.h @@ -62,8 +62,8 @@ class nsComputedDOMStyle : public nsDOMCSSDeclaration, { public: NS_DECL_CYCLE_COLLECTING_ISUPPORTS - NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsComputedDOMStyle, - nsICSSDeclaration) + NS_DECL_CYCLE_COLLECTION_SKIPPABLE_CLASS_AMBIGUOUS(nsComputedDOMStyle, + nsICSSDeclaration) NS_IMETHOD Init(nsIDOMElement *aElement, const nsAString& aPseudoElt, diff --git a/layout/style/test/Makefile.in b/layout/style/test/Makefile.in index 41dd9cedf3e5..86d9b1321649 100644 --- a/layout/style/test/Makefile.in +++ b/layout/style/test/Makefile.in @@ -229,6 +229,7 @@ _TEST_FILES = test_acid3_test46.html \ visited_image_loading_frame.html \ visited_image_loading_frame_empty.html \ test_load_events_on_stylesheets.html \ + test_bug721136.html \ $(NULL) _VISITED_REFTEST_FILES = \ diff --git a/layout/style/test/test_bug721136.html b/layout/style/test/test_bug721136.html new file mode 100644 index 000000000000..1dec8e8d24b8 --- /dev/null +++ b/layout/style/test/test_bug721136.html @@ -0,0 +1,45 @@ +<!doctype html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=721136 +--> +<title>Test for Bug 721136</title> +<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> +<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=721136">Mozilla Bug 721136</a> +<pre id="test"> +<script> +[ + [" mAtRiX(1, 2,3,4, 5,6 ) ", "matrix(1, 2, 3, 4, 5, 6)"], + [" mAtRiX3d( 1,2,3,0,4 ,5,6,0,7,8 , 9,0,10, 11,12,1 ) ", + "matrix3d(1, 2, 3, 0, 4, 5, 6, 0, 7, 8, 9, 0, 10, 11, 12, 1)"], + [" pErSpEcTiVe( 400Px ) ", "perspective(400px)"], + [" rOtAtE( 90dEg ) ", "rotate(90deg)"], + [" rOtAtE3d( 0,0 , 1 ,180DeG ) ", "rotate3d(0, 0, 1, 180deg)"], + [" rOtAtEx( 100GrAD ) ", "rotateX(100grad)"], + [" rOtAtEy( 1.57RaD ) ", "rotateY(1.57rad)"], + [" rOtAtEz( 0.25TuRn ) ", "rotateZ(0.25turn)"], + [" sCaLe( 2 ) ", "scale(2)"], + [" sCaLe( 2,3 ) ", "scale(2, 3)"], + [" sCaLe3D( 2,4 , -9 ) ", "scale3d(2, 4, -9)"], + [" sCaLeX( 2 ) ", "scaleX(2)"], + [" sCaLeY( 2 ) ", "scaleY(2)"], + [" sCaLeZ( 2 ) ", "scaleZ(2)"], + [" sKeW( 45dEg ) ", "skew(45deg)"], + [" sKeW( 45dEg,45DeG ) ", "skew(45deg, 45deg)"], + [" sKeWx( 45DeG ) ", "skewX(45deg)"], + [" sKeWy( 45DeG ) ", "skewY(45deg)"], + [" tRaNsLaTe( 1Px ) ", "translate(1px)"], + [" tRaNsLaTe( 1Px,3Pt ) ", "translate(1px, 3pt)"], + [" tRaNsLaTe3D( 21pX,-6pX , 4pX ) ", "translate3d(21px, -6px, 4px)"], + [" tRaNsLaTeX( 1pT ) ", "translateX(1pt)"], + [" tRaNsLaTeY( 1iN ) ", "translateY(1in)"], + [" tRaNsLaTeZ( 15.4pX ) ", "translateZ(15.4px)"], + ["tranSlatex( 16px )rotatez(-90deg) rotate(100grad)\ttranslate3d(12pt, 0pc, 0.0em)", + "translateX(16px) rotateZ(-90deg) rotate(100grad) translate3d(12pt, 0pc, 0em)"], +].forEach(function(arr) { + document.documentElement.style.MozTransform = arr[0]; + is(document.documentElement.style.MozTransform, arr[1], + "incorrect serialization"); +}); +</script> +</pre> diff --git a/layout/style/test/test_keyframes_rules.html b/layout/style/test/test_keyframes_rules.html index ca6a1f3c23bc..f31f057ef2b1 100644 --- a/layout/style/test/test_keyframes_rules.html +++ b/layout/style/test/test_keyframes_rules.html @@ -71,12 +71,12 @@ is(bounce.cssRules[0].keyText, "0%", "keyframe rule keyText"); is(bounce.cssRules[1].keyText, "25%", "keyframe rule keyText"); is(bounce.cssRules[2].keyText, "75%, 85%", "keyframe rule keyText"); is(bounce.cssRules[3].keyText, "100%", "keyframe rule keyText"); -is(bounce.cssRules[0].style.marginLeft, "0pt", "keyframe rule style"); +is(bounce.cssRules[0].style.marginLeft, "0px", "keyframe rule style"); is(bounce.cssRules[1].style.marginLeft, "25px", "keyframe rule style"); -is(bounce.cssRules[0].cssText, "0% { margin-left: 0pt; }"); +is(bounce.cssRules[0].cssText, "0% { margin-left: 0px; }"); is(bounce.cssText, "@-moz-keyframes bouncier {\n" + - "0% { margin-left: 0pt; }\n" + + "0% { margin-left: 0px; }\n" + "25% { margin-left: 25px; }\n" + "75%, 85% { margin-left: 90px; }\n" + "100% { margin-left: 100px; }\n" + diff --git a/layout/style/test/test_units_length.html b/layout/style/test/test_units_length.html index 378a98f35205..6db3f0c7dc6f 100644 --- a/layout/style/test/test_units_length.html +++ b/layout/style/test/test_units_length.html @@ -48,6 +48,11 @@ for (var test in tests) { } } +// Bug 393910 +p.setAttribute("style", "margin-left: 0"); +is(p.style.getPropertyValue("margin-left"), "0px", + "0 serializes to 0px"); + </script> </pre> </body> diff --git a/layout/svg/base/src/nsSVGForeignObjectFrame.cpp b/layout/svg/base/src/nsSVGForeignObjectFrame.cpp index 67de74f79dba..35169c61fbcd 100644 --- a/layout/svg/base/src/nsSVGForeignObjectFrame.cpp +++ b/layout/svg/base/src/nsSVGForeignObjectFrame.cpp @@ -271,12 +271,6 @@ nsSVGForeignObjectFrame::PaintSVG(nsSVGRenderState *aContext, gfx->Multiply(matrixForChildren); - // Transform the dirty rect into the rectangle containing the - // transformed dirty rect. - gfxMatrix invmatrix = matrix.Invert(); - NS_ASSERTION(!invmatrix.IsSingular(), - "inverse of non-singular matrix should be non-singular"); - PRUint32 flags = nsLayoutUtils::PAINT_IN_TRANSFORM; if (aContext->IsPaintingToWindow()) { flags |= nsLayoutUtils::PAINT_TO_WINDOW; diff --git a/layout/svg/base/src/nsSVGImageFrame.cpp b/layout/svg/base/src/nsSVGImageFrame.cpp index 9a2cd3205d6e..07e1eeb83dd2 100644 --- a/layout/svg/base/src/nsSVGImageFrame.cpp +++ b/layout/svg/base/src/nsSVGImageFrame.cpp @@ -52,7 +52,7 @@ using namespace mozilla; class nsSVGImageFrame; -class nsSVGImageListener : public nsStubImageDecoderObserver +class nsSVGImageListener MOZ_FINAL : public nsStubImageDecoderObserver { public: nsSVGImageListener(nsSVGImageFrame *aFrame); diff --git a/media/libpng/pngrutil.c b/media/libpng/pngrutil.c index 85386f2ad560..1f7af96df6dd 100644 --- a/media/libpng/pngrutil.c +++ b/media/libpng/pngrutil.c @@ -401,8 +401,15 @@ png_decompress_chunk(png_structp png_ptr, int comp_type, { /* Success (maybe) - really uncompress the chunk. */ png_size_t new_size = 0; - png_charp text = png_malloc_warn(png_ptr, - prefix_size + expanded_size + 1); + png_charp text = NULL; + /* Need to check for both truncation (64-bit platforms) and integer + * overflow. + */ + if (prefix_size + expanded_size > prefix_size && + prefix_size + expanded_size < 0xffffffffU) + { + text = png_malloc_warn(png_ptr, prefix_size + expanded_size + 1); + } if (text != NULL) { diff --git a/mobile/android/base/AboutHomeContent.java b/mobile/android/base/AboutHomeContent.java index bdf6e16c82f7..cf6a18ce335d 100644 --- a/mobile/android/base/AboutHomeContent.java +++ b/mobile/android/base/AboutHomeContent.java @@ -693,14 +693,14 @@ public class AboutHomeContent extends ScrollView { ImageView thumbnail = (ImageView) view; if (b == null) { - thumbnail.setImageResource(R.drawable.abouthome_topsite_placeholder); + thumbnail.setImageResource(R.drawable.tab_thumbnail_default); } else { try { Bitmap bitmap = BitmapFactory.decodeByteArray(b, 0, b.length); thumbnail.setImageBitmap(bitmap); } catch (OutOfMemoryError oom) { Log.e(LOGTAG, "Unable to load thumbnail bitmap", oom); - thumbnail.setImageResource(R.drawable.abouthome_topsite_placeholder); + thumbnail.setImageResource(R.drawable.tab_thumbnail_default); } } diff --git a/mobile/android/base/AwesomeBarTabs.java b/mobile/android/base/AwesomeBarTabs.java index d8d50d40a274..19524a3d1c35 100644 --- a/mobile/android/base/AwesomeBarTabs.java +++ b/mobile/android/base/AwesomeBarTabs.java @@ -284,7 +284,7 @@ public class AwesomeBarTabs extends TabHost { try { // use reflection to disable auto-requery - Class cls = Class.forName("android.widget.CursorTreeAdapter"); + Class<?> cls = Class.forName("android.widget.CursorTreeAdapter"); Field field = cls.getDeclaredField("mAutoRequery"); field.setAccessible(true); field.set(mBookmarksAdapter, false); diff --git a/mobile/android/base/BrowserToolbar.java b/mobile/android/base/BrowserToolbar.java index ef373e60a440..8708e236de81 100644 --- a/mobile/android/base/BrowserToolbar.java +++ b/mobile/android/base/BrowserToolbar.java @@ -322,6 +322,20 @@ public class BrowserToolbar extends LinearLayout { } } + public void show() { + if (Build.VERSION.SDK_INT >= 11) + GeckoActionBar.show(GeckoApp.mAppContext); + else + setVisibility(View.VISIBLE); + } + + public void hide() { + if (Build.VERSION.SDK_INT >= 11) + GeckoActionBar.hide(GeckoApp.mAppContext); + else + setVisibility(View.GONE); + } + public void refresh() { Tab tab = Tabs.getInstance().getSelectedTab(); if (tab != null) { diff --git a/mobile/android/base/GeckoActionBar.java b/mobile/android/base/GeckoActionBar.java index 9f1db9b7e021..4f707d8b6c65 100644 --- a/mobile/android/base/GeckoActionBar.java +++ b/mobile/android/base/GeckoActionBar.java @@ -66,4 +66,8 @@ public class GeckoActionBar { public static void setDisplayHomeAsUpEnabled(Activity activity, boolean enabled) { activity.getActionBar().setDisplayHomeAsUpEnabled(enabled); } + + public static void show(Activity activity) { + activity.getActionBar().show(); + } } diff --git a/mobile/android/base/GeckoApp.java b/mobile/android/base/GeckoApp.java index a06f1cfead98..2698af98bde7 100644 --- a/mobile/android/base/GeckoApp.java +++ b/mobile/android/base/GeckoApp.java @@ -1024,13 +1024,13 @@ abstract public class GeckoApp } else if (event.equals("ToggleChrome:Hide")) { mMainHandler.post(new Runnable() { public void run() { - mBrowserToolbar.setVisibility(View.GONE); + mBrowserToolbar.hide(); } }); } else if (event.equals("ToggleChrome:Show")) { mMainHandler.post(new Runnable() { public void run() { - mBrowserToolbar.setVisibility(View.VISIBLE); + mBrowserToolbar.show(); } }); } else if (event.equals("DOMFullScreen:Start")) { @@ -1507,7 +1507,8 @@ abstract public class GeckoApp if (tab == null) return; - tab.removePluginLayer(surface); + Layer layer = tab.removePluginLayer(surface); + hidePluginLayer(layer); } public void showSurface(Surface surface, int x, int y, @@ -1642,9 +1643,12 @@ abstract public class GeckoApp mMainHandler.post(new Runnable() { public void run() { // Hide/show the system notification bar - getWindow().setFlags(fullscreen ? - WindowManager.LayoutParams.FLAG_FULLSCREEN : 0, - WindowManager.LayoutParams.FLAG_FULLSCREEN); + Window window = getWindow(); + window.setFlags(fullscreen ? + WindowManager.LayoutParams.FLAG_FULLSCREEN : 0, + WindowManager.LayoutParams.FLAG_FULLSCREEN); + + window.getDecorView().setSystemUiVisibility(fullscreen ? 1 : 0); } }); } @@ -2087,7 +2091,7 @@ abstract public class GeckoApp Runnable r = new SessionSnapshotRunnable(null); GeckoAppShell.getHandler().post(r); - GeckoAppShell.sendEventToGecko(GeckoEvent.createPauseEvent()); + GeckoAppShell.sendEventToGecko(GeckoEvent.createPauseEvent(mOwnActivityDepth)); // The user is navigating away from this activity, but nothing // has come to the foreground yet; for Gecko, we may want to // stop repainting, for example. @@ -2107,7 +2111,8 @@ abstract public class GeckoApp { Log.i(LOGTAG, "resume"); if (checkLaunchState(LaunchState.GeckoRunning)) - GeckoAppShell.onResume(); + GeckoAppShell.sendEventToGecko(GeckoEvent.createResumeEvent(mOwnActivityDepth)); + // After an onPause, the activity is back in the foreground. // Undo whatever we did in onPause. super.onResume(); @@ -2156,7 +2161,7 @@ abstract public class GeckoApp // etc., and generally mark the profile as 'clean', and then // dirty it again if we get an onResume. - GeckoAppShell.sendEventToGecko(GeckoEvent.createStoppingEvent()); + GeckoAppShell.sendEventToGecko(GeckoEvent.createStoppingEvent(mOwnActivityDepth)); super.onStop(); } @@ -2173,7 +2178,7 @@ abstract public class GeckoApp Log.w(LOGTAG, "zerdatime " + SystemClock.uptimeMillis() + " - onStart"); Log.i(LOGTAG, "start"); - GeckoAppShell.sendEventToGecko(GeckoEvent.createStartEvent()); + GeckoAppShell.sendEventToGecko(GeckoEvent.createStartEvent(mOwnActivityDepth)); super.onStart(); } diff --git a/mobile/android/base/GeckoEvent.java b/mobile/android/base/GeckoEvent.java index 30701e3b3784..eb622c7770d1 100644 --- a/mobile/android/base/GeckoEvent.java +++ b/mobile/android/base/GeckoEvent.java @@ -87,6 +87,7 @@ public class GeckoEvent { private static final int VISITED = 21; private static final int NETWORK_CHANGED = 22; private static final int PROXIMITY_EVENT = 23; + private static final int ACTIVITY_RESUMING = 24; public static final int IME_COMPOSITION_END = 0; public static final int IME_COMPOSITION_BEGIN = 1; @@ -139,16 +140,28 @@ public class GeckoEvent { mType = evType; } - public static GeckoEvent createPauseEvent() { - return new GeckoEvent(ACTIVITY_PAUSING); + public static GeckoEvent createPauseEvent(int activityDepth) { + GeckoEvent event = new GeckoEvent(ACTIVITY_PAUSING); + event.mFlags = activityDepth > 0 ? 1 : 0; + return event; } - public static GeckoEvent createStoppingEvent() { - return new GeckoEvent(ACTIVITY_STOPPING); + public static GeckoEvent createResumeEvent(int activityDepth) { + GeckoEvent event = new GeckoEvent(ACTIVITY_RESUMING); + event.mFlags = activityDepth > 0 ? 1 : 0; + return event; } - public static GeckoEvent createStartEvent() { - return new GeckoEvent(ACTIVITY_START); + public static GeckoEvent createStoppingEvent(int activityDepth) { + GeckoEvent event = new GeckoEvent(ACTIVITY_STOPPING); + event.mFlags = activityDepth > 0 ? 1 : 0; + return event; + } + + public static GeckoEvent createStartEvent(int activityDepth) { + GeckoEvent event = new GeckoEvent(ACTIVITY_START); + event.mFlags = activityDepth > 0 ? 1 : 0; + return event; } public static GeckoEvent createShutdownEvent() { diff --git a/mobile/android/base/Makefile.in b/mobile/android/base/Makefile.in index 08bcb5d9140a..70d0d8ab0cb6 100644 --- a/mobile/android/base/Makefile.in +++ b/mobile/android/base/Makefile.in @@ -295,8 +295,6 @@ RES_DRAWABLE_BASE = \ res/drawable/abouthome_sync_logo.png \ res/drawable/abouthome_sync_bg.9.png \ res/drawable/abouthome_sync_pressed_bg.9.png \ - res/drawable/abouthome_topsite_placeholder.png \ - res/drawable/abouthome_topsite_shadow.9.png \ res/drawable/awesomebar_tab.9.png \ res/drawable/awesomebar_tab_pressed.9.png \ res/drawable/ic_addons_empty.png \ @@ -345,8 +343,6 @@ RES_DRAWABLE_HDPI = \ res/drawable-hdpi/abouthome_sync_logo.png \ res/drawable-hdpi/abouthome_sync_bg.9.png \ res/drawable-hdpi/abouthome_sync_pressed_bg.9.png \ - res/drawable-hdpi/abouthome_topsite_placeholder.png \ - res/drawable-hdpi/abouthome_topsite_shadow.9.png \ res/drawable-hdpi/awesomebar_tab.9.png \ res/drawable-hdpi/awesomebar_tab_pressed.9.png \ res/drawable-hdpi/ic_addons_empty.png \ @@ -409,8 +405,6 @@ RES_DRAWABLE_XHDPI_V11 = \ res/drawable-xhdpi-v11/abouthome_sync_logo.png \ res/drawable-xhdpi-v11/abouthome_sync_bg.9.png \ res/drawable-xhdpi-v11/abouthome_sync_pressed_bg.9.png \ - res/drawable-xhdpi-v11/abouthome_topsite_placeholder.png \ - res/drawable-xhdpi-v11/abouthome_topsite_shadow.9.png \ res/drawable-xhdpi-v11/awesomebar_tab.9.png \ res/drawable-xhdpi-v11/awesomebar_tab_pressed.9.png \ res/drawable-xhdpi-v11/ic_addons_empty.png \ diff --git a/mobile/android/base/db/AndroidBrowserDB.java b/mobile/android/base/db/AndroidBrowserDB.java index b2edaa9403a2..ca52ca37e007 100644 --- a/mobile/android/base/db/AndroidBrowserDB.java +++ b/mobile/android/base/db/AndroidBrowserDB.java @@ -188,23 +188,6 @@ public class AndroidBrowserDB implements BrowserDB.BrowserDBIface { Browser.clearHistory(cr); } - public Cursor getAllBookmarks(ContentResolver cr) { - Cursor c = cr.query(Browser.BOOKMARKS_URI, - new String[] { URL_COLUMN_ID, - BookmarkColumns.URL, - BookmarkColumns.TITLE, - BookmarkColumns.FAVICON }, - // Select all bookmarks with a non-empty URL. When the history - // is empty there appears to be a dummy entry in the database - // which has a title of "Bookmarks" and no URL; the length restriction - // is to avoid picking that up specifically. - Browser.BookmarkColumns.BOOKMARK + " = 1 AND LENGTH(" + Browser.BookmarkColumns.URL + ") > 0", - null, - Browser.BookmarkColumns.TITLE); - - return new AndroidDBCursor(c); - } - public Cursor getMobileBookmarks(ContentResolver cr) { Cursor c = cr.query(null, null, null, null, null); return new AndroidDBCursor(c); diff --git a/mobile/android/base/db/BrowserDB.java b/mobile/android/base/db/BrowserDB.java index 80a80ba015d0..922e6e8d7f30 100644 --- a/mobile/android/base/db/BrowserDB.java +++ b/mobile/android/base/db/BrowserDB.java @@ -77,8 +77,6 @@ public class BrowserDB { public void clearHistory(ContentResolver cr); - public Cursor getAllBookmarks(ContentResolver cr); - public Cursor getMobileBookmarks(ContentResolver cr); public Cursor getDesktopBookmarks(ContentResolver cr); @@ -148,10 +146,6 @@ public class BrowserDB { sDb.clearHistory(cr); } - public static Cursor getAllBookmarks(ContentResolver cr) { - return sDb.getAllBookmarks(cr); - } - public static Cursor getMobileBookmarks(ContentResolver cr) { return sDb.getMobileBookmarks(cr); } diff --git a/mobile/android/base/db/LocalBrowserDB.java b/mobile/android/base/db/LocalBrowserDB.java index 60906a18d71e..231920710213 100644 --- a/mobile/android/base/db/LocalBrowserDB.java +++ b/mobile/android/base/db/LocalBrowserDB.java @@ -80,14 +80,28 @@ public class LocalBrowserDB implements BrowserDB.BrowserDBIface { private final String mProfile; private long mMobileFolderId; + private final Uri mBookmarksUriWithProfile; + private final Uri mParentsUriWithProfile; + private final Uri mHistoryUriWithProfile; + private final Uri mImagesUriWithProfile; + private final Uri mDeletedHistoryUriWithProfile; + public LocalBrowserDB(String profile) { mProfile = profile; mMobileFolderId = -1; + + mBookmarksUriWithProfile = appendProfile(Bookmarks.CONTENT_URI); + mParentsUriWithProfile = appendProfile(Bookmarks.PARENTS_CONTENT_URI); + mHistoryUriWithProfile = appendProfile(History.CONTENT_URI); + mImagesUriWithProfile = appendProfile(Images.CONTENT_URI); + + mDeletedHistoryUriWithProfile = mHistoryUriWithProfile.buildUpon(). + appendQueryParameter(BrowserContract.PARAM_SHOW_DELETED, "1").build(); } - private Uri appendProfileAndLimit(Uri uri, int limit) { - return uri.buildUpon().appendQueryParameter(BrowserContract.PARAM_PROFILE, mProfile). - appendQueryParameter(BrowserContract.PARAM_LIMIT, String.valueOf(limit)).build(); + private Uri historyUriWithLimit(int limit) { + return mHistoryUriWithProfile.buildUpon().appendQueryParameter(BrowserContract.PARAM_LIMIT, + String.valueOf(limit)).build(); } private Uri appendProfile(Uri uri) { @@ -95,7 +109,7 @@ public class LocalBrowserDB implements BrowserDB.BrowserDBIface { } private Cursor filterAllSites(ContentResolver cr, String[] projection, CharSequence constraint, int limit, CharSequence urlFilter) { - Cursor c = cr.query(appendProfileAndLimit(History.CONTENT_URI, limit), + Cursor c = cr.query(historyUriWithLimit(limit), projection, (urlFilter != null ? "(" + History.URL + " NOT LIKE ? ) AND " : "" ) + "(" + History.URL + " LIKE ? OR " + History.TITLE + " LIKE ?)", @@ -136,7 +150,7 @@ public class LocalBrowserDB implements BrowserDB.BrowserDBIface { Cursor cursor = null; try { - cursor = cr.query(appendProfile(History.CONTENT_URI), + cursor = cr.query(mHistoryUriWithProfile, new String[] { History._ID }, null, null, @@ -170,7 +184,7 @@ public class LocalBrowserDB implements BrowserDB.BrowserDBIface { History.VISITS, // 1 }; - cursor = cr.query(appendProfile(History.CONTENT_URI), + cursor = cr.query(mDeletedHistoryUriWithProfile, projection, History.URL + " = ?", new String[] { uri }, @@ -182,6 +196,9 @@ public class LocalBrowserDB implements BrowserDB.BrowserDBIface { values.put(History.VISITS, cursor.getInt(1) + 1); values.put(History.DATE_LAST_VISITED, now); + // Restore deleted record if possible + values.put(History.IS_DELETED, 0); + Uri historyUri = ContentUris.withAppendedId(History.CONTENT_URI, cursor.getLong(0)); cr.update(appendProfile(historyUri), values, null, null); } else { @@ -196,7 +213,7 @@ public class LocalBrowserDB implements BrowserDB.BrowserDBIface { values.put(History.DATE_LAST_VISITED, now); values.put(History.TITLE, uri); - cr.insert(appendProfile(History.CONTENT_URI), values); + cr.insert(mHistoryUriWithProfile, values); } } finally { if (cursor != null) @@ -208,7 +225,7 @@ public class LocalBrowserDB implements BrowserDB.BrowserDBIface { ContentValues values = new ContentValues(); values.put(History.TITLE, title); - cr.update(appendProfile(History.CONTENT_URI), + cr.update(mHistoryUriWithProfile, values, History.URL + " = ?", new String[] { uri }); @@ -219,7 +236,7 @@ public class LocalBrowserDB implements BrowserDB.BrowserDBIface { int oldVisits = 0; Cursor cursor = null; try { - cursor = cr.query(appendProfile(History.CONTENT_URI), + cursor = cr.query(mHistoryUriWithProfile, new String[] { History.VISITS }, History.URL + " = ?", new String[] { uri }, @@ -240,14 +257,14 @@ public class LocalBrowserDB implements BrowserDB.BrowserDBIface { values.put(History.TITLE, title); } - cr.update(appendProfile(History.CONTENT_URI), + cr.update(mHistoryUriWithProfile, values, History.URL + " = ?", new String[] { uri }); } public Cursor getAllVisitedHistory(ContentResolver cr) { - Cursor c = cr.query(appendProfile(History.CONTENT_URI), + Cursor c = cr.query(mHistoryUriWithProfile, new String[] { History.URL }, History.VISITS + " > 0", null, @@ -257,7 +274,7 @@ public class LocalBrowserDB implements BrowserDB.BrowserDBIface { } public Cursor getRecentHistory(ContentResolver cr, int limit) { - Cursor c = cr.query(appendProfileAndLimit(History.CONTENT_URI, limit), + Cursor c = cr.query(historyUriWithLimit(limit), new String[] { History._ID, History.URL, History.TITLE, @@ -276,21 +293,7 @@ public class LocalBrowserDB implements BrowserDB.BrowserDBIface { } public void clearHistory(ContentResolver cr) { - cr.delete(appendProfile(History.CONTENT_URI), null, null); - } - - public Cursor getAllBookmarks(ContentResolver cr) { - Cursor c = cr.query(appendProfile(Bookmarks.CONTENT_URI), - new String[] { Bookmarks._ID, - Bookmarks.URL, - Bookmarks.TITLE, - Bookmarks.FAVICON, - Bookmarks.KEYWORD }, - Bookmarks.IS_FOLDER + " = 0", - null, - Bookmarks.TITLE + " ASC"); - - return new LocalDBCursor(c); + cr.delete(mHistoryUriWithProfile, null, null); } public Cursor getMobileBookmarks(ContentResolver cr) { @@ -304,7 +307,7 @@ public class LocalBrowserDB implements BrowserDB.BrowserDBIface { private Cursor getBookmarks(ContentResolver cr, boolean mobileBookmarks) { String parentSelection = mobileBookmarks ? " = ?" : " != ?"; long mobileFolderId = getMobileBookmarksFolderId(cr); - Cursor c = cr.query(appendProfile(Bookmarks.CONTENT_URI), + Cursor c = cr.query(mBookmarksUriWithProfile, new String[] { Bookmarks._ID, Bookmarks.URL, Bookmarks.TITLE, @@ -318,7 +321,7 @@ public class LocalBrowserDB implements BrowserDB.BrowserDBIface { } public boolean isBookmark(ContentResolver cr, String uri) { - Cursor cursor = cr.query(appendProfile(Bookmarks.CONTENT_URI), + Cursor cursor = cr.query(mBookmarksUriWithProfile, new String[] { Bookmarks._ID }, Bookmarks.URL + " = ?", new String[] { uri }, @@ -331,7 +334,7 @@ public class LocalBrowserDB implements BrowserDB.BrowserDBIface { } public String getUrlForKeyword(ContentResolver cr, String keyword) { - Cursor cursor = cr.query(appendProfile(Bookmarks.CONTENT_URI), + Cursor cursor = cr.query(mBookmarksUriWithProfile, new String[] { Bookmarks.URL }, Bookmarks.KEYWORD + " = ?", new String[] { keyword }, @@ -355,7 +358,7 @@ public class LocalBrowserDB implements BrowserDB.BrowserDBIface { Cursor c = null; try { - c = cr.query(appendProfile(Bookmarks.CONTENT_URI), + c = cr.query(mBookmarksUriWithProfile, new String[] { Bookmarks._ID }, Bookmarks.GUID + " = ?", new String[] { Bookmarks.MOBILE_FOLDER_GUID }, @@ -379,15 +382,9 @@ public class LocalBrowserDB implements BrowserDB.BrowserDBIface { ContentValues values = new ContentValues(); values.put(Bookmarks.DATE_MODIFIED, System.currentTimeMillis()); - // Inline appendProfile here to avoid building multiple Uri objects. - final Uri updateURI = - Bookmarks.CONTENT_URI.buildUpon() - .appendPath("parents") - .appendQueryParameter(BrowserContract.PARAM_PROFILE, mProfile) - .build(); String where = param + " = ?"; String[] args = new String[] { value }; - int updated = cr.update(updateURI, values, where, args); + int updated = cr.update(mParentsUriWithProfile, values, where, args); debug("Updated " + updated + " rows to new modified time."); } @@ -406,7 +403,7 @@ public class LocalBrowserDB implements BrowserDB.BrowserDBIface { // Restore deleted record if possible values.put(Bookmarks.IS_DELETED, 0); - Uri contentUri = appendProfile(Bookmarks.CONTENT_URI); + Uri contentUri = mBookmarksUriWithProfile; int updated = cr.update(contentUri, values, Bookmarks.URL + " = ?", @@ -430,7 +427,7 @@ public class LocalBrowserDB implements BrowserDB.BrowserDBIface { } public void removeBookmark(ContentResolver cr, int id) { - Uri contentUri = appendProfile(Bookmarks.CONTENT_URI); + Uri contentUri = mBookmarksUriWithProfile; // Do this now so that the item still exists! final String idString = String.valueOf(id); @@ -444,7 +441,7 @@ public class LocalBrowserDB implements BrowserDB.BrowserDBIface { } public void removeBookmarksWithURL(ContentResolver cr, String uri) { - Uri contentUri = appendProfile(Bookmarks.CONTENT_URI); + Uri contentUri = mBookmarksUriWithProfile; // Do this now so that the items still exist! bumpParents(cr, Bookmarks.URL, uri); @@ -457,7 +454,7 @@ public class LocalBrowserDB implements BrowserDB.BrowserDBIface { } public void registerBookmarkObserver(ContentResolver cr, ContentObserver observer) { - Uri uri = appendProfile(Bookmarks.CONTENT_URI); + Uri uri = mBookmarksUriWithProfile; cr.registerContentObserver(uri, false, observer); } @@ -467,14 +464,14 @@ public class LocalBrowserDB implements BrowserDB.BrowserDBIface { values.put(Bookmarks.URL, uri); values.put(Bookmarks.KEYWORD, keyword); - cr.update(appendProfile(Bookmarks.CONTENT_URI), + cr.update(mBookmarksUriWithProfile, values, Bookmarks.URL + " = ?", new String[] { oldUri }); } public BitmapDrawable getFaviconForUrl(ContentResolver cr, String uri) { - Cursor c = cr.query(appendProfile(Images.CONTENT_URI), + Cursor c = cr.query(mImagesUriWithProfile, new String[] { Images.FAVICON }, Images.URL + " = ?", new String[] { uri }, @@ -511,13 +508,13 @@ public class LocalBrowserDB implements BrowserDB.BrowserDBIface { // Restore deleted record if possible values.put(Images.IS_DELETED, 0); - int updated = cr.update(appendProfile(Images.CONTENT_URI), + int updated = cr.update(mImagesUriWithProfile, values, Images.URL + " = ?", new String[] { uri }); if (updated == 0) - cr.insert(appendProfile(Images.CONTENT_URI), values); + cr.insert(mImagesUriWithProfile, values); } public void updateThumbnailForUrl(ContentResolver cr, String uri, @@ -534,17 +531,17 @@ public class LocalBrowserDB implements BrowserDB.BrowserDBIface { // Restore deleted record if possible values.put(Images.IS_DELETED, 0); - int updated = cr.update(appendProfile(Images.CONTENT_URI), + int updated = cr.update(mImagesUriWithProfile, values, Images.URL + " = ?", new String[] { uri }); if (updated == 0) - cr.insert(appendProfile(Images.CONTENT_URI), values); + cr.insert(mImagesUriWithProfile, values); } public byte[] getThumbnailForUrl(ContentResolver cr, String uri) { - Cursor c = cr.query(appendProfile(Images.CONTENT_URI), + Cursor c = cr.query(mImagesUriWithProfile, new String[] { Images.THUMBNAIL }, Images.URL + " = ?", new String[] { uri }, diff --git a/mobile/android/base/resources/drawable-hdpi/abouthome_topsite_placeholder.png b/mobile/android/base/resources/drawable-hdpi/abouthome_topsite_placeholder.png deleted file mode 100644 index 82452a943b7d..000000000000 Binary files a/mobile/android/base/resources/drawable-hdpi/abouthome_topsite_placeholder.png and /dev/null differ diff --git a/mobile/android/base/resources/drawable-hdpi/abouthome_topsite_shadow.9.png b/mobile/android/base/resources/drawable-hdpi/abouthome_topsite_shadow.9.png deleted file mode 100644 index c3afbe3115cc..000000000000 Binary files a/mobile/android/base/resources/drawable-hdpi/abouthome_topsite_shadow.9.png and /dev/null differ diff --git a/mobile/android/base/resources/drawable-xhdpi-v11/abouthome_topsite_placeholder.png b/mobile/android/base/resources/drawable-xhdpi-v11/abouthome_topsite_placeholder.png deleted file mode 100644 index 6413a45633ee..000000000000 Binary files a/mobile/android/base/resources/drawable-xhdpi-v11/abouthome_topsite_placeholder.png and /dev/null differ diff --git a/mobile/android/base/resources/drawable-xhdpi-v11/abouthome_topsite_shadow.9.png b/mobile/android/base/resources/drawable-xhdpi-v11/abouthome_topsite_shadow.9.png deleted file mode 100644 index bad57a716659..000000000000 Binary files a/mobile/android/base/resources/drawable-xhdpi-v11/abouthome_topsite_shadow.9.png and /dev/null differ diff --git a/mobile/android/base/resources/drawable/abouthome_topsite_placeholder.png b/mobile/android/base/resources/drawable/abouthome_topsite_placeholder.png deleted file mode 100644 index 7ae2b283350a..000000000000 Binary files a/mobile/android/base/resources/drawable/abouthome_topsite_placeholder.png and /dev/null differ diff --git a/mobile/android/base/resources/drawable/abouthome_topsite_shadow.9.png b/mobile/android/base/resources/drawable/abouthome_topsite_shadow.9.png deleted file mode 100644 index 478fb92498e7..000000000000 Binary files a/mobile/android/base/resources/drawable/abouthome_topsite_shadow.9.png and /dev/null differ diff --git a/mobile/android/base/resources/layout/abouthome_topsite_item.xml b/mobile/android/base/resources/layout/abouthome_topsite_item.xml index 19e3afcc7caa..c4860aa6a61a 100644 --- a/mobile/android/base/resources/layout/abouthome_topsite_item.xml +++ b/mobile/android/base/resources/layout/abouthome_topsite_item.xml @@ -10,7 +10,7 @@ <LinearLayout android:orientation="vertical" android:layout_width="138dip" android:layout_height="80dip" - android:background="@drawable/abouthome_topsite_shadow" + android:background="@drawable/tab_thumbnail_shadow" android:padding="1dip" android:paddingBottom="2dip"> diff --git a/mobile/android/base/ui/PanZoomController.java b/mobile/android/base/ui/PanZoomController.java index bfd0b43e7d05..04a182f0d157 100644 --- a/mobile/android/base/ui/PanZoomController.java +++ b/mobile/android/base/ui/PanZoomController.java @@ -297,7 +297,7 @@ public class PanZoomController cancelTouch(); startPanning(event.getX(0), event.getY(0), event.getEventTime()); GeckoApp.mAppContext.hidePlugins(false /* don't hide layers */); - GeckoApp.mAppContext.mAutoCompletePopup.hide(); + GeckoApp.mAutoCompletePopup.hide(); track(event); return true; diff --git a/mobile/xul/installer/package-manifest.in b/mobile/xul/installer/package-manifest.in index 32a7f989175f..e03157b5edd8 100644 --- a/mobile/xul/installer/package-manifest.in +++ b/mobile/xul/installer/package-manifest.in @@ -157,6 +157,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 diff --git a/netwerk/protocol/http/SpdySession.cpp b/netwerk/protocol/http/SpdySession.cpp index d5ae8031b093..b592a6ef4236 100644 --- a/netwerk/protocol/http/SpdySession.cpp +++ b/netwerk/protocol/http/SpdySession.cpp @@ -1949,6 +1949,40 @@ SpdySession::Http1xTransactionCount() return 0; } +// used as an enumerator by TakeSubTransactions() +static PLDHashOperator +TakeStream(nsAHttpTransaction *key, + nsAutoPtr<SpdyStream> &stream, + void *closure) +{ + nsTArray<nsRefPtr<nsAHttpTransaction> > *list = + static_cast<nsTArray<nsRefPtr<nsAHttpTransaction> > *>(closure); + + list->AppendElement(key); + + // removing the stream from the hash will delete the stream + // and drop the transaction reference the hash held + return PL_DHASH_REMOVE; +} + +nsresult +SpdySession::TakeSubTransactions( + nsTArray<nsRefPtr<nsAHttpTransaction> > &outTransactions) +{ + // Generally this cannot be done with spdy as transactions are + // started right away. + + LOG3(("SpdySession::TakeSubTransactions %p\n", this)); + + if (mConcurrentHighWater > 0) + return NS_ERROR_ALREADY_OPENED; + + LOG3((" taking %d\n", mStreamTransactionHash.Count())); + + mStreamTransactionHash.Enumerate(TakeStream, &outTransactions); + return NS_OK; +} + //----------------------------------------------------------------------------- // Pass through methods of nsAHttpConnection //----------------------------------------------------------------------------- diff --git a/netwerk/protocol/http/nsAHttpTransaction.h b/netwerk/protocol/http/nsAHttpTransaction.h index d859cfcf87a5..4a7980d2ad48 100644 --- a/netwerk/protocol/http/nsAHttpTransaction.h +++ b/netwerk/protocol/http/nsAHttpTransaction.h @@ -39,6 +39,7 @@ #define nsAHttpTransaction_h__ #include "nsISupports.h" +#include "nsTArray.h" class nsAHttpConnection; class nsAHttpSegmentReader; @@ -101,6 +102,18 @@ public: // abstract object. Pipelines may have multiple, SPDY has 0, // normal http transactions have 1. virtual PRUint32 Http1xTransactionCount() = 0; + + // called to remove the unused sub transactions from an object that can + // handle multiple transactions simultaneously (i.e. pipelines or spdy). + // + // Returns NS_ERROR_NOT_IMPLEMENTED if the object does not implement + // sub-transactions. + // + // Returns NS_ERROR_ALREADY_OPENED if the subtransactions have been + // at least partially written and cannot be moved. + // + virtual nsresult TakeSubTransactions( + nsTArray<nsRefPtr<nsAHttpTransaction> > &outTransactions) = 0; }; #define NS_DECL_NSAHTTPTRANSACTION \ @@ -118,7 +131,8 @@ public: void Close(nsresult reason); \ void SetSSLConnectFailed(); \ nsHttpRequestHead *RequestHead(); \ - PRUint32 Http1xTransactionCount(); + PRUint32 Http1xTransactionCount(); \ + nsresult TakeSubTransactions(nsTArray<nsRefPtr<nsAHttpTransaction> > &outTransactions); //----------------------------------------------------------------------------- // nsAHttpSegmentReader diff --git a/netwerk/protocol/http/nsHttpChannelAuthProvider.cpp b/netwerk/protocol/http/nsHttpChannelAuthProvider.cpp index 3cdece64df88..6acce884ff58 100644 --- a/netwerk/protocol/http/nsHttpChannelAuthProvider.cpp +++ b/netwerk/protocol/http/nsHttpChannelAuthProvider.cpp @@ -128,13 +128,16 @@ nsHttpChannelAuthProvider::ProcessAuthentication(PRUint32 httpStatus, rv = mAuthChannel->GetLoadFlags(&loadFlags); if (NS_FAILED(rv)) return rv; - if (loadFlags & nsIRequest::LOAD_ANONYMOUS) { - return NS_ERROR_NOT_AVAILABLE; - } - nsCAutoString challenges; mProxyAuth = (httpStatus == 407); + // Do proxy auth even if we're LOAD_ANONYMOUS + if ((loadFlags & nsIRequest::LOAD_ANONYMOUS) && + (!mProxyAuth || !UsingHttpProxy())) { + LOG(("Skipping authentication for anonymous non-proxy request\n")); + return NS_ERROR_NOT_AVAILABLE; + } + rv = PrepareForAuthentication(mProxyAuth); if (NS_FAILED(rv)) return rv; @@ -199,10 +202,6 @@ nsHttpChannelAuthProvider::AddAuthorizationHeaders() rv = mAuthChannel->GetLoadFlags(&loadFlags); if (NS_FAILED(rv)) return rv; - if (loadFlags & nsIRequest::LOAD_ANONYMOUS) { - return NS_OK; - } - // this getter never fails nsHttpAuthCache *authCache = gHttpHandler->AuthCache(); @@ -214,6 +213,11 @@ nsHttpChannelAuthProvider::AddAuthorizationHeaders() nsnull, // proxy has no path mProxyIdent); + if (loadFlags & nsIRequest::LOAD_ANONYMOUS) { + LOG(("Skipping Authorization header for anonymous load\n")); + return NS_OK; + } + // check if server credentials should be sent nsCAutoString path, scheme; if (NS_SUCCEEDED(GetCurrentPath(path)) && diff --git a/netwerk/protocol/http/nsHttpConnection.cpp b/netwerk/protocol/http/nsHttpConnection.cpp index 51d34110ecd9..d47f0401a678 100644 --- a/netwerk/protocol/http/nsHttpConnection.cpp +++ b/netwerk/protocol/http/nsHttpConnection.cpp @@ -170,6 +170,93 @@ nsHttpConnection::Init(nsHttpConnectionInfo *info, return NS_OK; } +void +nsHttpConnection::StartSpdy() +{ + LOG(("nsHttpConnection::StartSpdy [this=%p]\n", this)); + + NS_ABORT_IF_FALSE(!mSpdySession, "mSpdySession should be null"); + + mUsingSpdy = true; + mEverUsedSpdy = true; + + // Setting the connection as reused allows some transactions that fail + // with NS_ERROR_NET_RESET to be restarted and SPDY uses that code + // to handle clean rejections (such as those that arrived after + // a server goaway was generated). + mIsReused = true; + + // If mTransaction is a pipeline object it might represent + // several requests. If so, we need to unpack that and + // pack them all into a new spdy session. + + nsTArray<nsRefPtr<nsAHttpTransaction> > list; + nsresult rv = mTransaction->TakeSubTransactions(list); + + if (rv == NS_ERROR_ALREADY_OPENED) { + // Has the interface for TakeSubTransactions() changed? + LOG(("TakeSubTranscations somehow called after " + "nsAHttpTransaction began processing\n")); + NS_ABORT_IF_FALSE(false, + "TakeSubTranscations somehow called after " + "nsAHttpTransaction began processing"); + mTransaction->Close(NS_ERROR_ABORT); + return; + } + + if (NS_FAILED(rv) && rv != NS_ERROR_NOT_IMPLEMENTED) { + // Has the interface for TakeSubTransactions() changed? + LOG(("unexpected rv from nnsAHttpTransaction::TakeSubTransactions()")); + NS_ABORT_IF_FALSE(false, + "unexpected result from " + "nsAHttpTransaction::TakeSubTransactions()"); + mTransaction->Close(NS_ERROR_ABORT); + return; + } + + if (NS_FAILED(rv)) { // includes NS_ERROR_NOT_IMPLEMENTED + NS_ABORT_IF_FALSE(list.IsEmpty(), "sub transaction list not empty"); + + // This is ok - treat mTransaction as a single real request. + // Wrap the old http transaction into the new spdy session + // as the first stream. + mSpdySession = new SpdySession(mTransaction, + mSocketTransport, + mPriority); + LOG(("nsHttpConnection::StartSpdy moves single transaction %p " + "into SpdySession %p\n", mTransaction.get(), mSpdySession.get())); + } + else { + NS_ABORT_IF_FALSE(!list.IsEmpty(), "sub transaction list empty"); + + PRInt32 count = list.Length(); + + LOG(("nsHttpConnection::StartSpdy moving transaction list len=%d " + "into SpdySession %p\n", count, mSpdySession.get())); + + for (PRInt32 index = 0; index < count; ++index) { + if (!mSpdySession) { + mSpdySession = new SpdySession(list[index], + mSocketTransport, + mPriority); + } + else { + // AddStream() cannot fail + if (!mSpdySession->AddStream(list[index], mPriority)) { + NS_ABORT_IF_FALSE(false, "SpdySession::AddStream failed"); + LOG(("SpdySession::AddStream failed\n")); + mTransaction->Close(NS_ERROR_ABORT); + return; + } + } + } + } + + mSupportsPipelining = false; // dont use http/1 pipelines with spdy + mTransaction = mSpdySession; + mIdleTimeout = gHttpHandler->SpdyTimeout(); +} + bool nsHttpConnection::EnsureNPNComplete() { @@ -215,31 +302,15 @@ nsHttpConnection::EnsureNPNComplete() goto npnComplete; return false; } - + if (NS_FAILED(rv)) goto npnComplete; LOG(("nsHttpConnection::EnsureNPNComplete %p negotiated to '%s'", this, negotiatedNPN.get())); - - if (negotiatedNPN.Equals(NS_LITERAL_CSTRING("spdy/2"))) { - mUsingSpdy = true; - mEverUsedSpdy = true; - // Setting the connection as reused allows some transactions that fail - // with NS_ERROR_NET_RESET to be restarted and SPDY uses that code - // to handle clean rejections (such as those that arrived after - // a server goaway was generated). - mIsReused = true; - - // Wrap the old http transaction into the new spdy session - // as the first stream - mSpdySession = new SpdySession(mTransaction, - mSocketTransport, - mPriority); - mTransaction = mSpdySession; - mIdleTimeout = gHttpHandler->SpdyTimeout(); - } + if (negotiatedNPN.Equals(NS_LITERAL_CSTRING("spdy/2"))) + StartSpdy(); mozilla::Telemetry::Accumulate(mozilla::Telemetry::SPDY_NPN_CONNECT, mUsingSpdy); diff --git a/netwerk/protocol/http/nsHttpConnection.h b/netwerk/protocol/http/nsHttpConnection.h index 9bc69d47e14e..38ea00247509 100644 --- a/netwerk/protocol/http/nsHttpConnection.h +++ b/netwerk/protocol/http/nsHttpConnection.h @@ -180,6 +180,9 @@ private: // redirections void HandleAlternateProtocol(nsHttpResponseHead *); + // Start the Spdy transaction handler when NPN indicates spdy/2 + void StartSpdy(); + // Directly Add a transaction to an active connection for SPDY nsresult AddTransaction(nsAHttpTransaction *, PRInt32); diff --git a/netwerk/protocol/http/nsHttpPipeline.cpp b/netwerk/protocol/http/nsHttpPipeline.cpp index f58f4a8026a0..6eb1908bfeee 100644 --- a/netwerk/protocol/http/nsHttpPipeline.cpp +++ b/netwerk/protocol/http/nsHttpPipeline.cpp @@ -364,6 +364,33 @@ nsHttpPipeline::Http1xTransactionCount() return mHttp1xTransactionCount; } +nsresult +nsHttpPipeline::TakeSubTransactions( + nsTArray<nsRefPtr<nsAHttpTransaction> > &outTransactions) +{ + LOG(("nsHttpPipeline::TakeSubTransactions [this=%p]\n", this)); + + if (mResponseQ.Length() || mRequestIsPartial) + return NS_ERROR_ALREADY_OPENED; + + // request queue could be empty if it was already canceled, in which + // case it is safe to treat this as a case without any + // sub-transactions. + if (!mRequestQ.Length()) + return NS_ERROR_NOT_IMPLEMENTED; + + PRInt32 i, count = mRequestQ.Length(); + for (i = 0; i < count; ++i) { + nsAHttpTransaction *trans = Request(i); + outTransactions.AppendElement(trans); + NS_RELEASE(trans); + } + mRequestQ.Clear(); + + LOG((" took %d\n", count)); + return NS_OK; +} + //----------------------------------------------------------------------------- // nsHttpPipeline::nsAHttpConnection //----------------------------------------------------------------------------- diff --git a/netwerk/protocol/http/nsHttpTransaction.cpp b/netwerk/protocol/http/nsHttpTransaction.cpp index d32c35ff2eb7..4571429d0b54 100644 --- a/netwerk/protocol/http/nsHttpTransaction.cpp +++ b/netwerk/protocol/http/nsHttpTransaction.cpp @@ -341,6 +341,13 @@ nsHttpTransaction::Http1xTransactionCount() return 1; } +nsresult +nsHttpTransaction::TakeSubTransactions( + nsTArray<nsRefPtr<nsAHttpTransaction> > &outTransactions) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + //---------------------------------------------------------------------------- // nsHttpTransaction::nsAHttpTransaction //---------------------------------------------------------------------------- diff --git a/testing/testsuite-targets.mk b/testing/testsuite-targets.mk index 8345d1a154d7..1bc40e6ed628 100644 --- a/testing/testsuite-targets.mk +++ b/testing/testsuite-targets.mk @@ -97,20 +97,24 @@ endif mochitest-remote: DM_TRANS?=adb mochitest-remote: - @if test -f ${MOZ_HOST_BIN}/xpcshell && [ "${TEST_DEVICE}" != "usb" -o "$(DM_TRANS)" = "adb" ]; \ - then $(RUN_MOCHITEST_REMOTE); \ - else \ - echo "please prepare your host with environment variables for TEST_DEVICE and MOZ_HOST_BIN"; \ - fi + @if [ ! -f ${MOZ_HOST_BIN}/xpcshell ]; then \ + echo "please prepare your host with the environment variable MOZ_HOST_BIN"; \ + elif [ "${TEST_DEVICE}" = "" -a "$(DM_TRANS)" != "adb" ]; then \ + echo "please prepare your host with the environment variable TEST_DEVICE"; \ + else \ + $(RUN_MOCHITEST_REMOTE); \ + fi mochitest-robotium: robotium-id-map mochitest-robotium: DM_TRANS?=adb mochitest-robotium: - @if test -f ${MOZ_HOST_BIN}/xpcshell && [ "${TEST_DEVICE}" != "usb" -o "$(DM_TRANS)" = "adb" ]; \ - then $(RUN_MOCHITEST_ROBOTIUM); \ - else \ - echo "please prepare your host with environment variables for TEST_DEVICE and MOZ_HOST_BIN"; \ - fi + @if [ ! -f ${MOZ_HOST_BIN}/xpcshell ]; then \ + echo "please prepare your host with the environment variable MOZ_HOST_BIN"; \ + elif [ "${TEST_DEVICE}" = "" -a "$(DM_TRANS)" != "adb" ]; then \ + echo "please prepare your host with the environment variable TEST_DEVICE"; \ + else \ + $(RUN_MOCHITEST_ROBOTIUM); \ + fi mochitest-plain: $(RUN_MOCHITEST) @@ -172,11 +176,15 @@ reftest: reftest-remote: TEST_PATH?=layout/reftests/reftest.list reftest-remote: DM_TRANS?=adb reftest-remote: - @if test -f ${MOZ_HOST_BIN}/xpcshell && [ "${TEST_DEVICE}" != "" -o "$(DM_TRANS)" = "adb" ]; \ - then ln -s $(abspath $(topsrcdir)) _tests/reftest/tests;$(call REMOTE_REFTEST,tests/$(TEST_PATH)); $(CHECK_TEST_ERROR); \ - else \ - echo "please prepare your host with environment variables for TEST_DEVICE and MOZ_HOST_BIN"; \ - fi + @if [ ! -f ${MOZ_HOST_BIN}/xpcshell ]; then \ + echo "please prepare your host with the environment variable MOZ_HOST_BIN"; \ + elif [ "${TEST_DEVICE}" = "" -a "$(DM_TRANS)" != "adb" ]; then \ + echo "please prepare your host with the environment variable TEST_DEVICE"; \ + else \ + ln -s $(abspath $(topsrcdir)) _tests/reftest/tests; \ + $(call REMOTE_REFTEST,tests/$(TEST_PATH)); \ + $(CHECK_TEST_ERROR); \ + fi reftest-ipc: TEST_PATH?=layout/reftests/reftest.list reftest-ipc: diff --git a/toolkit/components/passwordmgr/test/Makefile.in b/toolkit/components/passwordmgr/test/Makefile.in index f8fe444e87e6..dd36ea71d500 100644 --- a/toolkit/components/passwordmgr/test/Makefile.in +++ b/toolkit/components/passwordmgr/test/Makefile.in @@ -76,6 +76,7 @@ MOCHI_TESTS = \ test_bug_391514.html \ test_bug_427033.html \ test_bug_444968.html \ + test_bug_627616.html \ test_master_password.html \ test_master_password_cleanup.html \ test_prompt_async.html \ diff --git a/toolkit/components/passwordmgr/test/authenticate.sjs b/toolkit/components/passwordmgr/test/authenticate.sjs index 7c2102fd0dbb..58da655cf98f 100644 --- a/toolkit/components/passwordmgr/test/authenticate.sjs +++ b/toolkit/components/passwordmgr/test/authenticate.sjs @@ -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); diff --git a/toolkit/components/passwordmgr/test/prompt_common.js b/toolkit/components/passwordmgr/test/prompt_common.js index c93d3b131f3f..a25ffd17cd16 100644 --- a/toolkit/components/passwordmgr/test/prompt_common.js +++ b/toolkit/components/passwordmgr/test/prompt_common.js @@ -1,8 +1,8 @@ netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect'); -const Ci = Components.interfaces; +var Ci = Components.interfaces; ok(Ci != null, "Access Ci"); -const Cc = Components.classes; +var Cc = Components.classes; ok(Cc != null, "Access Cc"); var didDialog; diff --git a/toolkit/components/passwordmgr/test/test_bug_627616.html b/toolkit/components/passwordmgr/test/test_bug_627616.html new file mode 100644 index 000000000000..e4f5f0892f5b --- /dev/null +++ b/toolkit/components/passwordmgr/test/test_bug_627616.html @@ -0,0 +1,106 @@ +<!DOCTYPE HTML> +<html> +<head> + <title>Test bug 627616</title> + <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> + <script type="text/javascript" src="prompt_common.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> +<body> +<script class="testbody" type="text/javascript"> + SimpleTest.waitForExplicitFinish(); + + var Cc = SpecialPowers.wrap(Components).classes; + + testNum = 1; + + var login, login2; + function init() { + var ios = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService); + var pps = Cc["@mozilla.org/network/protocol-proxy-service;1"].getService(); + + var uri = ios.newURI("http://example.com", null, null); + var pi = pps.resolve(uri, 0); + var mozproxy = "moz-proxy://" + pi.host + ":" + pi.port; + + var pwmgr = Cc["@mozilla.org/login-manager;1"].getService(Ci.nsILoginManager); + login = Cc["@mozilla.org/login-manager/loginInfo;1"].createInstance(Ci.nsILoginInfo); + login.init(mozproxy, null, "proxy_realm", "proxy_user", "proxy_pass", "", ""); + pwmgr.addLogin(login); + + login2 = Cc["@mozilla.org/login-manager/loginInfo;1"].createInstance(Ci.nsILoginInfo); + login2.init("http://mochi.test:8888", null, "mochirealm", "user1name", "user1pass", "", ""); + pwmgr.addLogin(login2); + } + function cleanup() { + var pwmgr = Cc["@mozilla.org/login-manager;1"].getService(Ci.nsILoginManager); + pwmgr.removeLogin(login); + pwmgr.removeLogin(login2); + } + + function makeXHR(expectedStatus, expectedText, extra) { + var xhr = new XMLHttpRequest(); + xhr.open("GET", "authenticate.sjs?" + + "proxy_user=proxy_user&" + + "proxy_pass=proxy_pass&" + + "proxy_realm=proxy_realm&" + + "user=user1name&" + + "pass=user1pass&" + + "realm=mochirealm&" + + extra || ""); + xhr.onloadend = function() { + is(xhr.status, expectedStatus); + is(xhr.statusText, expectedText); + runNextTest(); + } + return xhr; + } + + function testNonAnonymousCredentials() { + var xhr = makeXHR(200, "OK"); + xhr.send(); + startCallbackTimer(); + } + + function testAnonymousCredentials() { + // Test that an anonymous request correctly performs proxy authentication + var xhr = makeXHR(401, "Authentication required"); + SpecialPowers.wrap(xhr).channel.loadFlags |= Ci.nsIChannel.LOAD_ANONYMOUS; + xhr.send(); + } + + function testAnonymousNoAuth() { + // Next, test that an anonymous request still does not include any non-proxy + // authentication headers. + var xhr = makeXHR(200, "Authorization header not found", "anonymous=1"); + SpecialPowers.wrap(xhr).channel.loadFlags |= Ci.nsIChannel.LOAD_ANONYMOUS; + xhr.send(); + } + + var gCurrentTest; + function runNextTest() { + if (pendingTests.length > 0) { + gCurrentTest = pendingTests.shift(); + gCurrentTest.call(this); + } else { + cleanup(); + SimpleTest.finish(); + } + } + + var pendingTests = [testNonAnonymousCredentials, testAnonymousCredentials, + testAnonymousNoAuth]; + init(); + runNextTest(); + + function handleDialog(doc, testNum) + { + var dialog = doc.getElementById("commonDialog"); + dialog.acceptDialog(); + if (gCurrentTest == testNonAnonymousCredentials) { + startCallbackTimer(); + } + } +</script> +</body> +</html> diff --git a/toolkit/components/places/tests/expiration/test_annos_expire_session.js b/toolkit/components/places/tests/expiration/test_annos_expire_session.js index 17f2763eb449..5a1e7aeb6de2 100644 --- a/toolkit/components/places/tests/expiration/test_annos_expire_session.js +++ b/toolkit/components/places/tests/expiration/test_annos_expire_session.js @@ -86,17 +86,28 @@ function run_test() { items = as.getItemsWithAnnotation("test2"); do_check_eq(items.length, 10); - waitForAsyncUpdates(function() { - let stmt = DBConn().createStatement( - "SELECT id FROM moz_annos " - + "UNION " - + "SELECT id FROM moz_items_annos " - ); - do_check_false(stmt.executeStep()); - stmt.finalize(); - - do_test_finished(); - }); - shutdownPlaces(); + + let stmt = DBConn(true).createAsyncStatement( + "SELECT id FROM moz_annos " + + "UNION " + + "SELECT id FROM moz_items_annos " + ); + stmt.executeAsync({ + handleResult: function(aResultSet) + { + do_throw("Should not find any leftover session annotations"); + }, + handleError: function(aError) + { + do_throw("Error code " + aError.result + " with message '" + + aError.message + "' returned."); + }, + handleCompletion: function(aReason) + { + do_check_eq(aReason, Ci.mozIStorageStatementCallback.REASON_FINISHED); + do_test_finished(); + } + }); + stmt.finalize(); } diff --git a/toolkit/components/places/tests/head_common.js b/toolkit/components/places/tests/head_common.js index dc585d0b2dcb..5a0af5be5bf2 100644 --- a/toolkit/components/places/tests/head_common.js +++ b/toolkit/components/places/tests/head_common.js @@ -112,25 +112,32 @@ function uri(aSpec) NetUtil.newURI(aSpec); * Gets the database connection. If the Places connection is invalid it will * try to create a new connection. * + * @param [optional] aForceNewConnection + * Forces creation of a new connection to the database. When a + * connection is asyncClosed it cannot anymore schedule async statements, + * though connectionReady will keep returning true (Bug 726990). + * * @return The database connection or null if unable to get one. */ let gDBConn; -function DBConn() { - let db = PlacesUtils.history.QueryInterface(Ci.nsPIPlacesDatabase) - .DBConnection; - if (db.connectionReady) - return db; +function DBConn(aForceNewConnection) { + if (!aForceNewConnection) { + let db = PlacesUtils.history.QueryInterface(Ci.nsPIPlacesDatabase) + .DBConnection; + if (db.connectionReady) + return db; + } // If the Places database connection has been closed, create a new connection. - if (!gDBConn) { + if (!gDBConn || aForceNewConnection) { let file = Services.dirsvc.get('ProfD', Ci.nsIFile); file.append("places.sqlite"); - gDBConn = Services.storage.openDatabase(file); + let dbConn = gDBConn = Services.storage.openDatabase(file); // Be sure to cleanly close this connection. - Services.obs.addObserver(function (aSubject, aTopic, aData) { - Services.obs.removeObserver(arguments.callee, aTopic); - gDBConn.asyncClose(); + Services.obs.addObserver(function DBCloseCallback(aSubject, aTopic, aData) { + Services.obs.removeObserver(DBCloseCallback, aTopic); + dbConn.asyncClose(); }, "profile-before-change", false); } diff --git a/toolkit/components/places/tests/inline/head_autocomplete.js b/toolkit/components/places/tests/inline/head_autocomplete.js index 6846920af8db..d475468a0ae6 100644 --- a/toolkit/components/places/tests/inline/head_autocomplete.js +++ b/toolkit/components/places/tests/inline/head_autocomplete.js @@ -21,9 +21,32 @@ XPCOMUtils.defineLazyServiceGetter(this, "gHistory", "@mozilla.org/browser/history;1", "mozIAsyncHistory"); +function VisitInfo(aTransitionType, aVisitTime) +{ + this.transitionType = + aTransitionType === undefined ? TRANSITION_LINK : aTransitionType; + this.visitDate = aVisitTime || Date.now() * 1000; +} + +function addVisits(aUrls) +{ + let places = []; + aUrls.forEach(function(url) { + places.push({ + uri: url.url, + title: "test for " + url.url, + visits: [ + new VisitInfo(url.transition), + ], + }); + }); + + gHistory.updatePlaces(places); +} + /** * @param aSearches - * Array of AutoCompleteSearch names. + * Array of AutoCompleteSearch names. */ function AutoCompleteInput(aSearches) { this.searches = aSearches; diff --git a/toolkit/components/places/tests/inline/test_autocomplete_functional.js b/toolkit/components/places/tests/inline/test_autocomplete_functional.js new file mode 100644 index 000000000000..6836e3024e98 --- /dev/null +++ b/toolkit/components/places/tests/inline/test_autocomplete_functional.js @@ -0,0 +1,148 @@ +/* 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/. */ + +// Functional tests for inline autocomplete + +add_autocomplete_test([ + "Add urls, check for correct order", + "vis", + "visit2.mozilla.org/", + function () + { + let urls = [{ url: NetUtil.newURI("http://visit1.mozilla.org"), + transition: undefined, + }, + { url: NetUtil.newURI("http://visit2.mozilla.org"), + transition: TRANSITION_TYPED, + }]; + addVisits(urls); + } +]); + +add_autocomplete_test([ + "Add urls, make sure www and http are ignored", + "visit1", + "visit1.mozilla.org/", + function () + { + + let urls = [{ url: NetUtil.newURI("http://www.visit1.mozilla.org"), + transition: undefined, + }, + ]; + addVisits(urls); + } +]); + +add_autocomplete_test([ + "Autocompleting after an existing host completes to the url", + "visit3.mozilla.org/", + "visit3.mozilla.org/", + function () + { + + let urls = [{ url: NetUtil.newURI("http://www.visit3.mozilla.org"), + transition: undefined, + }, + ]; + addVisits(urls); + } +]); + +add_autocomplete_test([ + "Searching for www.me should yield www.me.mozilla.org/", + "www.me", + "www.me.mozilla.org/", + function () + { + + let urls = [{ url: NetUtil.newURI("http://www.me.mozilla.org"), + transition: undefined, + }, + ]; + addVisits(urls); + } +]); + +add_autocomplete_test([ + "With a bookmark and history, the query result should be the bookmark", + "bookmark", + "bookmark1.mozilla.org/", + function () + { + + let urls = [{ url: NetUtil.newURI("http://bookmark1.mozilla.org/foo"), + transition: undefined, + }, + ]; + addBookmark({ url: "http://bookmark1.mozilla.org/", }); + addVisits(urls); + } +]); + +add_autocomplete_test([ + "Check to make sure we get the proper results with full paths", + "smokey", + "smokey.mozilla.org/", + function () + { + + let urls = [{ url: NetUtil.newURI("http://smokey.mozilla.org/foo/bar/baz?bacon=delicious"), + transition: undefined, + }, + { url: NetUtil.newURI("http://smokey.mozilla.org/foo/bar/baz?bacon=smokey"), + transition: undefined, + }, + ]; + addVisits(urls); + } +]); + +add_autocomplete_test([ + "Check to make sure we autocomplete to the following '/'", + "smokey.mozilla.org/fo", + "smokey.mozilla.org/foo/", + function () + { + + let urls = [{ url: NetUtil.newURI("http://smokey.mozilla.org/foo/bar/baz?bacon=delicious"), + transition: undefined, + }, + { url: NetUtil.newURI("http://smokey.mozilla.org/foo/bar/baz?bacon=smokey"), + transition: undefined, + }, + ]; + addVisits(urls); + } +]); + +add_autocomplete_test([ + "Check to make sure we autocomplete after ?", + "smokey.mozilla.org/foo?", + "smokey.mozilla.org/foo?bacon=delicious", + function () + { + + let urls = [{ url: NetUtil.newURI("http://smokey.mozilla.org/foo?bacon=delicious"), + transition: undefined, + }, + ]; + addVisits(urls); + } +]); + +add_autocomplete_test([ + "Check to make sure we autocomplete after #", + "smokey.mozilla.org/foo?bacon=delicious#bar", + "smokey.mozilla.org/foo?bacon=delicious#bar", + function () + { + + let urls = [{ url: NetUtil.newURI("http://smokey.mozilla.org/foo?bacon=delicious#bar"), + transition: undefined, + }, + ]; + addVisits(urls); + } +]); diff --git a/toolkit/components/places/tests/inline/xpcshell.ini b/toolkit/components/places/tests/inline/xpcshell.ini index 41a0312c6e09..2a4d0089541a 100644 --- a/toolkit/components/places/tests/inline/xpcshell.ini +++ b/toolkit/components/places/tests/inline/xpcshell.ini @@ -2,5 +2,6 @@ head = head_autocomplete.js tail = +[test_autocomplete_functional.js] [test_casing.js] [test_keywords.js] diff --git a/toolkit/content/widgets/videocontrols.css b/toolkit/content/widgets/videocontrols.css index ec38d974b6b0..ab9975701b6e 100644 --- a/toolkit/content/widgets/videocontrols.css +++ b/toolkit/content/widgets/videocontrols.css @@ -27,7 +27,7 @@ } .controlsSpacer[hideCursor] { - cursor: none; + cursor: none; } /* CSS Transitions diff --git a/toolkit/library/Makefile.in b/toolkit/library/Makefile.in index 2b8e9fd85962..8162e70ea212 100644 --- a/toolkit/library/Makefile.in +++ b/toolkit/library/Makefile.in @@ -398,6 +398,9 @@ OS_LIBS += \ -lbinder \ -lsensorservice \ $(NULL) +ifdef MOZ_B2G_BT +OS_LIBS += -lbluedroid +endif endif EXTRA_DEPS += \ diff --git a/toolkit/mozapps/installer/packager.mk b/toolkit/mozapps/installer/packager.mk index 1b3b37fa7a0d..61b5a868297a 100644 --- a/toolkit/mozapps/installer/packager.mk +++ b/toolkit/mozapps/installer/packager.mk @@ -342,7 +342,7 @@ UPLOAD_EXTRA_FILES += robocop.apk UPLOAD_EXTRA_FILES += fennec_ids.txt ROBOCOP_PATH = $(call core_abspath,$(_ABS_DIST)/../build/mobile/robocop) INNER_ROBOCOP_PACKAGE= \ - $(PYTHON) $(topsrcdir)/build/mobile/robocop/parse_ids.py -i $(call core_abspath,$(DEPTH)/mobile/android/base/R.java) -o $(call core_abspath,$(DEPTH)/build/mobile/robocop/fennec_ids.txt) && \ + $(PYTHON) $(abspath $(topsrcdir)/build/mobile/robocop/parse_ids.py) -i $(call core_abspath,$(DEPTH)/mobile/android/base/R.java) -o $(call core_abspath,$(DEPTH)/build/mobile/robocop/fennec_ids.txt) && \ $(NSINSTALL) $(call core_abspath,$(DEPTH)/build/mobile/robocop/fennec_ids.txt) $(_ABS_DIST) && \ $(APKBUILDER) $(_ABS_DIST)/robocop-raw.apk -v $(APKBUILDER_FLAGS) -z $(ROBOCOP_PATH)/robocop.ap_ -f $(ROBOCOP_PATH)/classes.dex && \ $(JARSIGNER) $(_ABS_DIST)/robocop-raw.apk && \ diff --git a/toolkit/mozapps/update/common/updatelogging.cpp b/toolkit/mozapps/update/common/updatelogging.cpp index 051a0840a86e..285e6730dd70 100644 --- a/toolkit/mozapps/update/common/updatelogging.cpp +++ b/toolkit/mozapps/update/common/updatelogging.cpp @@ -51,7 +51,7 @@ UpdateLog::UpdateLog() : logFP(NULL) { } -void UpdateLog::Init(NS_tchar* sourcePath, NS_tchar* fileName) +void UpdateLog::Init(NS_tchar* sourcePath, const NS_tchar* fileName) { if (logFP) return; diff --git a/toolkit/mozapps/update/common/updatelogging.h b/toolkit/mozapps/update/common/updatelogging.h index e53f9e6bc2e7..9d0b4fb999ee 100644 --- a/toolkit/mozapps/update/common/updatelogging.h +++ b/toolkit/mozapps/update/common/updatelogging.h @@ -50,7 +50,7 @@ public: return primaryLog; } - void Init(NS_tchar* sourcePath, NS_tchar* fileName); + void Init(NS_tchar* sourcePath, const NS_tchar* fileName); void Finish(); void Flush(); void Printf(const char *fmt, ... ); diff --git a/toolkit/mozapps/update/updater/updater.cpp b/toolkit/mozapps/update/updater/updater.cpp index 68e6bcd27e6d..50c22537e2a0 100644 --- a/toolkit/mozapps/update/updater/updater.cpp +++ b/toolkit/mozapps/update/updater/updater.cpp @@ -1452,6 +1452,7 @@ WriteStatusApplying() return true; } +#ifdef MOZ_MAINTENANCE_SERVICE /* * Read the update.status file and sets isPendingService to true if * the status is set to pending-service. @@ -1486,7 +1487,9 @@ IsUpdateStatusPending(bool &isPendingService) sizeof(kPendingService) - 1) == 0; return isPending; } +#endif +#ifdef XP_WIN /* * Read the update.status file and sets isSuccess to true if * the status is set to succeeded. @@ -1516,7 +1519,6 @@ IsUpdateStatusSucceeded(bool &isSucceeded) return true; } -#ifdef XP_WIN static void WaitForServiceFinishThread(void *param) { @@ -2555,7 +2557,6 @@ int DoUpdate() ActionList list; NS_tchar *line; bool isFirstAction = true; - bool isComplete = false; while((line = mstrtok(kNL, &rb)) != 0) { // skip comments @@ -2572,7 +2573,6 @@ int DoUpdate() const NS_tchar *type = mstrtok(kQuote, &line); LOG(("UPDATE TYPE " LOG_S "\n", type)); if (NS_tstrcmp(type, NS_T("complete")) == 0) { - isComplete = true; rv = AddPreCompleteActions(&list); if (rv) return rv; diff --git a/widget/android/AndroidJavaWrappers.cpp b/widget/android/AndroidJavaWrappers.cpp index 3fcadd2cf945..2051fe78c09f 100644 --- a/widget/android/AndroidJavaWrappers.cpp +++ b/widget/android/AndroidJavaWrappers.cpp @@ -547,6 +547,14 @@ AndroidGeckoEvent::Init(JNIEnv *jenv, jobject jobj) break; } + case ACTIVITY_STOPPING: + case ACTIVITY_START: + case ACTIVITY_PAUSING: + case ACTIVITY_RESUMING: { + mFlags = jenv->GetIntField(jobj, jFlagsField); + break; + } + default: break; } diff --git a/widget/android/AndroidJavaWrappers.h b/widget/android/AndroidJavaWrappers.h index 751c5be6e031..de02c6a40dbd 100644 --- a/widget/android/AndroidJavaWrappers.h +++ b/widget/android/AndroidJavaWrappers.h @@ -569,6 +569,7 @@ public: VISITED = 21, NETWORK_CHANGED = 22, PROXIMITY_EVENT = 23, + ACTIVITY_RESUMING = 24, dummy_java_enum_list_end }; diff --git a/widget/android/AndroidMediaLayer.cpp b/widget/android/AndroidMediaLayer.cpp index 572dadcc46b0..d5691c3c29f5 100644 --- a/widget/android/AndroidMediaLayer.cpp +++ b/widget/android/AndroidMediaLayer.cpp @@ -45,7 +45,7 @@ namespace mozilla { AndroidMediaLayer::AndroidMediaLayer() - : mInverted(false) { + : mInverted(false), mVisible(true) { } AndroidMediaLayer::~AndroidMediaLayer() { @@ -132,6 +132,8 @@ void AndroidMediaLayer::SetNativeWindowDimensions(void* aWindow, const gfxRect& } void AndroidMediaLayer::UpdatePosition(const gfxRect& aRect, float aZoomLevel) { + if (!mVisible) + return; std::map<void*, SurfaceData*>::iterator it; @@ -152,4 +154,24 @@ void AndroidMediaLayer::UpdatePosition(const gfxRect& aRect, float aZoomLevel) { } } +void AndroidMediaLayer::SetVisible(bool aVisible) { + if (aVisible == mVisible) + return; + + mVisible = aVisible; + if (mVisible) + return; + + // Hide all surfaces + std::map<void*, SurfaceData*>::iterator it; + + if (EnsureContentSurface()) + AndroidBridge::Bridge()->HideSurface(mContentData.surface); + + for (it = mVideoSurfaces.begin(); it != mVideoSurfaces.end(); it++) { + SurfaceData* data = it->second; + AndroidBridge::Bridge()->HideSurface(data->surface); + } +} + } /* mozilla */ diff --git a/widget/android/AndroidMediaLayer.h b/widget/android/AndroidMediaLayer.h index eb402743fc17..a5b01e6e080d 100644 --- a/widget/android/AndroidMediaLayer.h +++ b/widget/android/AndroidMediaLayer.h @@ -41,15 +41,17 @@ #include <map> #include <jni.h> #include "gfxRect.h" +#include "nsISupports.h" namespace mozilla { class AndroidMediaLayer { public: - AndroidMediaLayer(); virtual ~AndroidMediaLayer(); + + NS_INLINE_DECL_REFCOUNTING(AndroidMediaLayer) void* GetNativeWindowForContent(); @@ -68,8 +70,15 @@ public: mInverted = aInverted; } + bool IsVisible() { + return mVisible; + } + + void SetVisible(bool aVisible); + private: bool mInverted; + bool mVisible; class SurfaceData { public: diff --git a/widget/android/nsAppShell.cpp b/widget/android/nsAppShell.cpp index 581c21b9272f..e7e570ef7eab 100644 --- a/widget/android/nsAppShell.cpp +++ b/widget/android/nsAppShell.cpp @@ -370,6 +370,9 @@ nsAppShell::ProcessNextNativeEvent(bool mayWait) } case AndroidGeckoEvent::ACTIVITY_STOPPING: { + if (curEvent->Flags() > 0) + break; + nsCOMPtr<nsIObserverService> obsServ = mozilla::services::GetObserverService(); NS_NAMED_LITERAL_STRING(minimize, "heap-minimize"); @@ -395,6 +398,14 @@ nsAppShell::ProcessNextNativeEvent(bool mayWait) } case AndroidGeckoEvent::ACTIVITY_PAUSING: { + if (curEvent->Flags() == 0) { + // We aren't transferring to one of our own activities, so set + // background status + nsCOMPtr<nsIObserverService> obsServ = + mozilla::services::GetObserverService(); + obsServ->NotifyObservers(nsnull, "application-background", nsnull); + } + // We really want to send a notification like profile-before-change, // but profile-before-change ends up shutting some things down instead // of flushing data @@ -413,6 +424,9 @@ nsAppShell::ProcessNextNativeEvent(bool mayWait) } case AndroidGeckoEvent::ACTIVITY_START: { + if (curEvent->Flags() > 0) + break; + nsCOMPtr<nsIObserverService> obsServ = mozilla::services::GetObserverService(); obsServ->NotifyObservers(nsnull, "application-foreground", nsnull); @@ -483,6 +497,17 @@ nsAppShell::ProcessNextNativeEvent(bool mayWait) break; } + case AndroidGeckoEvent::ACTIVITY_RESUMING: { + if (curEvent->Flags() == 0) { + // We didn't return from one of our own activities, so restore + // to foreground status + nsCOMPtr<nsIObserverService> obsServ = + mozilla::services::GetObserverService(); + obsServ->NotifyObservers(nsnull, "application-foreground", nsnull); + } + break; + } + default: nsWindow::OnGlobalAndroidEvent(curEvent); } diff --git a/widget/cocoa/nsMenuItemX.h b/widget/cocoa/nsMenuItemX.h index f858c16780cb..0cff11e4e92e 100644 --- a/widget/cocoa/nsMenuItemX.h +++ b/widget/cocoa/nsMenuItemX.h @@ -90,6 +90,8 @@ public: nsresult DispatchDOMEvent(const nsString &eventName, bool* preventDefaultCalled); void SetupIcon(); + static PRUint32 ConvertGeckoToMacKeyCode(nsAString& aKeyCodeName); + protected: void UncheckRadioSiblings(nsIContent* inCheckedElement); void SetKeyEquiv(); diff --git a/widget/cocoa/nsMenuItemX.mm b/widget/cocoa/nsMenuItemX.mm index 0b8e5fc6043d..f1328aeee760 100644 --- a/widget/cocoa/nsMenuItemX.mm +++ b/widget/cocoa/nsMenuItemX.mm @@ -89,6 +89,159 @@ nsMenuItemX::~nsMenuItemX() NS_OBJC_END_TRY_ABORT_BLOCK; } +struct macKeyCodeData { + const char* str; + size_t strlength; + PRUint32 keycode; +}; + +static const macKeyCodeData gMacKeyCodes[] = { + +#define KEYCODE_ENTRY(str, code) {#str, sizeof(#str) - 1, code} + + KEYCODE_ENTRY(VK_CANCEL, 0x001B), + KEYCODE_ENTRY(VK_DELETE, NSBackspaceCharacter), + KEYCODE_ENTRY(VK_BACK, NSBackspaceCharacter), + KEYCODE_ENTRY(VK_BACK_SPACE, NSBackspaceCharacter), + KEYCODE_ENTRY(VK_TAB, NSTabCharacter), + KEYCODE_ENTRY(VK_CLEAR, NSClearLineFunctionKey), + KEYCODE_ENTRY(VK_RETURN, NSEnterCharacter), + KEYCODE_ENTRY(VK_ENTER, NSEnterCharacter), + KEYCODE_ENTRY(VK_SHIFT, 0), + KEYCODE_ENTRY(VK_CONTROL, 0), + KEYCODE_ENTRY(VK_ALT, 0), + KEYCODE_ENTRY(VK_PAUSE, NSPauseFunctionKey), + KEYCODE_ENTRY(VK_CAPS_LOCK, 0), + KEYCODE_ENTRY(VK_ESCAPE, 0), + KEYCODE_ENTRY(VK_SPACE, ' '), + KEYCODE_ENTRY(VK_PAGE_UP, NSPageUpFunctionKey), + KEYCODE_ENTRY(VK_PAGE_DOWN, NSPageDownFunctionKey), + KEYCODE_ENTRY(VK_END, NSEndFunctionKey), + KEYCODE_ENTRY(VK_HOME, NSHomeFunctionKey), + KEYCODE_ENTRY(VK_LEFT, NSLeftArrowFunctionKey), + KEYCODE_ENTRY(VK_UP, NSUpArrowFunctionKey), + KEYCODE_ENTRY(VK_RIGHT, NSRightArrowFunctionKey), + KEYCODE_ENTRY(VK_DOWN, NSDownArrowFunctionKey), + KEYCODE_ENTRY(VK_PRINTSCREEN, NSPrintScreenFunctionKey), + KEYCODE_ENTRY(VK_INSERT, NSInsertFunctionKey), + KEYCODE_ENTRY(VK_HELP, NSHelpFunctionKey), + KEYCODE_ENTRY(VK_0, '0'), + KEYCODE_ENTRY(VK_1, '1'), + KEYCODE_ENTRY(VK_2, '2'), + KEYCODE_ENTRY(VK_3, '3'), + KEYCODE_ENTRY(VK_4, '4'), + KEYCODE_ENTRY(VK_5, '5'), + KEYCODE_ENTRY(VK_6, '6'), + KEYCODE_ENTRY(VK_7, '7'), + KEYCODE_ENTRY(VK_8, '8'), + KEYCODE_ENTRY(VK_9, '9'), + KEYCODE_ENTRY(VK_SEMICOLON, ':'), + KEYCODE_ENTRY(VK_EQUALS, '='), + KEYCODE_ENTRY(VK_A, 'A'), + KEYCODE_ENTRY(VK_B, 'B'), + KEYCODE_ENTRY(VK_C, 'C'), + KEYCODE_ENTRY(VK_D, 'D'), + KEYCODE_ENTRY(VK_E, 'E'), + KEYCODE_ENTRY(VK_F, 'F'), + KEYCODE_ENTRY(VK_G, 'G'), + KEYCODE_ENTRY(VK_H, 'H'), + KEYCODE_ENTRY(VK_I, 'I'), + KEYCODE_ENTRY(VK_J, 'J'), + KEYCODE_ENTRY(VK_K, 'K'), + KEYCODE_ENTRY(VK_L, 'L'), + KEYCODE_ENTRY(VK_M, 'M'), + KEYCODE_ENTRY(VK_N, 'N'), + KEYCODE_ENTRY(VK_O, 'O'), + KEYCODE_ENTRY(VK_P, 'P'), + KEYCODE_ENTRY(VK_Q, 'Q'), + KEYCODE_ENTRY(VK_R, 'R'), + KEYCODE_ENTRY(VK_S, 'S'), + KEYCODE_ENTRY(VK_T, 'T'), + KEYCODE_ENTRY(VK_U, 'U'), + KEYCODE_ENTRY(VK_V, 'V'), + KEYCODE_ENTRY(VK_W, 'W'), + KEYCODE_ENTRY(VK_X, 'X'), + KEYCODE_ENTRY(VK_Y, 'Y'), + KEYCODE_ENTRY(VK_Z, 'Z'), + KEYCODE_ENTRY(VK_CONTEXT_MENU, NSMenuFunctionKey), + KEYCODE_ENTRY(VK_NUMPAD0, '0'), + KEYCODE_ENTRY(VK_NUMPAD1, '1'), + KEYCODE_ENTRY(VK_NUMPAD2, '2'), + KEYCODE_ENTRY(VK_NUMPAD3, '3'), + KEYCODE_ENTRY(VK_NUMPAD4, '4'), + KEYCODE_ENTRY(VK_NUMPAD5, '5'), + KEYCODE_ENTRY(VK_NUMPAD6, '6'), + KEYCODE_ENTRY(VK_NUMPAD7, '7'), + KEYCODE_ENTRY(VK_NUMPAD8, '8'), + KEYCODE_ENTRY(VK_NUMPAD9, '9'), + KEYCODE_ENTRY(VK_MULTIPLY, '*'), + KEYCODE_ENTRY(VK_ADD, '+'), + KEYCODE_ENTRY(VK_SEPARATOR, 0), + KEYCODE_ENTRY(VK_SUBTRACT, '-'), + KEYCODE_ENTRY(VK_DECIMAL, '.'), + KEYCODE_ENTRY(VK_DIVIDE, '/'), + KEYCODE_ENTRY(VK_F1, NSF1FunctionKey), + KEYCODE_ENTRY(VK_F2, NSF2FunctionKey), + KEYCODE_ENTRY(VK_F3, NSF3FunctionKey), + KEYCODE_ENTRY(VK_F4, NSF4FunctionKey), + KEYCODE_ENTRY(VK_F5, NSF5FunctionKey), + KEYCODE_ENTRY(VK_F6, NSF6FunctionKey), + KEYCODE_ENTRY(VK_F7, NSF7FunctionKey), + KEYCODE_ENTRY(VK_F8, NSF8FunctionKey), + KEYCODE_ENTRY(VK_F9, NSF9FunctionKey), + KEYCODE_ENTRY(VK_F10, NSF10FunctionKey), + KEYCODE_ENTRY(VK_F11, NSF11FunctionKey), + KEYCODE_ENTRY(VK_F12, NSF12FunctionKey), + KEYCODE_ENTRY(VK_F13, NSF13FunctionKey), + KEYCODE_ENTRY(VK_F14, NSF14FunctionKey), + KEYCODE_ENTRY(VK_F15, NSF15FunctionKey), + KEYCODE_ENTRY(VK_F16, NSF16FunctionKey), + KEYCODE_ENTRY(VK_F17, NSF17FunctionKey), + KEYCODE_ENTRY(VK_F18, NSF18FunctionKey), + KEYCODE_ENTRY(VK_F19, NSF19FunctionKey), + KEYCODE_ENTRY(VK_F20, NSF20FunctionKey), + KEYCODE_ENTRY(VK_F21, NSF21FunctionKey), + KEYCODE_ENTRY(VK_F22, NSF22FunctionKey), + KEYCODE_ENTRY(VK_F23, NSF23FunctionKey), + KEYCODE_ENTRY(VK_F24, NSF24FunctionKey), + KEYCODE_ENTRY(VK_NUM_LOCK, NSClearLineFunctionKey), + KEYCODE_ENTRY(VK_SCROLL_LOCK, NSScrollLockFunctionKey), + KEYCODE_ENTRY(VK_COMMA, ','), + KEYCODE_ENTRY(VK_PERIOD, '.'), + KEYCODE_ENTRY(VK_SLASH, '/'), + KEYCODE_ENTRY(VK_BACK_QUOTE, '`'), + KEYCODE_ENTRY(VK_OPEN_BRACKET, '['), + KEYCODE_ENTRY(VK_BACK_SLASH, '\\'), + KEYCODE_ENTRY(VK_CLOSE_BRACKET, ']'), + KEYCODE_ENTRY(VK_QUOTE, '\'') + +#undef KEYCODE_ENTRY + +}; + +PRUint32 nsMenuItemX::ConvertGeckoToMacKeyCode(nsAString& aKeyCodeName) +{ + if (aKeyCodeName.IsEmpty()) { + return 0; + } + + nsCAutoString keyCodeName; + keyCodeName.AssignWithConversion(aKeyCodeName); + // We want case-insensitive comparison with data stored as uppercase. + ToUpperCase(keyCodeName); + + PRUint32 keyCodeNameLength = keyCodeName.Length(); + const char* keyCodeNameStr = keyCodeName.get(); + for (PRUint16 i = 0; i < (sizeof(gMacKeyCodes) / sizeof(gMacKeyCodes[0])); ++i) { + if (keyCodeNameLength == gMacKeyCodes[i].strlength && + nsCRT::strcmp(gMacKeyCodes[i].str, keyCodeNameStr) == 0) { + return gMacKeyCodes[i].keycode; + } + } + + return 0; +} + nsresult nsMenuItemX::Create(nsMenuX* aParent, const nsString& aLabel, EMenuItemType aItemType, nsMenuGroupOwnerX* aMenuGroupOwner, nsIContent* aNode) { @@ -274,8 +427,20 @@ void nsMenuItemX::SetKeyEquiv() if (!keyValue.IsEmpty() && mContent->GetCurrentDoc()) { nsIContent *keyContent = mContent->GetCurrentDoc()->GetElementById(keyValue); if (keyContent) { - nsAutoString keyChar(NS_LITERAL_STRING(" ")); - keyContent->GetAttr(kNameSpaceID_None, nsGkAtoms::key, keyChar); + nsAutoString keyChar; + bool hasKey = keyContent->GetAttr(kNameSpaceID_None, nsGkAtoms::key, keyChar); + + if (!hasKey || keyChar.IsEmpty()) { + nsAutoString keyCodeName; + keyContent->GetAttr(kNameSpaceID_None, nsGkAtoms::keycode, keyCodeName); + PRUint32 keycode = ConvertGeckoToMacKeyCode(keyCodeName); + if (keycode) { + keyChar.Assign(keycode); + } + else { + keyChar.Assign(NS_LITERAL_STRING(" ")); + } + } nsAutoString modifiersStr; keyContent->GetAttr(kNameSpaceID_None, nsGkAtoms::modifiers, modifiersStr); diff --git a/widget/windows/nsLookAndFeel.cpp b/widget/windows/nsLookAndFeel.cpp index 844411bfaad6..6d437c8d7f1a 100644 --- a/widget/windows/nsLookAndFeel.cpp +++ b/widget/windows/nsLookAndFeel.cpp @@ -46,6 +46,9 @@ #include "nsStyleConsts.h" #include "nsUXThemeData.h" #include "nsUXThemeConstants.h" +#include "WinUtils.h" + +using namespace mozilla::widget; typedef UINT (CALLBACK *SHAppBarMessagePtr)(DWORD, PAPPBARDATA); SHAppBarMessagePtr gSHAppBarMessage = NULL; @@ -199,7 +202,8 @@ nsLookAndFeel::NativeGetColor(ColorID aID, nscolor &aColor) idx = COLOR_HIGHLIGHT; break; case eColorID__moz_menubarhovertext: - if (!nsUXThemeData::sIsVistaOrLater || !nsUXThemeData::isAppThemed()) + if (WinUtils::GetWindowsVersion() < WinUtils::VISTA_VERSION || + !nsUXThemeData::isAppThemed()) { idx = nsUXThemeData::sFlatMenus ? COLOR_HIGHLIGHTTEXT : @@ -208,7 +212,8 @@ nsLookAndFeel::NativeGetColor(ColorID aID, nscolor &aColor) } // Fall through case eColorID__moz_menuhovertext: - if (nsUXThemeData::IsAppThemed() && nsUXThemeData::sIsVistaOrLater) + if (WinUtils::GetWindowsVersion() >= WinUtils::VISTA_VERSION && + nsUXThemeData::IsAppThemed()) { res = ::GetColorFromTheme(eUXMenu, MENU_POPUPITEM, MPI_HOT, TMT_TEXTCOLOR, aColor); @@ -284,7 +289,8 @@ nsLookAndFeel::NativeGetColor(ColorID aID, nscolor &aColor) idx = COLOR_3DFACE; break; case eColorID__moz_win_mediatext: - if (nsUXThemeData::IsAppThemed() && nsUXThemeData::sIsVistaOrLater) { + if (WinUtils::GetWindowsVersion() >= WinUtils::VISTA_VERSION && + nsUXThemeData::IsAppThemed()) { res = ::GetColorFromTheme(eUXMediaToolbar, TP_BUTTON, TS_NORMAL, TMT_TEXTCOLOR, aColor); if (NS_SUCCEEDED(res)) @@ -294,7 +300,8 @@ nsLookAndFeel::NativeGetColor(ColorID aID, nscolor &aColor) idx = COLOR_WINDOWTEXT; break; case eColorID__moz_win_communicationstext: - if (nsUXThemeData::IsAppThemed() && nsUXThemeData::sIsVistaOrLater) + if (WinUtils::GetWindowsVersion() >= WinUtils::VISTA_VERSION && + nsUXThemeData::IsAppThemed()) { res = ::GetColorFromTheme(eUXCommunicationsToolbar, TP_BUTTON, TS_NORMAL, TMT_TEXTCOLOR, aColor); @@ -519,11 +526,5 @@ PRUnichar nsLookAndFeel::GetPasswordCharacterImpl() { #define UNICODE_BLACK_CIRCLE_CHAR 0x25cf - static PRUnichar passwordCharacter = 0; - if (!passwordCharacter) { - passwordCharacter = '*'; - if (nsUXThemeData::sIsXPOrLater) - passwordCharacter = UNICODE_BLACK_CIRCLE_CHAR; - } - return passwordCharacter; + return UNICODE_BLACK_CIRCLE_CHAR; } diff --git a/widget/windows/nsNativeThemeWin.cpp b/widget/windows/nsNativeThemeWin.cpp index 2360bd89e2ab..be3002e90d58 100644 --- a/widget/windows/nsNativeThemeWin.cpp +++ b/widget/windows/nsNativeThemeWin.cpp @@ -412,7 +412,7 @@ static void OffsetBackgroundRect(RECT& rect, CaptionButton button) { HANDLE nsNativeThemeWin::GetTheme(PRUint8 aWidgetType) { - if (!nsUXThemeData::sIsVistaOrLater) { + if (WinUtils::GetWindowsVersion() < WinUtils::VISTA_VERSION) { // On XP or earlier, render dropdowns as textfields; // doing it the right way works fine with the MS themes, // but breaks on a lot of custom themes (presumably because MS @@ -431,8 +431,9 @@ nsNativeThemeWin::GetTheme(PRUint8 aWidgetType) case NS_THEME_TEXTFIELD_MULTILINE: return nsUXThemeData::GetTheme(eUXEdit); case NS_THEME_TOOLTIP: - // BUG #161600: XP/2K3 should force a classic treatment of tooltips - return nsUXThemeData::sIsVistaOrLater ? nsUXThemeData::GetTheme(eUXTooltip) : NULL; + // XP/2K3 should force a classic treatment of tooltips + return WinUtils::GetWindowsVersion() < WinUtils::VISTA_VERSION ? + NULL : nsUXThemeData::GetTheme(eUXTooltip); case NS_THEME_TOOLBOX: return nsUXThemeData::GetTheme(eUXRebar); case NS_THEME_WIN_MEDIA_TOOLBOX: @@ -557,7 +558,7 @@ nsresult nsNativeThemeWin::GetThemePartAndState(nsIFrame* aFrame, PRUint8 aWidgetType, PRInt32& aPart, PRInt32& aState) { - if (!nsUXThemeData::sIsVistaOrLater) { + if (WinUtils::GetWindowsVersion() < WinUtils::VISTA_VERSION) { // See GetTheme if (aWidgetType == NS_THEME_DROPDOWN) aWidgetType = NS_THEME_TEXTFIELD; @@ -634,7 +635,7 @@ nsNativeThemeWin::GetThemePartAndState(nsIFrame* aFrame, PRUint8 aWidgetType, case NS_THEME_TEXTFIELD_MULTILINE: { nsEventStates eventState = GetContentState(aFrame, aWidgetType); - if (nsUXThemeData::sIsVistaOrLater) { + if (WinUtils::GetWindowsVersion() >= WinUtils::VISTA_VERSION) { /* Note: the NOSCROLL type has a rounded corner in each * corner. The more specific HSCROLL, VSCROLL, HVSCROLL types * have side and/or top/bottom edges rendered as straight @@ -701,9 +702,11 @@ nsNativeThemeWin::GetThemePartAndState(nsIFrame* aFrame, PRUint8 aWidgetType, // we have to return aPart = -1. aPart = -1; } else if (IsVerticalProgress(stateFrame)) { - aPart = nsUXThemeData::sIsVistaOrLater ? PP_FILLVERT : PP_CHUNKVERT; + aPart = WinUtils::GetWindowsVersion() >= WinUtils::VISTA_VERSION ? + PP_FILLVERT : PP_CHUNKVERT; } else { - aPart = nsUXThemeData::sIsVistaOrLater ? PP_FILL : PP_CHUNK; + aPart = WinUtils::GetWindowsVersion() >= WinUtils::VISTA_VERSION ? + PP_FILL : PP_CHUNK; } aState = TS_NORMAL; @@ -776,7 +779,8 @@ nsNativeThemeWin::GetThemePartAndState(nsIFrame* aFrame, PRUint8 aWidgetType, aState += TS_ACTIVE; else if (eventState.HasState(NS_EVENT_STATE_HOVER)) aState += TS_HOVER; - else if (nsUXThemeData::sIsVistaOrLater && parentState.HasState(NS_EVENT_STATE_HOVER)) + else if (WinUtils::GetWindowsVersion() >= WinUtils::VISTA_VERSION && + parentState.HasState(NS_EVENT_STATE_HOVER)) aState = (aWidgetType - NS_THEME_SCROLLBAR_BUTTON_UP) + SP_BUTTON_IMPLICIT_HOVER_BASE; else aState += TS_NORMAL; @@ -864,7 +868,7 @@ nsNativeThemeWin::GetThemePartAndState(nsIFrame* aFrame, PRUint8 aWidgetType, case NS_THEME_SCROLLBAR: case NS_THEME_SCROLLBAR_SMALL: { aState = 0; - if (nsUXThemeData::sIsVistaOrLater) { + if (WinUtils::GetWindowsVersion() >= WinUtils::VISTA_VERSION) { // On vista, they have a part aPart = RP_BACKGROUND; } else { @@ -996,7 +1000,8 @@ nsNativeThemeWin::GetThemePartAndState(nsIFrame* aFrame, PRUint8 aWidgetType, aFrame = parentFrame; nsEventStates eventState = GetContentState(aFrame, aWidgetType); - aPart = nsUXThemeData::sIsVistaOrLater ? CBP_DROPMARKER_VISTA : CBP_DROPMARKER; + aPart = WinUtils::GetWindowsVersion() >= WinUtils::VISTA_VERSION ? + CBP_DROPMARKER_VISTA : CBP_DROPMARKER; // For HTML controls with author styling, we should fall // back to the old dropmarker style to avoid clashes with @@ -1016,7 +1021,7 @@ nsNativeThemeWin::GetThemePartAndState(nsIFrame* aFrame, PRUint8 aWidgetType, else isOpen = IsOpenButton(aFrame); - if (nsUXThemeData::sIsVistaOrLater) { + if (WinUtils::GetWindowsVersion() >= WinUtils::VISTA_VERSION) { if (isHTML || IsMenuListEditable(aFrame)) { if (isOpen) { /* Hover is propagated, but we need to know whether we're @@ -1487,7 +1492,8 @@ RENDER_AGAIN: // On vista, choose our own colors and draw an XP style half focus rect // for focused checkboxes and a full rect when active. - if (nsUXThemeData::sIsVistaOrLater && aWidgetType == NS_THEME_CHECKBOX) { + if (WinUtils::GetWindowsVersion() >= WinUtils::VISTA_VERSION && + aWidgetType == NS_THEME_CHECKBOX) { LOGBRUSH lb; lb.lbStyle = BS_SOLID; lb.lbColor = RGB(255,255,255); @@ -1596,7 +1602,8 @@ RENDER_AGAIN: bool indeterminate = IsIndeterminateProgress(stateFrame, eventStates); bool vertical = IsVerticalProgress(stateFrame); - if (indeterminate || nsUXThemeData::sIsVistaOrLater) { + if (indeterminate || + WinUtils::GetWindowsVersion() >= WinUtils::VISTA_VERSION) { if (!QueueAnimatedContentForRefresh(aFrame->GetContent(), 30)) { NS_WARNING("unable to animate progress widget!"); } @@ -1608,7 +1615,7 @@ RENDER_AGAIN: * indeterminate progress bars. */ PRInt32 overlaySize; - if (nsUXThemeData::sIsVistaOrLater) { + if (WinUtils::GetWindowsVersion() >= WinUtils::VISTA_VERSION) { if (vertical) { overlaySize = indeterminate ? kProgressVerticalIndeterminateOverlaySize : kProgressVerticalOverlaySize; @@ -1652,13 +1659,14 @@ RENDER_AGAIN: PRInt32 overlayPart; if (vertical) { - if (nsUXThemeData::sIsVistaOrLater) { + if (WinUtils::GetWindowsVersion() >= WinUtils::VISTA_VERSION) { overlayPart = indeterminate ? PP_MOVEOVERLAY : PP_MOVEOVERLAYVERT; } else { overlayPart = PP_CHUNKVERT; } } else { - overlayPart = nsUXThemeData::sIsVistaOrLater ? PP_MOVEOVERLAY : PP_CHUNK; + overlayPart = WinUtils::GetWindowsVersion() >= WinUtils::VISTA_VERSION ? + PP_MOVEOVERLAY : PP_CHUNK; } nsUXThemeData::drawThemeBG(theme, hdc, overlayPart, state, &overlayRect, @@ -1823,7 +1831,7 @@ nsNativeThemeWin::GetWidgetPadding(nsDeviceContext* aContext, return true; } - if (nsUXThemeData::sIsVistaOrLater) { + if (WinUtils::GetWindowsVersion() >= WinUtils::VISTA_VERSION) { if (aWidgetType == NS_THEME_TEXTFIELD || aWidgetType == NS_THEME_TEXTFIELD_MULTILINE || aWidgetType == NS_THEME_DROPDOWN) @@ -1916,7 +1924,7 @@ nsNativeThemeWin::GetWidgetOverflow(nsDeviceContext* aContext, * a border only shows up if the widget is being hovered. */ #if 0 - if (nsUXThemeData::sIsVistaOrLater) { + if (WinUtils::GetWindowsVersion() >= WinUtils::VISTA_VERSION) { /* We explicitly draw dropdown buttons in HTML content 1px bigger * up, right, and bottom so that they overlap the dropdown's border * like they're supposed to. @@ -2042,7 +2050,7 @@ nsNativeThemeWin::GetMinimumWidgetSize(nsRenderingContext* aContext, nsIFrame* a *aIsOverridable = false; // on Vista, GetThemePartAndState returns odd values for // scale thumbs, so use a hardcoded size instead. - if (nsUXThemeData::sIsVistaOrLater) { + if (WinUtils::GetWindowsVersion() >= WinUtils::VISTA_VERSION) { if (aWidgetType == NS_THEME_SCALE_THUMB_HORIZONTAL) { aResult->width = 12; aResult->height = 20; @@ -2217,7 +2225,7 @@ nsNativeThemeWin::WidgetStateChanged(nsIFrame* aFrame, PRUint8 aWidgetType, } // On Vista, the scrollbar buttons need to change state when the track has/doesn't have hover - if (!nsUXThemeData::sIsVistaOrLater && + if (WinUtils::GetWindowsVersion() < WinUtils::VISTA_VERSION && (aWidgetType == NS_THEME_SCROLLBAR_TRACK_VERTICAL || aWidgetType == NS_THEME_SCROLLBAR_TRACK_HORIZONTAL)) { *aShouldRepaint = false; @@ -2226,7 +2234,7 @@ nsNativeThemeWin::WidgetStateChanged(nsIFrame* aFrame, PRUint8 aWidgetType, // We need to repaint the dropdown arrow in vista HTML combobox controls when // the control is closed to get rid of the hover effect. - if (nsUXThemeData::sIsVistaOrLater && + if (WinUtils::GetWindowsVersion() >= WinUtils::VISTA_VERSION && (aWidgetType == NS_THEME_DROPDOWN || aWidgetType == NS_THEME_DROPDOWN_BUTTON) && IsHTMLContent(aFrame)) { diff --git a/widget/windows/nsUXThemeData.cpp b/widget/windows/nsUXThemeData.cpp index f526a507a133..b4ea9d7761a7 100644 --- a/widget/windows/nsUXThemeData.cpp +++ b/widget/windows/nsUXThemeData.cpp @@ -69,10 +69,6 @@ nsUXThemeData::sDwmDLL = NULL; BOOL nsUXThemeData::sFlatMenus = FALSE; -bool -nsUXThemeData::sIsXPOrLater = false; -bool -nsUXThemeData::sIsVistaOrLater = false; bool nsUXThemeData::sTitlebarInfoPopulatedAero = false; bool nsUXThemeData::sTitlebarInfoPopulatedThemed = false; @@ -121,10 +117,6 @@ nsUXThemeData::Initialize() ::ZeroMemory(sThemes, sizeof(sThemes)); NS_ASSERTION(!sThemeDLL, "nsUXThemeData being initialized twice!"); - WinUtils::WinVersion version = WinUtils::GetWindowsVersion(); - sIsXPOrLater = version >= WinUtils::WINXP_VERSION; - sIsVistaOrLater = version >= WinUtils::VISTA_VERSION; - if (GetThemeDLL()) { openTheme = (OpenThemeDataPtr)GetProcAddress(sThemeDLL, "OpenThemeData"); closeTheme = (CloseThemeDataPtr)GetProcAddress(sThemeDLL, "CloseThemeData"); @@ -166,17 +158,9 @@ nsUXThemeData::Invalidate() { sThemes[i] = NULL; } } - if (sIsXPOrLater) { - BOOL useFlat = false; - sFlatMenus = ::SystemParametersInfo(SPI_GETFLATMENU, 0, &useFlat, 0) ? - useFlat : false; - } else { - // Contrary to Microsoft's documentation, SPI_GETFLATMENU will not fail - // on Windows 2000, and it is also possible (though unlikely) for WIN2K - // to be misconfigured in such a way that it would return true, so we - // shall give WIN2K special treatment - sFlatMenus = false; - } + BOOL useFlat = false; + sFlatMenus = ::SystemParametersInfo(SPI_GETFLATMENU, 0, &useFlat, 0) ? + useFlat : false; } HANDLE @@ -193,7 +177,7 @@ nsUXThemeData::GetTheme(nsUXThemeClass cls) { HMODULE nsUXThemeData::GetThemeDLL() { - if (!sThemeDLL && sIsXPOrLater) + if (!sThemeDLL) sThemeDLL = ::LoadLibraryW(kThemeLibraryName); return sThemeDLL; } @@ -201,7 +185,7 @@ nsUXThemeData::GetThemeDLL() { #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN HMODULE nsUXThemeData::GetDwmDLL() { - if (!sDwmDLL && sIsVistaOrLater) + if (!sDwmDLL && WinUtils::GetWindowsVersion() >= WinUtils::VISTA_VERSION) sDwmDLL = ::LoadLibraryW(kDwmLibraryName); return sDwmDLL; } diff --git a/widget/windows/nsUXThemeData.h b/widget/windows/nsUXThemeData.h index 9e9369852e1b..1e6026dd8126 100644 --- a/widget/windows/nsUXThemeData.h +++ b/widget/windows/nsUXThemeData.h @@ -128,8 +128,6 @@ public: static const PRUnichar kDwmLibraryName[]; #endif static BOOL sFlatMenus; - static bool sIsXPOrLater; - static bool sIsVistaOrLater; static bool sTitlebarInfoPopulatedAero; static bool sTitlebarInfoPopulatedThemed; static SIZE sCommandButtons[4]; diff --git a/widget/windows/nsWindow.cpp b/widget/windows/nsWindow.cpp index 9c677d7dbd16..98fcd712d883 100644 --- a/widget/windows/nsWindow.cpp +++ b/widget/windows/nsWindow.cpp @@ -1273,7 +1273,8 @@ NS_METHOD nsWindow::IsVisible(bool & bState) // transparency. These routines are called on size and move operations. void nsWindow::ClearThemeRegion() { - if (nsUXThemeData::sIsVistaOrLater && !HasGlass() && + if (WinUtils::GetWindowsVersion() >= WinUtils::VISTA_VERSION && + !HasGlass() && (mWindowType == eWindowType_popup && !IsPopupWithTitleBar() && (mPopupType == ePopupTypeTooltip || mPopupType == ePopupTypePanel))) { SetWindowRgn(mWnd, NULL, false); @@ -1287,7 +1288,8 @@ void nsWindow::SetThemeRegion() // so default constants are used for part and state. At some point we might need part and // state values from nsNativeThemeWin's GetThemePartAndState, but currently windows that // change shape based on state haven't come up. - if (nsUXThemeData::sIsVistaOrLater && !HasGlass() && + if (WinUtils::GetWindowsVersion() >= WinUtils::VISTA_VERSION && + !HasGlass() && (mWindowType == eWindowType_popup && !IsPopupWithTitleBar() && (mPopupType == ePopupTypeTooltip || mPopupType == ePopupTypePanel))) { HRGN hRgn = nsnull; @@ -6357,7 +6359,7 @@ nsWindow::InitMouseWheelScrollData() if (!::SystemParametersInfo(SPI_GETWHEELSCROLLCHARS, 0, &sMouseWheelScrollChars, 0)) { - NS_ASSERTION(!nsUXThemeData::sIsVistaOrLater, + NS_ASSERTION(WinUtils::GetWindowsVersion() < WinUtils::VISTA_VERSION, "Failed to get SPI_GETWHEELSCROLLCHARS"); sMouseWheelScrollChars = 1; } else if (sMouseWheelScrollChars > WHEEL_DELTA) { diff --git a/xpcom/build/Makefile.in b/xpcom/build/Makefile.in index d7f00ba2ad87..dc3ee3d10cae 100644 --- a/xpcom/build/Makefile.in +++ b/xpcom/build/Makefile.in @@ -79,7 +79,6 @@ SHARED_LIBRARY_LIBS = \ ../io/$(LIB_PREFIX)xpcomio_s.$(LIB_SUFFIX) \ ../components/$(LIB_PREFIX)xpcomcomponents_s.$(LIB_SUFFIX) \ ../threads/$(LIB_PREFIX)xpcomthreads_s.$(LIB_SUFFIX) \ - ../proxy/src/$(LIB_PREFIX)xpcomproxy_s.$(LIB_SUFFIX) \ ../base/$(LIB_PREFIX)xpcombase_s.$(LIB_SUFFIX) \ ../reflect/xptcall/src/$(LIB_PREFIX)xptcall.$(LIB_SUFFIX) \ ../reflect/xptcall/src/$(LIB_PREFIX)xptcmd.$(LIB_SUFFIX) \ diff --git a/xpcom/build/nsXPCOMCIDInternal.h b/xpcom/build/nsXPCOMCIDInternal.h index bc2185fdfead..be5d17ff3ba0 100644 --- a/xpcom/build/nsXPCOMCIDInternal.h +++ b/xpcom/build/nsXPCOMCIDInternal.h @@ -71,12 +71,6 @@ */ #define NS_THREADPOOL_CONTRACTID "@mozilla.org/thread-pool;1" -/** - * The global proxy object manager. This component is a singleton. - * @implement nsIProxyObjectManager - */ -#define NS_XPCOMPROXY_CONTRACTID "@mozilla.org/xpcomproxy;1" - /** * The contract id for the nsIXULAppInfo service. */ diff --git a/xpcom/glue/nsCycleCollectionParticipant.h b/xpcom/glue/nsCycleCollectionParticipant.h index 7bcefbebd335..50a55f8da968 100644 --- a/xpcom/glue/nsCycleCollectionParticipant.h +++ b/xpcom/glue/nsCycleCollectionParticipant.h @@ -299,6 +299,10 @@ public: #define NS_CYCLE_COLLECTION_UPCAST(obj, clazz) \ NS_CYCLE_COLLECTION_CLASSNAME(clazz)::Upcast(obj) +/////////////////////////////////////////////////////////////////////////////// +// Helpers for implementing CanSkip methods +/////////////////////////////////////////////////////////////////////////////// + #define NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(_class) \ NS_IMETHODIMP_(bool) \ NS_CYCLE_COLLECTION_CLASSNAME(_class)::CanSkipReal(void *p, \ @@ -310,6 +314,7 @@ public: _class *tmp = Downcast(s); #define NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END \ + (void)tmp; \ return false; \ } @@ -323,6 +328,7 @@ public: _class *tmp = Downcast(s); #define NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_END \ + (void)tmp; \ return false; \ } @@ -336,6 +342,7 @@ public: _class *tmp = Downcast(s); #define NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_END \ + (void)tmp; \ return false; \ } @@ -614,6 +621,24 @@ NS_CYCLE_COLLECTION_PARTICIPANT_INSTANCE #define NS_DECL_CYCLE_COLLECTION_CLASS(_class) \ NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(_class, _class) +// Cycle collector helper for ambiguous classes that can sometimes be skipped. +#define NS_DECL_CYCLE_COLLECTION_SKIPPABLE_CLASS_AMBIGUOUS(_class, _base) \ +class NS_CYCLE_COLLECTION_INNERCLASS \ + : public nsXPCOMCycleCollectionParticipant \ +{ \ +public: \ + NS_CYCLE_COLLECTION_INNERCLASS () : nsXPCOMCycleCollectionParticipant(true) {} \ + NS_DECL_CYCLE_COLLECTION_CLASS_BODY(_class, _base) \ +protected: \ + NS_IMETHOD_(bool) CanSkipReal(void *p, bool aRemovingAllowed); \ + NS_IMETHOD_(bool) CanSkipInCCReal(void *p); \ + NS_IMETHOD_(bool) CanSkipThisReal(void *p); \ +}; \ +NS_CYCLE_COLLECTION_PARTICIPANT_INSTANCE + +#define NS_DECL_CYCLE_COLLECTION_SKIPPABLE_CLASS(_class) \ + NS_DECL_CYCLE_COLLECTION_SKIPPABLE_CLASS_AMBIGUOUS(_class, _class) + // Cycle collector helper for classes that don't want to unlink anything. // Note: if this is used a lot it might make sense to have a base class that // doesn't do anything in Root/Unlink/Unroot. diff --git a/xpcom/typelib/xpt/tools/xpt.py b/xpcom/typelib/xpt/tools/xpt.py index b2034ed2303a..e00a58926587 100644 --- a/xpcom/typelib/xpt/tools/xpt.py +++ b/xpcom/typelib/xpt/tools/xpt.py @@ -172,7 +172,7 @@ class Type(object): if self.reference: flags |= 0x20 return flags - + @staticmethod def read(typelib, map, data_pool, offset): """ @@ -439,7 +439,7 @@ class StringWithSizeType(Type): (size_is_arg_num, length_is_arg_num) = StringWithSizeType._descriptor.unpack(map[start:start + StringWithSizeType._descriptor.size]) offset += StringWithSizeType._descriptor.size return StringWithSizeType(size_is_arg_num, length_is_arg_num, **flags), offset - + def write(self, typelib, file): """ Write a StringWithSizeTypeDescriptor to |file|, which is assumed @@ -449,7 +449,7 @@ class StringWithSizeType(Type): Type.write(self, typelib, file) file.write(StringWithSizeType._descriptor.pack(self.size_is_arg_num, self.length_is_arg_num)) - + def __str__(self): return "string_s" @@ -459,7 +459,7 @@ class WideStringWithSizeType(Type): are passed as separate arguments to a method. (WideStringWithSizeTypeDescriptor from the typelib specification.) - """ + """ _descriptor = struct.Struct(">BB") def __init__(self, size_is_arg_num, length_is_arg_num, @@ -614,7 +614,7 @@ class Param(object): if self.optional: s += "optional " return s - + def __str__(self): return self.prefix() + str(self.type) @@ -626,7 +626,7 @@ class Method(object): """ _descriptorstart = struct.Struct(">BIB") - + def __init__(self, name, result, params=[], getter=False, setter=False, notxpcom=False, constructor=False, hidden=False, optargc=False, @@ -777,7 +777,7 @@ class Constant(object): def __init__(self, name, type, value): self.name = name - self._name_offset = 0 + self._name_offset = 0 self.type = type self.value = value @@ -839,11 +839,11 @@ class Interface(object): (InterfaceDescriptor from the typelib specification.) """ - _direntry = struct.Struct(">16sIII") + _direntry = struct.Struct(">16sIII") _descriptorstart = struct.Struct(">HH") UNRESOLVED_IID = "00000000-0000-0000-0000-000000000000" - + def __init__(self, name, iid=UNRESOLVED_IID, namespace="", resolved=False, parent=None, methods=[], constants=[], scriptable=False, function=False, builtinclass=False): @@ -972,7 +972,7 @@ class Interface(object): if self.builtinclass: flags |= 0x20 file.write(struct.pack(">B", flags)) - + def write_names(self, file, data_pool_offset): """ Write this interface's name and namespace to |file|, @@ -1016,6 +1016,7 @@ class Typelib(object): self.version = version self.interfaces = list(interfaces) self.annotations = list(annotations) + self.filename = None @staticmethod def iid_to_string(iid): @@ -1025,6 +1026,7 @@ class Typelib(object): """ def hexify(s): return ''.join(["%02x" % ord(x) for x in s]) + return "%s-%s-%s-%s-%s" % (hexify(iid[:4]), hexify(iid[4:6]), hexify(iid[6:8]), hexify(iid[8:10]), hexify(iid[10:])) @@ -1037,7 +1039,7 @@ class Typelib(object): """ s = iid_str.replace('-','') return ''.join([chr(int(s[i:i+2], 16)) for i in range(0, len(s), 2)]) - + @staticmethod def read_string(map, data_pool, offset): if offset == 0: @@ -1046,7 +1048,7 @@ class Typelib(object): if sz == -1: return "" return map[data_pool + offset - 1:sz] - + @staticmethod def read(filename): """ @@ -1061,6 +1063,7 @@ class Typelib(object): if data[0] != XPT_MAGIC: raise FileFormatError, "Bad magic: %s" % data[0] xpt = Typelib((data[1], data[2])) + xpt.filename = filename num_interfaces = data[3] file_length = data[4] if file_length != st.st_size: @@ -1096,7 +1099,7 @@ class Typelib(object): for iface in xpt.interfaces: iface.read_descriptor(xpt, map, data_pool_offset) return xpt - + def __repr__(self): return "<Typelib with %d interfaces>" % len(self.interfaces) @@ -1208,20 +1211,25 @@ class Typelib(object): merged = True # Fixup will happen after processing all interfaces. else: - # Same name, different IIDs, raise an exception + # Same name but different IIDs: raise an exception. + # self.* is the (target) Typelib being merged into, + # not the one which j.iid was from. raise DataError, \ "Typelibs contain definitions of interface %s" \ - " with different IIDs (%s vs %s)!" % \ - (i.name, i.iid, j.iid) + " with different IIDs (%s (%s) vs %s (%s))!" % \ + (i.name, i.iid, other.filename, j.iid, self.filename) elif i.iid == j.iid and i.iid != Interface.UNRESOLVED_IID: - # Same IID, different names, raise an exception + # Same IID but different names: raise an exception. + # self.* is the (target) Typelib being merged into, + # not the one which j.name was from. raise DataError, \ "Typelibs contain definitions of interface %s" \ - " with different names (%s vs %s)!" % \ - (i.iid, i.name, j.name) + " with different names (%s (%s) vs %s (%s))!" % \ + (i.iid, i.name, other.filename, j.name, self.filename) if not merged: # No partially matching interfaces, so just take this interface self.interfaces.append(i) + # Now fixup any merged interfaces def checkType(t, replaced_from, replaced_to): if isinstance(t, InterfaceType) and t.iface == replaced_from: @@ -1230,7 +1238,7 @@ class Typelib(object): isinstance(t.element_type, InterfaceType) and \ t.element_type.iface == replaced_from: t.element_type.iface = replaced_to - + for replaced_from, replaced_to in merged_interfaces: for i in self.interfaces: # Replace parent references