author | Carsten "Tomcat" Book <cbook@mozilla.com> |
Fri, 27 Nov 2015 11:08:41 +0100 | |
changeset 274446 | 47b49b0d32360fab04b11ff9120970979c426911 |
parent 274445 | ad985ade8a2e5e58123f0a774605d273834c3ba1 (current diff) |
parent 274413 | 48139ac411625d1ee8b21c51770b917502dba1d9 (diff) |
child 274447 | 2c0df58d9443dec00c684b00b111dfaf96613997 |
child 274594 | 7883e81f3c305078353ca27a6b1adb8c769d5904 |
child 274597 | bf0d6a7b6fa1374e52560dce73111e9de835100d |
child 274628 | bb512bf5a0669afa0d8158daf906a4223f4ba6ce |
push id | 68581 |
push user | cbook@mozilla.com |
push date | Fri, 27 Nov 2015 10:11:11 +0000 |
treeherder | mozilla-inbound@2c0df58d9443 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | merge |
milestone | 45.0a1 |
first release with | nightly linux32
47b49b0d3236
/
45.0a1
/
20151127030231
/
files
nightly linux64
47b49b0d3236
/
45.0a1
/
20151127030231
/
files
nightly mac
47b49b0d3236
/
45.0a1
/
20151127030231
/
files
nightly win32
47b49b0d3236
/
45.0a1
/
20151127030231
/
files
nightly win64
47b49b0d3236
/
45.0a1
/
20151127030231
/
files
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
releases | nightly linux32
45.0a1
/
20151127030231
/
pushlog to previous
nightly linux64
45.0a1
/
20151127030231
/
pushlog to previous
nightly mac
45.0a1
/
20151127030231
/
pushlog to previous
nightly win32
45.0a1
/
20151127030231
/
pushlog to previous
nightly win64
45.0a1
/
20151127030231
/
pushlog to previous
|
--- a/accessible/generic/DocAccessible.cpp +++ b/accessible/generic/DocAccessible.cpp @@ -2156,17 +2156,17 @@ DocAccessible::MoveChild(Accessible* aCh MaybeNotifyOfValueChange(parent); FireDelayedEvent(reorderEvent); } void DocAccessible::PutChildrenBack(nsTArray<RefPtr<Accessible> >* aChildren, uint32_t aStartIdx) { - nsTArray<Accessible*> containers; + nsTArray<RefPtr<Accessible> > containers; for (auto idx = aStartIdx; idx < aChildren->Length(); idx++) { Accessible* child = aChildren->ElementAt(idx); // If the child is in the tree then remove it from the owner. if (child->IsInDocument()) { Accessible* owner = child->Parent(); if (!owner) { NS_ERROR("Cannot put the child back. No parent, a broken tree."); @@ -2193,17 +2193,21 @@ DocAccessible::PutChildrenBack(nsTArray< containers.IndexOf(container) == nsTArray<Accessible*>::NoIndex) { containers.AppendElement(container); } } // And put it back where it belongs to. aChildren->RemoveElementsAt(aStartIdx, aChildren->Length() - aStartIdx); for (uint32_t idx = 0; idx < containers.Length(); idx++) { - UpdateTreeOnInsertion(containers[idx]); + NS_ASSERTION(containers[idx]->IsInDocument(), + "A container has been destroyed."); + if (containers[idx]->IsInDocument()) { + UpdateTreeOnInsertion(containers[idx]); + } } } void DocAccessible::CacheChildrenInSubtree(Accessible* aRoot, Accessible** aFocusedAcc) { // If the accessible is focused then report a focus event after all related
--- a/browser/base/content/browser-gestureSupport.js +++ b/browser/base/content/browser-gestureSupport.js @@ -641,38 +641,43 @@ var gHistorySwipeAnimation = { // from 0. if (this._direction == "horizontal" || this._lastSwipeDir != "") { gBrowser.stop(); this._lastSwipeDir = "RELOAD"; // just ensure that != "" this._canGoBack = this.canGoBack(); this._canGoForward = this.canGoForward(); this._handleFastSwiping(); } + this.updateAnimation(0); } else { - this._startingIndex = gBrowser.webNavigation.sessionHistory.index; - this._historyIndex = this._startingIndex; - this._canGoBack = this.canGoBack(); - this._canGoForward = this.canGoForward(); - if (this.active) { - this._addBoxes(); - this._takeSnapshot(); - this._installPrevAndNextSnapshots(); - this._lastSwipeDir = ""; + // Get the session history from SessionStore. + let updateSessionHistory = sessionHistory => { + this._startingIndex = sessionHistory.index; + this._historyIndex = this._startingIndex; + this._canGoBack = this.canGoBack(); + this._canGoForward = this.canGoForward(); + if (this.active) { + this._addBoxes(); + this._takeSnapshot(); + this._installPrevAndNextSnapshots(); + this._lastSwipeDir = ""; + } + this.updateAnimation(0); } + SessionStore.getSessionHistory(gBrowser.selectedTab, updateSessionHistory); } - this.updateAnimation(0); }, /** * Stops the swipe animation. */ stopAnimation: function HSA_stopAnimation() { gHistorySwipeAnimation._removeBoxes(); - this._historyIndex = gBrowser.webNavigation.sessionHistory.index; + this._historyIndex = this._getCurrentHistoryIndex(); }, /** * Updates the animation between two pages in history. * * @param aVal * A floating point value that represents the progress of the * swipe gesture. @@ -721,16 +726,20 @@ var gHistorySwipeAnimation = { this._positionBox(this._nextBox, offset + aVal); } else { this._prevBox.collapsed = true; this._positionBox(this._curBox, aVal / dampValue); } } }, + _getCurrentHistoryIndex: function() { + return SessionStore.getSessionHistory(gBrowser.selectedTab).index; + }, + /** * Event handler for events relevant to the history swipe animation. * * @param aEvent * An event to process. */ handleEvent: function HSA_handleEvent(aEvent) { let browser = gBrowser.selectedBrowser; @@ -816,32 +825,36 @@ var gHistorySwipeAnimation = { }, /** * Used to notify the history swipe animation that the OS sent a swipe end * event and that we should navigate to the page that the user swiped to, if * any. This will also result in the animation overlay to be torn down. */ swipeEndEventReceived: function HSA_swipeEndEventReceived() { - if (this._lastSwipeDir != "" && this._historyIndex != this._startingIndex) - this._navigateToHistoryIndex(); - else - this.stopAnimation(); + // Update the session history before continuing. + let updateSessionHistory = sessionHistory => { + if (this._lastSwipeDir != "" && this._historyIndex != this._startingIndex) + this._navigateToHistoryIndex(); + else + this.stopAnimation(); + } + SessionStore.getSessionHistory(gBrowser.selectedTab, updateSessionHistory); }, /** * Checks whether a particular index exists in the browser history or not. * * @param aIndex * The index to check for availability for in the history. * @return true if the index exists in the browser history, false otherwise. */ _doesIndexExistInHistory: function HSA__doesIndexExistInHistory(aIndex) { try { - gBrowser.webNavigation.sessionHistory.getEntryAtIndex(aIndex, false); + return SessionStore.getSessionHistory(gBrowser.selectedTab).entries[aIndex] != null; } catch(ex) { return false; } return true; }, /** @@ -954,21 +967,17 @@ var gHistorySwipeAnimation = { /** * Verifies that we're ready to take snapshots based on the global pref and * the current index in history. * * @return true if we're ready to take snapshots, false otherwise. */ _readyToTakeSnapshots: function HSA__readyToTakeSnapshots() { - if ((this._maxSnapshots < 1) || - (gBrowser.webNavigation.sessionHistory.index < 0)) { - return false; - } - return true; + return (this._maxSnapshots >= 1 && this._getCurrentHistoryIndex() >= 0); }, /** * Takes a snapshot of the page the browser is currently on. */ _takeSnapshot: function HSA__takeSnapshot() { if (!this._readyToTakeSnapshots()) { return; @@ -1021,17 +1030,17 @@ var gHistorySwipeAnimation = { * snapshot in the list. * * @param aCanvas * The snapshot to add to the list and compress. */ _assignSnapshotToCurrentBrowser: function HSA__assignSnapshotToCurrentBrowser(aCanvas) { let browser = gBrowser.selectedBrowser; - let currIndex = browser.webNavigation.sessionHistory.index; + let currIndex = this._getCurrentHistoryIndex(); this._removeTrackedSnapshot(currIndex, browser); this._addSnapshotRefToArray(currIndex, browser); if (!("snapshots" in browser)) browser.snapshots = []; let snapshots = browser.snapshots; // Temporarily store the canvas as the compressed snapshot. @@ -1054,17 +1063,17 @@ var gHistorySwipeAnimation = { // there's nothing to compress. return; } TelemetryStopwatch.start("FX_GESTURE_COMPRESS_SNAPSHOT_OF_PAGE"); try { let browser = gBrowser.selectedBrowser; let snapshots = browser.snapshots; - let currIndex = browser.webNavigation.sessionHistory.index; + let currIndex = _getCurrentHistoryIndex(); // Kick off snapshot compression. let canvas = snapshots[currIndex].image; canvas.toBlob(function(aBlob) { if (snapshots[currIndex]) { snapshots[currIndex].image = aBlob; } }, "image/png"
--- a/browser/components/nsBrowserGlue.js +++ b/browser/components/nsBrowserGlue.js @@ -3372,27 +3372,26 @@ var E10SUINotification = { }, }; #else // E10S_TESTING_ONLY var E10SAccessibilityCheck = { init: function() { Services.obs.addObserver(this, "a11y-init-or-shutdown", true); - if (Services.appinfo.accessibilityIsBlacklistedForE10S) { + if (Services.appinfo.accessibilityEnabled) { this._showE10sAccessibilityWarning(); } }, QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver, Ci.nsISupportsWeakReference]), observe: function(subject, topic, data) { if (topic == "a11y-init-or-shutdown" - && data == "1" && - Services.appinfo.accessibilityIsBlacklistedForE10S) { + && data == "1") { this._showE10sAccessibilityWarning(); } }, _warnedAboutAccessibility: false, _showE10sAccessibilityWarning: function() { try {
--- a/configure.in +++ b/configure.in @@ -319,27 +319,26 @@ if test -n "$gonkdir" ; then AC_DEFINE(HAVE_SYS_UIO_H) AC_DEFINE(HAVE_PTHREADS) MOZ_CHROME_FILE_FORMAT=omni direct_nspr_config=1 android_cxx_stl=mozstlport else if test "$COMPILE_ENVIRONMENT"; then MOZ_ANDROID_NDK - else - AC_DEFINE(ANDROID) fi # COMPILE_ENVIRONMENT case "$target" in *-android*|*-linuxandroid*) if test -z "$ANDROID_PACKAGE_NAME" ; then ANDROID_PACKAGE_NAME='org.mozilla.$(MOZ_APP_NAME)' fi MOZ_CHROME_FILE_FORMAT=omni ZLIB_DIR=yes + AC_DEFINE(ANDROID) ;; *-linux*) AC_PATH_PROG(OBJCOPY,objcopy) ;; esac fi case "$target" in @@ -4213,16 +4212,17 @@ cairo-uikit) AC_DEFINE(MOZ_WIDGET_UIKIT) LDFLAGS="$LDFLAGS -framework UIKit -lobjc" TK_CFLAGS="-DNO_X11" TK_LIBS='-Wl,-framework,Foundation -Wl,-framework,CoreFoundation -Wl,-framework,CoreGraphics -Wl,-framework,CoreText -Wl,-framework,AVFoundation -Wl,-framework,AudioToolbox -Wl,-framework,CoreMedia -Wl,-framework,CoreVideo -Wl,-framework,OpenGLES -Wl,-framework,QuartzCore' CFLAGS="$CFLAGS $TK_CFLAGS" CXXFLAGS="$CXXFLAGS $TK_CFLAGS" MOZ_USER_DIR="Mozilla" MOZ_FS_LAYOUT=bundle + AC_DEFINE(MOZ_SINGLE_PROCESS_APZ) ;; cairo-android) AC_DEFINE(MOZ_WIDGET_ANDROID) MOZ_WIDGET_TOOLKIT=android MOZ_PDF_PRINTING=1 MOZ_INSTRUMENT_EVENT_LOOP=1 ;; @@ -4796,18 +4796,21 @@ fi dnl ======================================================== dnl = Enable the C++ async pan/zoom code instead of the Java version dnl ======================================================== MOZ_ARG_ENABLE_BOOL(android-apz, [ --enable-android-apz Switch to C++ pan/zoom code], MOZ_ANDROID_APZ=1, MOZ_ANDROID_APZ=) if test -n "$MOZ_ANDROID_APZ"; then - dnl Do this if defined in confvars.sh - AC_DEFINE(MOZ_ANDROID_APZ) + dnl Do this if defined in confvars.sh + AC_DEFINE(MOZ_ANDROID_APZ) + if test -z "$MOZ_B2GDROID"; then + AC_DEFINE(MOZ_SINGLE_PROCESS_APZ) + fi fi dnl ======================================================== dnl = Disable WebSMS backend dnl ======================================================== MOZ_ARG_DISABLE_BOOL(websms-backend, [ --disable-websms-backend Disable WebSMS backend],
--- a/devtools/client/framework/gDevTools.jsm +++ b/devtools/client/framework/gDevTools.jsm @@ -824,17 +824,17 @@ var gDevToolsBrowser = { gDevToolsBrowser._trackedBrowserWindows.add(win); gDevToolsBrowser._addAllToolsToMenu(win.document); if (this._isFirebugInstalled()) { let broadcaster = win.document.getElementById("devtoolsMenuBroadcaster_DevToolbox"); broadcaster.removeAttribute("key"); } - let tabContainer = win.document.getElementById("tabbrowser-tabs"); + let tabContainer = win.gBrowser.tabContainer; tabContainer.addEventListener("TabSelect", this, false); tabContainer.addEventListener("TabOpen", this, false); tabContainer.addEventListener("TabClose", this, false); tabContainer.addEventListener("TabPinned", this, false); tabContainer.addEventListener("TabUnpinned", this, false); }, /** @@ -1019,30 +1019,27 @@ var gDevToolsBrowser = { ref = doc.getElementById("appmenu_devtools_separator"); } if (ref) { amp.insertBefore(elements.appmenuitem, ref); } } - let mp = doc.getElementById("menuWebDeveloperPopup"); - if (mp) { - let ref; + let ref; - if (prevDef != null) { - let menuitem = doc.getElementById("menuitem_" + prevDef.id); - ref = menuitem && menuitem.nextSibling ? menuitem.nextSibling : null; - } else { - ref = doc.getElementById("menu_devtools_separator"); - } + if (prevDef) { + let menuitem = doc.getElementById("menuitem_" + prevDef.id); + ref = menuitem && menuitem.nextSibling ? menuitem.nextSibling : null; + } else { + ref = doc.getElementById("menu_devtools_separator"); + } - if (ref) { - mp.insertBefore(elements.menuitem, ref); - } + if (ref) { + ref.parentNode.insertBefore(elements.menuitem, ref); } } if (toolDefinition.id === "jsdebugger") { gDevToolsBrowser.setSlowScriptDebugHandler(); } }, @@ -1082,25 +1079,25 @@ var gDevToolsBrowser = { let mcs = doc.getElementById("mainCommandSet"); mcs.appendChild(fragCommands); this.attachKeybindingsToBrowser(doc, fragKeys); let mbs = doc.getElementById("mainBroadcasterSet"); mbs.appendChild(fragBroadcasters); - let amp = doc.getElementById("appmenu_webDeveloper_popup"); - if (amp) { - let amps = doc.getElementById("appmenu_devtools_separator"); - amp.insertBefore(fragAppMenuItems, amps); + let amps = doc.getElementById("appmenu_devtools_separator"); + if (amps) { + amps.parentNode.insertBefore(fragAppMenuItems, amps); } - let mp = doc.getElementById("menuWebDeveloperPopup"); let mps = doc.getElementById("menu_devtools_separator"); - mp.insertBefore(fragMenuItems, mps); + if (mps) { + mps.parentNode.insertBefore(fragMenuItems, mps); + } }, /** * Add a menu entry for a tool definition * * @param {string} toolDefinition * Tool definition of the tool to add a menu entry. * @param {XULDocument} doc @@ -1251,17 +1248,17 @@ var gDevToolsBrowser = { // Destroy toolboxes for closed window for (let [target, toolbox] of gDevTools._toolboxes) { if (toolbox.frame && toolbox.frame.ownerDocument.defaultView == win) { toolbox.destroy(); } } - let tabContainer = win.document.getElementById("tabbrowser-tabs"); + let tabContainer = win.gBrowser.tabContainer; tabContainer.removeEventListener("TabSelect", this, false); tabContainer.removeEventListener("TabOpen", this, false); tabContainer.removeEventListener("TabClose", this, false); tabContainer.removeEventListener("TabPinned", this, false); tabContainer.removeEventListener("TabUnpinned", this, false); }, handleEvent: function(event) { @@ -1270,17 +1267,17 @@ var gDevToolsBrowser = { case "TabClose": case "TabPinned": case "TabUnpinned": let open = 0; let pinned = 0; for (let win of this._trackedBrowserWindows) { let tabContainer = win.gBrowser.tabContainer; - let numPinnedTabs = tabContainer.tabbrowser._numPinnedTabs; + let numPinnedTabs = win.gBrowser._numPinnedTabs || 0; let numTabs = tabContainer.itemCount - numPinnedTabs; open += numTabs; pinned += numPinnedTabs; } this._tabStats.histOpen.push(open); this._tabStats.histPinned.push(pinned);
--- a/devtools/server/actors/webbrowser.js +++ b/devtools/server/actors/webbrowser.js @@ -1084,16 +1084,20 @@ TabActor.prototype = { }, onListFrames: function BTA_onListFrames(aRequest) { let windows = this._docShellsToWindows(this.docShells); return { frames: windows }; }, onListWorkers: function BTA_onListWorkers(aRequest) { + if (!this.attached) { + return { error: "wrongState" }; + } + if (this._workerActorList === null) { this._workerActorList = new WorkerActorList({ type: Ci.nsIWorkerDebugger.TYPE_DEDICATED, window: this.window }); } return this._workerActorList.getList().then((actors) => {
--- a/devtools/server/actors/worker.js +++ b/devtools/server/actors/worker.js @@ -141,74 +141,82 @@ function WorkerActorList(options) { this._onListChanged = null; this._mustNotify = false; this.onRegister = this.onRegister.bind(this); this.onUnregister = this.onUnregister.bind(this); } WorkerActorList.prototype = { getList: function () { + // Create a set of debuggers. let dbgs = new Set(); let e = wdm.getWorkerDebuggerEnumerator(); while (e.hasMoreElements()) { let dbg = e.getNext().QueryInterface(Ci.nsIWorkerDebugger); if (matchWorkerDebugger(dbg, this._options)) { dbgs.add(dbg); } } + // Delete each actor for which we don't have a debugger. for (let [dbg, ] of this._actors) { if (!dbgs.has(dbg)) { this._actors.delete(dbg); } } + // Create an actor for each debugger for which we don't have one. for (let dbg of dbgs) { if (!this._actors.has(dbg)) { this._actors.set(dbg, new WorkerActor(dbg)); } } let actors = []; for (let [, actor] of this._actors) { actors.push(actor); } - this._mustNotify = true; - this._checkListening(); + if (!this._mustNotify) { + if (this._onListChanged !== null) { + wdm.addListener(this); + } + this._mustNotify = true; + } return Promise.resolve(actors); }, get onListChanged() { return this._onListChanged; }, set onListChanged(onListChanged) { if (typeof onListChanged !== "function" && onListChanged !== null) { throw new Error("onListChanged must be either a function or null."); } + if (this._mustNotify) { + if (this._onListChanged === null && onListChanged !== null) { + wdm.addListener(this); + } + if (this._onListChanged !== null && onListChanged === null) { + wdm.removeListener(this); + } + } this._onListChanged = onListChanged; - this._checkListening(); - }, - - _checkListening: function () { - if (this._onListChanged !== null && this._mustNotify) { - wdm.addListener(this); - } else { - wdm.removeListener(this); - } }, _notifyListChanged: function () { - if (this._mustNotify) { - this._onListChanged(); - this._mustNotify = false; - } + this._onListChanged(); + + if (this._onListChanged !== null) { + wdm.removeListener(this); + } + this._mustNotify = false; }, onRegister: function (dbg) { if (matchWorkerDebugger(dbg, this._options)) { this._notifyListChanged(); } },
--- a/dom/base/nsContentUtils.cpp +++ b/dom/base/nsContentUtils.cpp @@ -7653,19 +7653,21 @@ nsContentUtils::GetButtonsFlagForButton( } } LayoutDeviceIntPoint nsContentUtils::ToWidgetPoint(const CSSPoint& aPoint, const nsPoint& aOffset, nsPresContext* aPresContext) { - return LayoutDeviceIntPoint::FromAppUnitsRounded( - CSSPoint::ToAppUnits(aPoint) + aOffset, - aPresContext->AppUnitsPerDevPixel()); + nsPoint point = CSSPoint::ToAppUnits(aPoint) + aOffset; +#if defined(MOZ_SINGLE_PROCESS_APZ) + point = point.ApplyResolution(aPresContext->PresShell()->GetCumulativeScaleResolution()); +#endif + return LayoutDeviceIntPoint::FromAppUnitsRounded(point, aPresContext->AppUnitsPerDevPixel()); } nsView* nsContentUtils::GetViewToDispatchEvent(nsPresContext* presContext, nsIPresShell** presShell) { if (presContext && presShell) { *presShell = presContext->PresShell();
--- a/dom/base/nsGlobalWindow.cpp +++ b/dom/base/nsGlobalWindow.cpp @@ -220,16 +220,17 @@ #include "mozilla/dom/PopupBlockedEvent.h" #include "mozilla/dom/PrimitiveConversions.h" #include "mozilla/dom/WindowBinding.h" #include "nsITabChild.h" #include "mozilla/dom/MediaQueryList.h" #include "mozilla/dom/ScriptSettings.h" #include "mozilla/dom/NavigatorBinding.h" #include "mozilla/dom/ImageBitmap.h" +#include "mozilla/dom/ServiceWorkerRegistration.h" #ifdef HAVE_SIDEBAR #include "mozilla/dom/ExternalBinding.h" #endif #ifdef MOZ_WEBSPEECH #include "mozilla/dom/SpeechSynthesis.h" #endif @@ -1571,16 +1572,18 @@ nsGlobalWindow::CleanUp() mAudioContexts.Clear(); if (mIdleTimer) { mIdleTimer->Cancel(); mIdleTimer = nullptr; } DisableTimeChangeNotifications(); + + mServiceWorkerRegistrationTable.Clear(); } void nsGlobalWindow::ClearControllers() { if (mControllers) { uint32_t count; mControllers->GetControllerCount(&count); @@ -1783,16 +1786,18 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_ NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mControllers) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mArguments) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDialogArguments) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mReturnValue) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mNavigator) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPerformance) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mServiceWorkerRegistrationTable) + #ifdef MOZ_WEBSPEECH NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSpeechSynthesis) #endif NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOuterWindow) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mListenerManager) @@ -1854,16 +1859,18 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(ns NS_IMPL_CYCLE_COLLECTION_UNLINK(mControllers) NS_IMPL_CYCLE_COLLECTION_UNLINK(mArguments) NS_IMPL_CYCLE_COLLECTION_UNLINK(mDialogArguments) NS_IMPL_CYCLE_COLLECTION_UNLINK(mReturnValue) NS_IMPL_CYCLE_COLLECTION_UNLINK(mNavigator) NS_IMPL_CYCLE_COLLECTION_UNLINK(mPerformance) + NS_IMPL_CYCLE_COLLECTION_UNLINK(mServiceWorkerRegistrationTable) + #ifdef MOZ_WEBSPEECH NS_IMPL_CYCLE_COLLECTION_UNLINK(mSpeechSynthesis) #endif if (tmp->mOuterWindow) { static_cast<nsGlobalWindow*>(tmp->mOuterWindow.get())->MaybeClearInnerWindow(tmp); NS_IMPL_CYCLE_COLLECTION_UNLINK(mOuterWindow) } @@ -10227,16 +10234,34 @@ nsGlobalWindow::GetCaches(ErrorResult& a storageBlocked, forceTrustedOrigin, aRv); } RefPtr<CacheStorage> ref = mCacheStorage; return ref.forget(); } +already_AddRefed<ServiceWorkerRegistrationMainThread> +nsPIDOMWindow::GetServiceWorkerRegistration(const nsAString& aScope) +{ + RefPtr<ServiceWorkerRegistrationMainThread> registration; + if (!mServiceWorkerRegistrationTable.Get(aScope, + getter_AddRefs(registration))) { + registration = new ServiceWorkerRegistrationMainThread(this, aScope); + mServiceWorkerRegistrationTable.Put(aScope, registration); + } + return registration.forget(); +} + +void +nsPIDOMWindow::InvalidateServiceWorkerRegistration(const nsAString& aScope) +{ + mServiceWorkerRegistrationTable.Remove(aScope); +} + void nsGlobalWindow::FireOfflineStatusEventIfChanged() { if (!IsCurrentInnerWindow()) return; bool isOffline = NS_IsOffline() || NS_IsAppOffline(GetPrincipal());
--- a/dom/base/nsPIDOMWindow.h +++ b/dom/base/nsPIDOMWindow.h @@ -10,16 +10,17 @@ #include "nsIDOMWindow.h" #include "nsCOMPtr.h" #include "nsAutoPtr.h" #include "nsTArray.h" #include "mozilla/dom/EventTarget.h" #include "js/TypeDecls.h" +#include "nsRefPtrHashtable.h" #define DOM_WINDOW_DESTROYED_TOPIC "dom-window-destroyed" #define DOM_WINDOW_FROZEN_TOPIC "dom-window-frozen" #define DOM_WINDOW_THAWED_TOPIC "dom-window-thawed" class nsIArray; class nsIContent; class nsICSSDeclaration; @@ -32,16 +33,17 @@ class nsPerformance; class nsPIWindowRoot; class nsXBLPrototypeHandler; struct nsTimeout; namespace mozilla { namespace dom { class AudioContext; class Element; +class ServiceWorkerRegistrationMainThread; } // namespace dom namespace gfx { class VRHMDInfo; } // namespace gfx } // namespace mozilla // Popup control state enum. The values in this enum must go from most // permissive to least permissive so that it's safe to push state in @@ -213,16 +215,20 @@ public: } bool GetServiceWorkersTestingEnabled() { MOZ_ASSERT(IsOuterWindow()); return mServiceWorkersTestingEnabled; } + already_AddRefed<mozilla::dom::ServiceWorkerRegistrationMainThread> + GetServiceWorkerRegistration(const nsAString& aScope); + void InvalidateServiceWorkerRegistration(const nsAString& aScope); + protected: // Lazily instantiate an about:blank document if necessary, and if // we have what it takes to do so. void MaybeCreateDoc(); float GetAudioGlobalVolumeInternal(float aVolume); void RefreshMediaElements(); @@ -850,16 +856,21 @@ protected: // This reference is used by the subclass nsGlobalWindow, and cleared in it's // DetachFromDocShell() method. This method is called by nsDocShell::Destroy(), // which is called before the nsDocShell is destroyed. nsIDocShell* MOZ_NON_OWNING_REF mDocShell; // Weak Reference // mPerformance is only used on inner windows. RefPtr<nsPerformance> mPerformance; + typedef nsRefPtrHashtable<nsStringHashKey, + mozilla::dom::ServiceWorkerRegistrationMainThread> + ServiceWorkerRegistrationTable; + ServiceWorkerRegistrationTable mServiceWorkerRegistrationTable; + uint32_t mModalStateDepth; // These variables are only used on inner windows. nsTimeout *mRunningTimeout; uint32_t mMutationBits; bool mIsDocumentLoaded;
--- a/dom/base/nsScriptLoader.cpp +++ b/dom/base/nsScriptLoader.cpp @@ -964,16 +964,21 @@ nsScriptLoader::ProcessRequest(nsScriptL mCurrentParserInsertedScript = aRequest->mElement; } FireScriptAvailable(NS_OK, aRequest); // The window may have gone away by this point, in which case there's no point // in trying to run the script. nsCOMPtr<nsIDocument> master = mDocument->MasterDocument(); + { + // Try to perform a microtask checkpoint + nsAutoMicroTask mt; + } + nsPIDOMWindow *pwin = master->GetInnerWindow(); bool runScript = !!pwin; if (runScript) { nsContentUtils::DispatchTrustedEvent(scriptElem->OwnerDoc(), scriptElem, NS_LITERAL_STRING("beforescriptexecute"), true, true, &runScript); }
--- a/dom/base/test/mochitest.ini +++ b/dom/base/test/mochitest.ini @@ -672,16 +672,17 @@ skip-if = os == "mac" # fails intermitte [test_bug737612.html] [test_bug738108.html] [test_bug744830.html] [test_bug749367.html] [test_bug753278.html] [test_bug761120.html] [test_bug782342.html] [test_bug787778.html] +[test_bug789315.html] [test_bug789856.html] [test_bug804395.html] skip-if = (buildapp == 'b2g' && toolkit != 'gonk') #bug 901343, specialpowers.wrap issue createsystemxhr [test_bug809003.html] [test_bug810494.html] [test_bug811701.html] [test_bug811701.xhtml] [test_bug813919.html]
new file mode 100644 --- /dev/null +++ b/dom/base/test/test_bug789315.html @@ -0,0 +1,49 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=789315 +--> +<head> + <meta charset="utf-8"> + <title>Test for Bug 789315</title> + <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> + <script type="text/javascript"> + (function() { + const observerConfig = { + childList: true, + }; + + var observer = new MutationObserver(onMutations); + observer.observe(document.head, observerConfig); + + function onMutations(mutations) { + for (var i in mutations) { + var mutation = mutations[i]; + for (var j in mutation.addedNodes) { + var addedNode = mutation.addedNodes[j]; + addedNode.mutationObserverHasNotified = true; + } + } + } + + })(); + </script> + + <link id="testnode" rel="localization" href="dummy"></link> + + <script type="text/javascript"> + var testNode = document.getElementById("testnode"); + ok(testNode.mutationObserverHasNotified); + </script> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=789315">Mozilla Bug 789315</a> +<p id="display"></p> +<div id="content" style="display: none"> + +</div> +<pre id="test"> +</pre> +</body> +</html>
--- a/dom/events/Event.cpp +++ b/dom/events/Event.cpp @@ -922,29 +922,32 @@ Event::GetScreenCoords(nsPresContext* aP aEvent->mClass != eTouchEventClass && aEvent->mClass != eDragEventClass && aEvent->mClass != eSimpleGestureEventClass)) { return CSSIntPoint(0, 0); } // Doing a straight conversion from LayoutDeviceIntPoint to CSSIntPoint // seem incorrect, but it is needed to maintain legacy functionality. - if (!aPresContext) { + WidgetGUIEvent* guiEvent = aEvent->AsGUIEvent(); + if (!aPresContext || !(guiEvent && guiEvent->widget)) { return CSSIntPoint(aPoint.x, aPoint.y); } - LayoutDeviceIntPoint offset = aPoint; + nsPoint pt = + LayoutDevicePixel::ToAppUnits(aPoint, aPresContext->DeviceContext()->AppUnitsPerDevPixelAtUnitFullZoom()); - WidgetGUIEvent* guiEvent = aEvent->AsGUIEvent(); - if (guiEvent && guiEvent->widget) { - offset += guiEvent->widget->WidgetToScreenOffset(); +#if defined(MOZ_SINGLE_PROCESS_APZ) + if (aPresContext->PresShell()) { + pt = pt.RemoveResolution(aPresContext->PresShell()->GetCumulativeScaleResolution()); } +#endif - nsPoint pt = - LayoutDevicePixel::ToAppUnits(offset, aPresContext->DeviceContext()->AppUnitsPerDevPixelAtUnitFullZoom()); + pt += LayoutDevicePixel::ToAppUnits(guiEvent->widget->WidgetToScreenOffset(), + aPresContext->DeviceContext()->AppUnitsPerDevPixelAtUnitFullZoom()); return CSSPixel::FromAppUnitsRounded(pt); } // static CSSIntPoint Event::GetPageCoords(nsPresContext* aPresContext, WidgetEvent* aEvent,
--- a/dom/interfaces/base/nsIServiceWorkerManager.idl +++ b/dom/interfaces/base/nsIServiceWorkerManager.idl @@ -16,21 +16,29 @@ interface nsIURI; interface nsIServiceWorkerUnregisterCallback : nsISupports { // aState is true if the unregistration succeded. // It's false if this ServiceWorkerRegistration doesn't exist. void unregisterSucceeded(in bool aState); void unregisterFailed(); }; -[scriptable, builtinclass, uuid(1a1e71dd-0f78-4e2e-a2db-a946fe02cddf)] +interface nsIWorkerDebugger; + +[scriptable, builtinclass, uuid(76e357ed-208d-4e4c-9165-1c4059707879)] interface nsIServiceWorkerInfo : nsISupports { readonly attribute DOMString scriptSpec; readonly attribute DOMString cacheName; + + readonly attribute nsIWorkerDebugger debugger; + + void attachDebugger(); + + void detachDebugger(); }; [scriptable, uuid(87e63548-d440-4b8a-b158-65ad1de0211E)] interface nsIServiceWorkerRegistrationInfoListener : nsISupports { void onChange(); };
--- a/dom/ipc/ContentChild.cpp +++ b/dom/ipc/ContentChild.cpp @@ -2802,32 +2802,30 @@ ContentChild::RecvOnAppThemeChanged() nsCOMPtr<nsIObserverService> os = services::GetObserverService(); if (os) { os->NotifyObservers(nullptr, "app-theme-changed", nullptr); } return true; } bool -ContentChild::RecvStartProfiler(const uint32_t& aEntries, - const double& aInterval, - nsTArray<nsCString>&& aFeatures, - nsTArray<nsCString>&& aThreadNameFilters) +ContentChild::RecvStartProfiler(const ProfilerInitParams& params) { nsTArray<const char*> featureArray; - for (size_t i = 0; i < aFeatures.Length(); ++i) { - featureArray.AppendElement(aFeatures[i].get()); + for (size_t i = 0; i < params.features().Length(); ++i) { + featureArray.AppendElement(params.features()[i].get()); } nsTArray<const char*> threadNameFilterArray; - for (size_t i = 0; i < aThreadNameFilters.Length(); ++i) { - threadNameFilterArray.AppendElement(aThreadNameFilters[i].get()); + for (size_t i = 0; i < params.threadFilters().Length(); ++i) { + threadNameFilterArray.AppendElement(params.threadFilters()[i].get()); } - profiler_start(aEntries, aInterval, featureArray.Elements(), featureArray.Length(), + profiler_start(params.entries(), params.interval(), + featureArray.Elements(), featureArray.Length(), threadNameFilterArray.Elements(), threadNameFilterArray.Length()); return true; } bool ContentChild::RecvStopProfiler() {
--- a/dom/ipc/ContentChild.h +++ b/dom/ipc/ContentChild.h @@ -419,20 +419,17 @@ public: virtual bool RecvOnAppThemeChanged() override; virtual bool RecvAssociatePluginId(const uint32_t& aPluginId, const base::ProcessId& aProcessId) override; virtual bool RecvLoadPluginResult(const uint32_t& aPluginId, const bool& aResult) override; virtual bool RecvUpdateWindow(const uintptr_t& aChildId) override; - virtual bool RecvStartProfiler(const uint32_t& aEntries, - const double& aInterval, - nsTArray<nsCString>&& aFeatures, - nsTArray<nsCString>&& aThreadNameFilters) override; + virtual bool RecvStartProfiler(const ProfilerInitParams& params) override; virtual bool RecvPauseProfiler(const bool& aPause) override; virtual bool RecvStopProfiler() override; virtual bool RecvGatherProfile() override; virtual bool RecvDomainSetChanged(const uint32_t& aSetType, const uint32_t& aChangeType, const OptionalURIParams& aDomain) override; virtual bool RecvShutdown() override; virtual bool
--- a/dom/ipc/ContentParent.cpp +++ b/dom/ipc/ContentParent.cpp @@ -1552,16 +1552,31 @@ ContentParent::Init() #ifdef ACCESSIBILITY // If accessibility is running in chrome process then start it in content // process. if (nsIPresShell::IsAccessibilityActive()) { Unused << SendActivateA11y(); } #endif + +#ifdef MOZ_ENABLE_PROFILER_SPS + nsCOMPtr<nsIProfiler> profiler(do_GetService("@mozilla.org/tools/profiler;1")); + bool profilerActive = false; + DebugOnly<nsresult> rv = profiler->IsActive(&profilerActive); + MOZ_ASSERT(NS_SUCCEEDED(rv)); + + if (profilerActive) { + nsCOMPtr<nsIProfilerStartParams> currentProfilerParams; + rv = profiler->GetStartParams(getter_AddRefs(currentProfilerParams)); + MOZ_ASSERT(NS_SUCCEEDED(rv)); + + StartProfiler(currentProfilerParams); + } +#endif } void ContentParent::ForwardKnownInfo() { MOZ_ASSERT(mMetamorphosed); if (!mMetamorphosed) { return; @@ -3270,23 +3285,17 @@ ContentParent::Observe(nsISupports* aSub } #endif else if (!strcmp(aTopic, "app-theme-changed")) { Unused << SendOnAppThemeChanged(); } #ifdef MOZ_ENABLE_PROFILER_SPS else if (!strcmp(aTopic, "profiler-started")) { nsCOMPtr<nsIProfilerStartParams> params(do_QueryInterface(aSubject)); - uint32_t entries; - double interval; - params->GetEntries(&entries); - params->GetInterval(&interval); - const nsTArray<nsCString>& features = params->GetFeatures(); - const nsTArray<nsCString>& threadFilterNames = params->GetThreadFilterNames(); - Unused << SendStartProfiler(entries, interval, features, threadFilterNames); + StartProfiler(params); } else if (!strcmp(aTopic, "profiler-stopped")) { Unused << SendStopProfiler(); } else if (!strcmp(aTopic, "profiler-paused")) { Unused << SendPauseProfiler(true); } else if (!strcmp(aTopic, "profiler-resumed")) { @@ -5704,16 +5713,34 @@ ContentParent::RecvGetAndroidSystemInfo( nsSystemInfo::GetAndroidSystemInfo(aInfo); return true; #else MOZ_CRASH("wrong platform!"); return false; #endif } +void +ContentParent::StartProfiler(nsIProfilerStartParams* aParams) +{ + if (NS_WARN_IF(!aParams)) { + return; + } + + ProfilerInitParams ipcParams; + + ipcParams.enabled() = true; + aParams->GetEntries(&ipcParams.entries()); + aParams->GetInterval(&ipcParams.interval()); + ipcParams.features() = aParams->GetFeatures(); + ipcParams.threadFilters() = aParams->GetThreadFilterNames(); + + Unused << SendStartProfiler(ipcParams); +} + } // namespace dom } // namespace mozilla NS_IMPL_ISUPPORTS(ParentIdleListener, nsIObserver) NS_IMETHODIMP ParentIdleListener::Observe(nsISupports*, const char* aTopic, const char16_t* aData) { mozilla::Unused << mParent->SendNotifyIdleObserver(mObserver,
--- a/dom/ipc/ContentParent.h +++ b/dom/ipc/ContentParent.h @@ -930,16 +930,17 @@ private: const uint32_t& aDropEffect) override; virtual bool RecvGetBrowserConfiguration(const nsCString& aURI, BrowserConfiguration* aConfig) override; virtual bool RecvGamepadListenerAdded() override; virtual bool RecvGamepadListenerRemoved() override; virtual bool RecvProfile(const nsCString& aProfile) override; virtual bool RecvGetGraphicsDeviceInitData(DeviceInitData* aOut) override; + void StartProfiler(nsIProfilerStartParams* aParams); virtual bool RecvGetDeviceStorageLocation(const nsString& aType, nsString* aPath) override; virtual bool RecvGetAndroidSystemInfo(AndroidSystemInfo* aInfo) override; // If you add strong pointers to cycle collected objects here, be sure to // release these objects in ShutDownProcess. See the comment there for more
--- a/dom/ipc/PContent.ipdl +++ b/dom/ipc/PContent.ipdl @@ -60,16 +60,17 @@ include InputStreamParams; include PTabContext; include URIParams; include PluginTypes; include ProtocolTypes; include PBackgroundSharedTypes; include PContentPermission; include BrowserConfiguration; include GraphicsMessages; +include ProfilerTypes; // Workaround to prevent error if PContentChild.cpp & PContentBridgeParent.cpp // are put into different UnifiedProtocolsXX.cpp files. // XXX Remove this once bug 1069073 is fixed include "mozilla/dom/PContentBridgeParent.h"; using GeoPosition from "nsGeoPositionIPCSerialiser.h"; @@ -646,18 +647,17 @@ child: * PluginModuleContentParent that the PluginModuleChromeParent's async * init has completed. */ async LoadPluginResult(uint32_t aPluginId, bool aResult); /** * Control the Gecko Profiler in the child process. */ - async StartProfiler(uint32_t aEntries, double aInterval, nsCString[] aFeatures, - nsCString[] aThreadNameFilters); + async StartProfiler(ProfilerInitParams params); async StopProfiler(); async PauseProfiler(bool aPause); async GatherProfile(); InvokeDragSession(IPCDataTransfer[] transfers, uint32_t action); EndDragSession(bool aDoneDrag, bool aUserCancelled);
--- a/dom/media/eme/CDMProxy.cpp +++ b/dom/media/eme/CDMProxy.cpp @@ -13,16 +13,17 @@ #include "nsServiceManagerUtils.h" #include "MainThreadUtils.h" #include "mozilla/EMEUtils.h" #include "nsIConsoleService.h" #include "prenv.h" #include "mozilla/PodOperations.h" #include "mozilla/CDMCallbackProxy.h" #include "MediaData.h" +#include "nsPrintfCString.h" namespace mozilla { CDMProxy::CDMProxy(dom::MediaKeys* aKeys, const nsAString& aKeySystem) : mKeys(aKeys) , mKeySystem(aKeySystem) , mCDM(nullptr) , mDecryptionJobCount(0) @@ -36,16 +37,17 @@ CDMProxy::~CDMProxy() { MOZ_COUNT_DTOR(CDMProxy); } void CDMProxy::Init(PromiseId aPromiseId, const nsAString& aOrigin, const nsAString& aTopLevelOrigin, + const nsAString& aGMPName, bool aInPrivateBrowsing) { MOZ_ASSERT(NS_IsMainThread()); NS_ENSURE_TRUE_VOID(!mKeys.IsNull()); EME_LOG("CDMProxy::Init (%s, %s) %s", NS_ConvertUTF16toUTF8(aOrigin).get(), NS_ConvertUTF16toUTF8(aTopLevelOrigin).get(), @@ -63,20 +65,27 @@ CDMProxy::Init(PromiseId aPromiseId, mps->GetThread(getter_AddRefs(mGMPThread)); if (!mGMPThread) { RejectPromise(aPromiseId, NS_ERROR_DOM_INVALID_STATE_ERR, NS_LITERAL_CSTRING("Couldn't get GMP thread CDMProxy::Init")); return; } } + if (aGMPName.IsEmpty()) { + RejectPromise(aPromiseId, NS_ERROR_DOM_INVALID_STATE_ERR, + nsPrintfCString("Unknown GMP for keysystem '%s'", NS_ConvertUTF16toUTF8(mKeySystem).get())); + return; + } + nsAutoPtr<InitData> data(new InitData()); data->mPromiseId = aPromiseId; data->mOrigin = aOrigin; data->mTopLevelOrigin = aTopLevelOrigin; + data->mGMPName = aGMPName; data->mInPrivateBrowsing = aInPrivateBrowsing; nsCOMPtr<nsIRunnable> task( NS_NewRunnableMethodWithArg<nsAutoPtr<InitData>>(this, &CDMProxy::gmp_Init, Move(data))); mGMPThread->Dispatch(task, NS_DISPATCH_NORMAL); } @@ -171,16 +180,17 @@ CDMProxy::gmp_Init(nsAutoPtr<InitData>&& // Make a copy before we transfer ownership of aData to the // gmp_InitGetGMPDecryptorCallback. InitData data(*aData); UniquePtr<GetNodeIdCallback> callback( new gmp_InitGetGMPDecryptorCallback(this, Move(aData))); nsresult rv = mps->GetNodeId(data.mOrigin, data.mTopLevelOrigin, + data.mGMPName, data.mInPrivateBrowsing, Move(callback)); if (NS_FAILED(rv)) { RejectPromise(data.mPromiseId, NS_ERROR_DOM_INVALID_STATE_ERR, NS_LITERAL_CSTRING("Call to GetNodeId() failed early")); } }
--- a/dom/media/eme/CDMProxy.h +++ b/dom/media/eme/CDMProxy.h @@ -52,16 +52,17 @@ public: CDMProxy(dom::MediaKeys* aKeys, const nsAString& aKeySystem); // Main thread only. // Loads the CDM corresponding to mKeySystem. // Calls MediaKeys::OnCDMCreated() when the CDM is created. void Init(PromiseId aPromiseId, const nsAString& aOrigin, const nsAString& aTopLevelOrigin, + const nsAString& aGMPName, bool aInPrivateBrowsing); // Main thread only. // Uses the CDM to create a key session. // Calls MediaKeys::OnSessionActivated() when session is created. // Assumes ownership of (Move()s) aInitData's contents. void CreateSession(uint32_t aCreateSessionToken, dom::SessionType aSessionType, @@ -181,16 +182,17 @@ public: private: friend class gmp_InitDoneCallback; friend class gmp_InitGetGMPDecryptorCallback; struct InitData { uint32_t mPromiseId; nsAutoString mOrigin; nsAutoString mTopLevelOrigin; + nsString mGMPName; bool mInPrivateBrowsing; }; // GMP thread only. void gmp_Init(nsAutoPtr<InitData>&& aData); void gmp_InitDone(GMPDecryptorProxy* aCDM, nsAutoPtr<InitData>&& aData); void gmp_InitGetGMPDecryptor(nsresult aResult, const nsACString& aNodeId,
--- a/dom/media/eme/EMEUtils.cpp +++ b/dom/media/eme/EMEUtils.cpp @@ -136,9 +136,22 @@ CopyArrayBufferViewOrArrayBufferData(con ArrayData data = GetArrayBufferViewOrArrayBufferData(aBufferOrView); aOutData.Clear(); if (!data.IsValid()) { return; } aOutData.AppendElements(data.mData, data.mLength); } +nsString +KeySystemToGMPName(const nsAString& aKeySystem) +{ + if (aKeySystem.EqualsLiteral("com.adobe.primetime")) { + return NS_LITERAL_STRING("gmp-eme-adobe"); + } + if (aKeySystem.EqualsLiteral("org.w3.clearkey")) { + return NS_LITERAL_STRING("gmp-clearkey"); + } + MOZ_ASSERT(false, "We should only call this for known GMPs"); + return EmptyString(); +} + } // namespace mozilla
--- a/dom/media/eme/EMEUtils.h +++ b/dom/media/eme/EMEUtils.h @@ -99,11 +99,14 @@ struct ArrayData { // while the ArrayData is live, as then all bets about the data not changing // are off! No calls into JS, no calls into JS-implemented WebIDL or XPIDL, // nothing. Beware! // // Only call this on a properly initialized ArrayBufferViewOrArrayBuffer. ArrayData GetArrayBufferViewOrArrayBufferData(const dom::ArrayBufferViewOrArrayBuffer& aBufferOrView); +nsString +KeySystemToGMPName(const nsAString& aKeySystem); + } // namespace mozilla #endif // EME_LOG_H_
--- a/dom/media/eme/MediaKeySystemAccess.cpp +++ b/dom/media/eme/MediaKeySystemAccess.cpp @@ -438,16 +438,19 @@ GetSupportedConfig(mozIGeckoMediaPluginS { MediaKeySystemConfiguration config; config.mLabel = aCandidate.mLabel; if (aCandidate.mInitDataTypes.WasPassed()) { nsTArray<nsString> initDataTypes; for (const nsString& candidate : aCandidate.mInitDataTypes.Value()) { if (candidate.EqualsLiteral("cenc")) { initDataTypes.AppendElement(candidate); + } else if (candidate.EqualsLiteral("keyids") && + aKeySystem.EqualsLiteral("org.w3.clearkey")) { + initDataTypes.AppendElement(candidate); } } if (initDataTypes.IsEmpty()) { return false; } config.mInitDataTypes.Construct(); config.mInitDataTypes.Value().Assign(initDataTypes); }
--- a/dom/media/eme/MediaKeys.cpp +++ b/dom/media/eme/MediaKeys.cpp @@ -363,16 +363,17 @@ MediaKeys::Init(ErrorResult& aRv) // here, and hold a self-reference until that promise is resolved or // rejected. MOZ_ASSERT(!mCreatePromiseId, "Should only be created once!"); mCreatePromiseId = StorePromise(promise); AddRef(); mProxy->Init(mCreatePromiseId, origin, topLevelOrigin, + KeySystemToGMPName(mKeySystem), inPrivateBrowsing); return promise.forget(); } void MediaKeys::OnCDMCreated(PromiseId aId, const nsACString& aNodeId, const uint32_t aPluginId) {
--- a/dom/media/gmp/GMPParent.cpp +++ b/dom/media/gmp/GMPParent.cpp @@ -1063,13 +1063,19 @@ GMPParent::Bridge(GMPServiceParent* aGMP { if (NS_FAILED(PGMPContent::Bridge(aGMPServiceParent, this))) { return false; } ++mGMPContentChildCount; return true; } +nsString +GMPParent::GetPluginBaseName() const +{ + return NS_LITERAL_STRING("gmp-") + mName; +} + } // namespace gmp } // namespace mozilla #undef LOG #undef LOGD
--- a/dom/media/gmp/GMPParent.h +++ b/dom/media/gmp/GMPParent.h @@ -119,16 +119,17 @@ public: // Specifies that a GMP can only work with the specified NodeIds. void SetNodeId(const nsACString& aNodeId); const nsACString& GetNodeId() const { return mNodeId; } const nsCString& GetDisplayName() const; const nsCString& GetVersion() const; const uint32_t GetPluginId() const; + nsString GetPluginBaseName() const; // Returns true if a plugin can be or is being used across multiple NodeIds. bool CanBeSharedCrossNodeIds() const; // A GMP can be used from a NodeId if it's already been set to work with // that NodeId, or if it's not been set to work with any NodeId and has // not yet been loaded (i.e. it's not shared across NodeIds). bool CanBeUsedFrom(const nsACString& aNodeId) const;
--- a/dom/media/gmp/GMPServiceChild.cpp +++ b/dom/media/gmp/GMPServiceChild.cpp @@ -132,56 +132,61 @@ GeckoMediaPluginServiceChild::GetPluginV aOutVersion = version; return ok ? NS_OK : NS_ERROR_FAILURE; } class GetNodeIdDone : public GetServiceChildCallback { public: GetNodeIdDone(const nsAString& aOrigin, const nsAString& aTopLevelOrigin, + const nsAString& aGMPName, bool aInPrivateBrowsing, UniquePtr<GetNodeIdCallback>&& aCallback) : mOrigin(aOrigin), mTopLevelOrigin(aTopLevelOrigin), + mGMPName(aGMPName), mInPrivateBrowsing(aInPrivateBrowsing), mCallback(Move(aCallback)) { } virtual void Done(GMPServiceChild* aGMPServiceChild) { if (!aGMPServiceChild) { mCallback->Done(NS_ERROR_FAILURE, EmptyCString()); return; } nsCString outId; if (!aGMPServiceChild->SendGetGMPNodeId(mOrigin, mTopLevelOrigin, + mGMPName, mInPrivateBrowsing, &outId)) { mCallback->Done(NS_ERROR_FAILURE, EmptyCString()); return; } mCallback->Done(NS_OK, outId); } private: nsString mOrigin; nsString mTopLevelOrigin; + nsString mGMPName; bool mInPrivateBrowsing; UniquePtr<GetNodeIdCallback> mCallback; }; NS_IMETHODIMP GeckoMediaPluginServiceChild::GetNodeId(const nsAString& aOrigin, const nsAString& aTopLevelOrigin, + const nsAString& aGMPName, bool aInPrivateBrowsing, UniquePtr<GetNodeIdCallback>&& aCallback) { UniquePtr<GetServiceChildCallback> callback( - new GetNodeIdDone(aOrigin, aTopLevelOrigin, aInPrivateBrowsing, Move(aCallback))); + new GetNodeIdDone(aOrigin, aTopLevelOrigin, aGMPName, aInPrivateBrowsing, Move(aCallback))); GetServiceChild(Move(callback)); return NS_OK; } NS_IMETHODIMP GeckoMediaPluginServiceChild::UpdateTrialCreateState(const nsAString& aKeySystem, uint32_t aState) {
--- a/dom/media/gmp/GMPServiceChild.h +++ b/dom/media/gmp/GMPServiceChild.h @@ -42,16 +42,17 @@ public: static already_AddRefed<GeckoMediaPluginServiceChild> GetSingleton(); NS_IMETHOD GetPluginVersionForAPI(const nsACString& aAPI, nsTArray<nsCString>* aTags, bool* aHasPlugin, nsACString& aOutVersion) override; NS_IMETHOD GetNodeId(const nsAString& aOrigin, const nsAString& aTopLevelOrigin, + const nsAString& aGMPName, bool aInPrivateBrowsingMode, UniquePtr<GetNodeIdCallback>&& aCallback) override; NS_IMETHOD UpdateTrialCreateState(const nsAString& aKeySystem, uint32_t aState) override; NS_DECL_NSIOBSERVER void SetServiceChild(UniquePtr<GMPServiceChild>&& aServiceChild);
--- a/dom/media/gmp/GMPServiceParent.cpp +++ b/dom/media/gmp/GMPServiceParent.cpp @@ -158,58 +158,79 @@ CloneAndAppend(nsIFile* aFile, const nsA rv = f->Append(aDir); if (NS_WARN_IF(NS_FAILED(rv))) { return nullptr; } return f.forget(); } static void -MoveAndOverwrite(nsIFile* aOldStorageDir, - nsIFile* aNewStorageDir, +MoveAndOverwrite(nsIFile* aOldParentDir, + nsIFile* aNewParentDir, const nsAString& aSubDir) { nsresult rv; - nsCOMPtr<nsIFile> srcDir(CloneAndAppend(aOldStorageDir, aSubDir)); + nsCOMPtr<nsIFile> srcDir(CloneAndAppend(aOldParentDir, aSubDir)); if (NS_WARN_IF(!srcDir)) { return; } if (!FileExists(srcDir)) { // No sub-directory to be migrated. return; } - nsCOMPtr<nsIFile> dstDir(CloneAndAppend(aNewStorageDir, aSubDir)); + // Ensure destination parent directory exists. + rv = aNewParentDir->Create(nsIFile::DIRECTORY_TYPE, 0700); + if (rv != NS_ERROR_FILE_ALREADY_EXISTS && NS_WARN_IF(NS_FAILED(rv))) { + return; + } + + nsCOMPtr<nsIFile> dstDir(CloneAndAppend(aNewParentDir, aSubDir)); if (FileExists(dstDir)) { // We must have migrated before already, and then ran an old version // of Gecko again which created storage at the old location. Overwrite // the previously migrated storage. rv = dstDir->Remove(true); if (NS_WARN_IF(NS_FAILED(rv))) { // MoveTo will fail. return; } } - rv = srcDir->MoveTo(aNewStorageDir, EmptyString()); + rv = srcDir->MoveTo(aNewParentDir, EmptyString()); if (NS_WARN_IF(NS_FAILED(rv))) { return; } } static void MigratePreGecko42StorageDir(nsIFile* aOldStorageDir, nsIFile* aNewStorageDir) { MoveAndOverwrite(aOldStorageDir, aNewStorageDir, NS_LITERAL_STRING("id")); MoveAndOverwrite(aOldStorageDir, aNewStorageDir, NS_LITERAL_STRING("storage")); } +static void +MigratePreGecko45StorageDir(nsIFile* aStorageDirBase) +{ + nsCOMPtr<nsIFile> adobeStorageDir(CloneAndAppend(aStorageDirBase, NS_LITERAL_STRING("gmp-eme-adobe"))); + if (NS_WARN_IF(!adobeStorageDir)) { + return; + } + + // The base storage dir in pre-45 contained "id" and "storage" subdirs. + // We assume all storage in the base storage dir that aren't known to GMP + // storage are records for the Adobe GMP. + MoveAndOverwrite(aStorageDirBase, adobeStorageDir, NS_LITERAL_STRING("id")); + MoveAndOverwrite(aStorageDirBase, adobeStorageDir, NS_LITERAL_STRING("storage")); +} + static nsresult GMPPlatformString(nsAString& aOutPlatform) { // Append the OS and arch so that we don't reuse the storage if the profile is // copied or used under a different bit-ness, or copied to another platform. nsCOMPtr<nsIXULRuntime> runtime = do_GetService("@mozilla.org/xre/runtime;1"); if (!runtime) { return NS_ERROR_FAILURE; @@ -286,21 +307,29 @@ GeckoMediaPluginServiceParent::InitStora return rv; } rv = mStorageBaseDir->Create(nsIFile::DIRECTORY_TYPE, 0700); if (NS_WARN_IF(NS_FAILED(rv) && rv != NS_ERROR_FILE_ALREADY_EXISTS)) { return rv; } - // Prior to 42, GMP storage was stored in $profile/gmp/. After 42, it's - // stored in $profile/gmp/$platform/. So we must migrate any old records + // Prior to 42, GMP storage was stored in $profileDir/gmp/. After 42, it's + // stored in $profileDir/gmp/$platform/. So we must migrate any old records // from the old location to the new location, for forwards compatibility. MigratePreGecko42StorageDir(gmpDirWithoutPlatform, mStorageBaseDir); + // Prior to 45, GMP storage was not separated by plugin. In 45 and after, + // it's stored in $profile/gmp/$platform/$gmpName. So we must migrate old + // records from the old location to the new location, for forwards + // compatibility. We assume all directories in the base storage dir that + // aren't known to GMP storage are records for the Adobe GMP, since it + // was first. + MigratePreGecko45StorageDir(mStorageBaseDir); + return GeckoMediaPluginService::Init(); } NS_IMETHODIMP GeckoMediaPluginServiceParent::Observe(nsISupports* aSubject, const char* aTopic, const char16_t* aSomeData) { @@ -727,17 +756,17 @@ GeckoMediaPluginServiceParent::PathRunna { if (mOperation == ADD) { mService->AddOnGMPThread(mPath); } else { mService->RemoveOnGMPThread(mPath, mOperation == REMOVE_AND_DELETE_FROM_DISK, mDefer); } -#ifndef MOZ_WIDGET_GONK // Bug 1214967: disabled on B2G due to inscrutable test failures. +#ifndef MOZ_WIDGET_GONK // Bug 1214967: disabled on B2G due to inscrutable test failures. // For e10s, we must fire a notification so that all ContentParents notify // their children to update the codecs that the GMPDecoderModule can use. NS_DispatchToMainThread(new NotifyObserversTask("gmp-changed"), NS_DISPATCH_NORMAL); // For non-e10s, and for decoding in the chrome process, must update GMP // PDM's codecs list directly. NS_DispatchToMainThread(NS_NewRunnableFunction([]() -> void { GMPDecoderModule::UpdateUsableCodecs(); })); @@ -1207,16 +1236,17 @@ GeckoMediaPluginServiceParent::IsPersist NS_ENSURE_ARG(aOutAllowed); *aOutAllowed = mPersistentStorageAllowed.Get(aNodeId); return NS_OK; } nsresult GeckoMediaPluginServiceParent::GetNodeId(const nsAString& aOrigin, const nsAString& aTopLevelOrigin, + const nsAString& aGMPName, bool aInPrivateBrowsing, nsACString& aOutId) { MOZ_ASSERT(NS_GetCurrentThread() == mGMPThread); LOGD(("%s::%s: (%s, %s), %s", __CLASS__, __FUNCTION__, NS_ConvertUTF16toUTF8(aOrigin).get(), NS_ConvertUTF16toUTF8(aTopLevelOrigin).get(), (aInPrivateBrowsing ? "PrivateBrowsing" : "NonPrivateBrowsing"))); @@ -1239,58 +1269,70 @@ GeckoMediaPluginServiceParent::GetNodeId mPersistentStorageAllowed.Put(salt, false); return NS_OK; } const uint32_t hash = AddToHash(HashString(aOrigin), HashString(aTopLevelOrigin)); if (aInPrivateBrowsing) { - // For PB mode, we store the node id, indexed by the origin pair, - // so that if the same origin pair is opened in this session, it gets - // the same node id. + // For PB mode, we store the node id, indexed by the origin pair and GMP name, + // so that if the same origin pair is opened for the same GMP in this session, + // it gets the same node id. + const uint32_t pbHash = AddToHash(HashString(aGMPName), hash); nsCString* salt = nullptr; - if (!(salt = mTempNodeIds.Get(hash))) { + if (!(salt = mTempNodeIds.Get(pbHash))) { // No salt stored, generate and temporarily store some for this id. nsAutoCString newSalt; rv = GenerateRandomPathName(newSalt, NodeIdSaltLength); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } salt = new nsCString(newSalt); - mTempNodeIds.Put(hash, salt); + mTempNodeIds.Put(pbHash, salt); mPersistentStorageAllowed.Put(*salt, false); } aOutId = *salt; return NS_OK; } // Otherwise, try to see if we've previously generated and stored salt // for this origin pair. - nsCOMPtr<nsIFile> path; // $profileDir/gmp/ + nsCOMPtr<nsIFile> path; // $profileDir/gmp/$platform/ rv = GetStorageDir(getter_AddRefs(path)); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } + rv = path->Append(aGMPName); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + // $profileDir/gmp/$platform/$gmpName/ + rv = path->Create(nsIFile::DIRECTORY_TYPE, 0700); + if (rv != NS_ERROR_FILE_ALREADY_EXISTS && NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + rv = path->AppendNative(NS_LITERAL_CSTRING("id")); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } - // $profileDir/gmp/id/ + // $profileDir/gmp/$platform/$gmpName/id/ rv = path->Create(nsIFile::DIRECTORY_TYPE, 0700); if (rv != NS_ERROR_FILE_ALREADY_EXISTS && NS_WARN_IF(NS_FAILED(rv))) { return rv; } nsAutoCString hashStr; hashStr.AppendInt((int64_t)hash); - // $profileDir/gmp/id/$hash + // $profileDir/gmp/$platform/$gmpName/id/$hash rv = path->AppendNative(hashStr); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } rv = path->Create(nsIFile::DIRECTORY_TYPE, 0700); if (rv != NS_ERROR_FILE_ALREADY_EXISTS && NS_WARN_IF(NS_FAILED(rv))) { return rv; @@ -1317,31 +1359,31 @@ GeckoMediaPluginServiceParent::GetNodeId // No stored salt for this origin. Generate salt, and store it and // the origin on disk. nsresult rv = GenerateRandomPathName(salt, NodeIdSaltLength); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } MOZ_ASSERT(salt.Length() == NodeIdSaltLength); - // $profileDir/gmp/id/$hash/salt + // $profileDir/gmp/$platform/$gmpName/id/$hash/salt rv = WriteToFile(path, NS_LITERAL_CSTRING("salt"), salt); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } - // $profileDir/gmp/id/$hash/origin + // $profileDir/gmp/$platform/$gmpName/id/$hash/origin rv = WriteToFile(path, NS_LITERAL_CSTRING("origin"), NS_ConvertUTF16toUTF8(aOrigin)); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } - // $profileDir/gmp/id/$hash/topLevelOrigin + // $profileDir/gmp/$platform/$gmpName/id/$hash/topLevelOrigin rv = WriteToFile(path, NS_LITERAL_CSTRING("topLevelOrigin"), NS_ConvertUTF16toUTF8(aTopLevelOrigin)); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } } else { @@ -1355,21 +1397,22 @@ GeckoMediaPluginServiceParent::GetNodeId mPersistentStorageAllowed.Put(salt, true); return NS_OK; } NS_IMETHODIMP GeckoMediaPluginServiceParent::GetNodeId(const nsAString& aOrigin, const nsAString& aTopLevelOrigin, + const nsAString& aGMPName, bool aInPrivateBrowsing, UniquePtr<GetNodeIdCallback>&& aCallback) { nsCString nodeId; - nsresult rv = GetNodeId(aOrigin, aTopLevelOrigin, aInPrivateBrowsing, nodeId); + nsresult rv = GetNodeId(aOrigin, aTopLevelOrigin, aGMPName, aInPrivateBrowsing, nodeId); aCallback->Done(rv, nodeId); return rv; } NS_IMETHODIMP GeckoMediaPluginServiceParent::UpdateTrialCreateState(const nsAString& aKeySystem, uint32_t aState) { @@ -1476,99 +1519,80 @@ struct NodeFilter { } private: const nsTArray<nsCString>& mNodeIDs; }; void GeckoMediaPluginServiceParent::ClearNodeIdAndPlugin(DirectoryFilter& aFilter) { - nsresult rv; + // $profileDir/gmp/$platform/ nsCOMPtr<nsIFile> path; - - // $profileDir/gmp/ - rv = GetStorageDir(getter_AddRefs(path)); - if (NS_FAILED(rv)) { - return; - } - - // $profileDir/gmp/id/ - rv = path->AppendNative(NS_LITERAL_CSTRING("id")); - if (NS_FAILED(rv)) { - return; - } - - // Iterate all sub-folders of $profileDir/gmp/id/ - nsCOMPtr<nsISimpleEnumerator> iter; - rv = path->GetDirectoryEntries(getter_AddRefs(iter)); + nsresult rv = GetStorageDir(getter_AddRefs(path)); if (NS_FAILED(rv)) { return; } - bool hasMore = false; - nsTArray<nsCString> nodeIDsToClear; - while (NS_SUCCEEDED(iter->HasMoreElements(&hasMore)) && hasMore) { - nsCOMPtr<nsISupports> supports; - rv = iter->GetNext(getter_AddRefs(supports)); - if (NS_FAILED(rv)) { - continue; - } + // Iterate all sub-folders of $profileDir/gmp/$platform/, i.e. the dirs in which + // specific GMPs store their data. + DirectoryEnumerator iter(path, DirectoryEnumerator::DirsOnly); + for (nsCOMPtr<nsIFile> pluginDir; (pluginDir = iter.Next()) != nullptr;) { + ClearNodeIdAndPlugin(pluginDir, aFilter); + } +} - // $profileDir/gmp/id/$hash - nsCOMPtr<nsIFile> dirEntry(do_QueryInterface(supports, &rv)); - if (NS_FAILED(rv)) { - continue; - } +void +GeckoMediaPluginServiceParent::ClearNodeIdAndPlugin(nsIFile* aPluginStorageDir, + DirectoryFilter& aFilter) +{ + // $profileDir/gmp/$platform/$gmpName/id/ + nsCOMPtr<nsIFile> path = CloneAndAppend(aPluginStorageDir, NS_LITERAL_STRING("id")); + if (!path) { + return; + } - // Skip non-directory files. - bool isDirectory = false; - rv = dirEntry->IsDirectory(&isDirectory); - if (NS_FAILED(rv) || !isDirectory) { - continue; - } - + // Iterate all sub-folders of $profileDir/gmp/$platform/$gmpName/id/ + nsTArray<nsCString> nodeIDsToClear; + DirectoryEnumerator iter(path, DirectoryEnumerator::DirsOnly); + for (nsCOMPtr<nsIFile> dirEntry; (dirEntry = iter.Next()) != nullptr;) { + // dirEntry is the hash of origins, i.e.: + // $profileDir/gmp/$platform/$gmpName/id/$originHash/ if (!aFilter(dirEntry)) { continue; } - nsAutoCString salt; if (NS_SUCCEEDED(ReadSalt(dirEntry, salt))) { // Keep node IDs to clear data/plugins associated with them later. nodeIDsToClear.AppendElement(salt); // Also remove node IDs from the table. mPersistentStorageAllowed.Remove(salt); } // Now we can remove the directory for the origin pair. if (NS_FAILED(dirEntry->Remove(true))) { NS_WARNING("Failed to delete the directory for the origin pair"); } } - // Kill plugins that have node IDs to be cleared. + // Kill plugin instances that have node IDs being cleared. KillPlugins(mPlugins, mMutex, NodeFilter(nodeIDsToClear)); - // Clear all matching $profileDir/gmp/storage/$nodeId/ - rv = GetStorageDir(getter_AddRefs(path)); - if (NS_FAILED(rv)) { + // Clear all storage in $profileDir/gmp/$platform/$gmpName/storage/$nodeId/ + path = CloneAndAppend(aPluginStorageDir, NS_LITERAL_STRING("storage")); + if (!path) { return; } - rv = path->AppendNative(NS_LITERAL_CSTRING("storage")); - if (NS_FAILED(rv)) { - return; - } - - for (size_t i = 0; i < nodeIDsToClear.Length(); i++) { + for (const nsCString& nodeId : nodeIDsToClear) { nsCOMPtr<nsIFile> dirEntry; - rv = path->Clone(getter_AddRefs(dirEntry)); + nsresult rv = path->Clone(getter_AddRefs(dirEntry)); if (NS_FAILED(rv)) { continue; } - rv = dirEntry->AppendNative(nodeIDsToClear[i]); + rv = dirEntry->AppendNative(nodeId); if (NS_FAILED(rv)) { continue; } if (NS_FAILED(DeleteDir(dirEntry))) { NS_WARNING("Failed to delete GMP storage directory for the node"); } } @@ -1593,91 +1617,68 @@ GeckoMediaPluginServiceParent::ForgetThi } void GeckoMediaPluginServiceParent::ClearRecentHistoryOnGMPThread(PRTime aSince) { MOZ_ASSERT(NS_GetCurrentThread() == mGMPThread); LOGD(("%s::%s: since=%lld", __CLASS__, __FUNCTION__, (int64_t)aSince)); - nsCOMPtr<nsIFile> storagePath; - nsCOMPtr<nsIFile> temp; - if (NS_SUCCEEDED(GetStorageDir(getter_AddRefs(temp))) && - NS_SUCCEEDED(temp->AppendNative(NS_LITERAL_CSTRING("storage")))) { - storagePath = temp.forget(); - } - struct MTimeFilter : public DirectoryFilter { - explicit MTimeFilter(PRTime aSince, already_AddRefed<nsIFile> aPath) - : mSince(aSince), mStoragePath(aPath) {} + explicit MTimeFilter(PRTime aSince) + : mSince(aSince) {} // Return true if any files under aPath is modified after |mSince|. bool IsModifiedAfter(nsIFile* aPath) { PRTime lastModified; nsresult rv = aPath->GetLastModifiedTime(&lastModified); if (NS_SUCCEEDED(rv) && lastModified >= mSince) { return true; } - // Check sub-directories recursively - nsCOMPtr<nsISimpleEnumerator> iter; - rv = aPath->GetDirectoryEntries(getter_AddRefs(iter)); - if (NS_FAILED(rv)) { - return false; - } - - bool hasMore = false; - while (NS_SUCCEEDED(iter->HasMoreElements(&hasMore)) && hasMore) { - nsCOMPtr<nsISupports> supports; - rv = iter->GetNext(getter_AddRefs(supports)); - if (NS_FAILED(rv)) { - continue; - } - - nsCOMPtr<nsIFile> path(do_QueryInterface(supports, &rv)); - if (NS_FAILED(rv)) { - continue; - } - - if (IsModifiedAfter(path)) { + DirectoryEnumerator iter(aPath, DirectoryEnumerator::FilesAndDirs); + for (nsCOMPtr<nsIFile> dirEntry; (dirEntry = iter.Next()) != nullptr;) { + if (IsModifiedAfter(dirEntry)) { return true; } } return false; } - // |aPath| is $profileDir/gmp/id/$hash + // |aPath| is $profileDir/gmp/$platform/$gmpName/id/$originHash/ virtual bool operator()(nsIFile* aPath) { if (IsModifiedAfter(aPath)) { return true; } nsAutoCString salt; - nsresult rv = ReadSalt(aPath, salt); - if (NS_FAILED(rv)) { + if (NS_FAILED(ReadSalt(aPath, salt))) { return false; } - // $profileDir/gmp/storage/ - if (!mStoragePath) { + // $profileDir/gmp/$platform/$gmpName/id/ + nsCOMPtr<nsIFile> idDir; + if (NS_FAILED(aPath->GetParent(getter_AddRefs(idDir)))) { return false; } - // $profileDir/gmp/storage/$nodeId/ - nsCOMPtr<nsIFile> path; - rv = mStoragePath->Clone(getter_AddRefs(path)); - if (NS_FAILED(rv)) { + // $profileDir/gmp/$platform/$gmpName/ + nsCOMPtr<nsIFile> temp; + if (NS_FAILED(idDir->GetParent(getter_AddRefs(temp)))) { return false; } - rv = path->AppendNative(salt); - return NS_SUCCEEDED(rv) && IsModifiedAfter(path); + // $profileDir/gmp/$platform/$gmpName/storage/ + if (NS_FAILED(temp->Append(NS_LITERAL_STRING("storage")))) { + return false; + } + // $profileDir/gmp/$platform/$gmpName/storage/$originSalt + return NS_SUCCEEDED(temp->AppendNative(salt)) && IsModifiedAfter(temp); } private: const PRTime mSince; - const nsCOMPtr<nsIFile> mStoragePath; - } filter(aSince, storagePath.forget()); + } filter(aSince); ClearNodeIdAndPlugin(filter); NS_DispatchToMainThread(new NotifyObserversTask("gmp-clear-storage-complete"), NS_DISPATCH_NORMAL); } NS_IMETHODIMP GeckoMediaPluginServiceParent::ForgetThisSite(const nsAString& aSite) @@ -1696,17 +1697,17 @@ void GeckoMediaPluginServiceParent::ClearStorage() { MOZ_ASSERT(NS_GetCurrentThread() == mGMPThread); LOGD(("%s::%s", __CLASS__, __FUNCTION__)); // Kill plugins with valid nodeIDs. KillPlugins(mPlugins, mMutex, &IsNodeIdValid); - nsCOMPtr<nsIFile> path; // $profileDir/gmp/ + nsCOMPtr<nsIFile> path; // $profileDir/gmp/$platform/ nsresult rv = GetStorageDir(getter_AddRefs(path)); if (NS_WARN_IF(NS_FAILED(rv))) { return; } if (NS_FAILED(DeleteDir(path))) { NS_WARNING("Failed to delete GMP storage directory"); } @@ -1741,20 +1742,21 @@ GMPServiceParent::RecvLoadGMP(const nsCS *aPluginId = gmp->GetPluginId(); return aAlreadyBridgedTo.Contains(*aId) || gmp->Bridge(this); } bool GMPServiceParent::RecvGetGMPNodeId(const nsString& aOrigin, const nsString& aTopLevelOrigin, + const nsString& aGMPName, const bool& aInPrivateBrowsing, nsCString* aID) { - nsresult rv = mService->GetNodeId(aOrigin, aTopLevelOrigin, + nsresult rv = mService->GetNodeId(aOrigin, aTopLevelOrigin, aGMPName, aInPrivateBrowsing, *aID); return NS_SUCCEEDED(rv); } bool GMPServiceParent::RecvUpdateGMPTrialCreateState(const nsString& aKeySystem, const uint32_t& aState) {
--- a/dom/media/gmp/GMPServiceParent.h +++ b/dom/media/gmp/GMPServiceParent.h @@ -36,16 +36,17 @@ public: // mozIGeckoMediaPluginService NS_IMETHOD GetPluginVersionForAPI(const nsACString& aAPI, nsTArray<nsCString>* aTags, bool* aHasPlugin, nsACString& aOutVersion) override; NS_IMETHOD GetNodeId(const nsAString& aOrigin, const nsAString& aTopLevelOrigin, + const nsAString& aGMPName, bool aInPrivateBrowsingMode, UniquePtr<GetNodeIdCallback>&& aCallback) override; NS_IMETHOD UpdateTrialCreateState(const nsAString& aKeySystem, uint32_t aState) override; NS_DECL_MOZIGECKOMEDIAPLUGINCHROMESERVICE NS_DECL_NSIOBSERVER @@ -68,16 +69,17 @@ private: const nsCString& aAPI, const nsTArray<nsCString>& aTags); GMPParent* FindPluginForAPIFrom(size_t aSearchStartIndex, const nsCString& aAPI, const nsTArray<nsCString>& aTags, size_t* aOutPluginIndex); nsresult GetNodeId(const nsAString& aOrigin, const nsAString& aTopLevelOrigin, + const nsAString& aGMPName, bool aInPrivateBrowsing, nsACString& aOutId); void UnloadPlugins(); void CrashPlugins(); void NotifySyncShutdownComplete(); void NotifyAsyncShutdownComplete(); void LoadFromEnvironment(); @@ -90,17 +92,18 @@ private: nsresult SetAsyncShutdownTimeout(); struct DirectoryFilter { virtual bool operator()(nsIFile* aPath) = 0; ~DirectoryFilter() {} }; void ClearNodeIdAndPlugin(DirectoryFilter& aFilter); - + void ClearNodeIdAndPlugin(nsIFile* aPluginStorageDir, + DirectoryFilter& aFilter); void ForgetThisSiteOnGMPThread(const nsACString& aOrigin); void ClearRecentHistoryOnGMPThread(PRTime aSince); protected: friend class GMPParent; void ReAddOnGMPThread(const RefPtr<GMPParent>& aOld); void PluginTerminated(const RefPtr<GMPParent>& aOld); virtual void InitializePlugins() override; @@ -210,16 +213,17 @@ public: const nsCString& aApi, nsTArray<nsCString>&& aTags, nsTArray<ProcessId>&& aAlreadyBridgedTo, base::ProcessId* aID, nsCString* aDisplayName, uint32_t* aPluginId) override; virtual bool RecvGetGMPNodeId(const nsString& aOrigin, const nsString& aTopLevelOrigin, + const nsString& aGMPName, const bool& aInPrivateBrowsing, nsCString* aID) override; static bool RecvGetGMPPluginVersionForAPI(const nsCString& aAPI, nsTArray<nsCString>&& aTags, bool* aHasPlugin, nsCString* aVersion); virtual bool RecvUpdateGMPTrialCreateState(const nsString& aKeySystem, const uint32_t& aState) override;
--- a/dom/media/gmp/GMPStorageParent.cpp +++ b/dom/media/gmp/GMPStorageParent.cpp @@ -27,20 +27,22 @@ namespace mozilla { extern LogModule* GetGMPLog(); #define LOGD(msg) MOZ_LOG(GetGMPLog(), mozilla::LogLevel::Debug, msg) #define LOG(level, msg) MOZ_LOG(GetGMPLog(), (level), msg) namespace gmp { -// We store the records in files in the profile dir. -// $profileDir/gmp/storage/$nodeId/ +// We store the records for a given GMP as files in the profile dir. +// $profileDir/gmp/$platform/$gmpName/storage/$nodeId/ static nsresult -GetGMPStorageDir(nsIFile** aTempDir, const nsCString& aNodeId) +GetGMPStorageDir(nsIFile** aTempDir, + const nsString& aGMPName, + const nsCString& aNodeId) { if (NS_WARN_IF(!aTempDir)) { return NS_ERROR_INVALID_ARG; } nsCOMPtr<mozIGeckoMediaPluginChromeService> mps = do_GetService("@mozilla.org/gecko-media-plugin-service;1"); if (NS_WARN_IF(!mps)) { @@ -48,16 +50,26 @@ GetGMPStorageDir(nsIFile** aTempDir, con } nsCOMPtr<nsIFile> tmpFile; nsresult rv = mps->GetStorageDir(getter_AddRefs(tmpFile)); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } + rv = tmpFile->Append(aGMPName); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + rv = tmpFile->Create(nsIFile::DIRECTORY_TYPE, 0700); + if (rv != NS_ERROR_FILE_ALREADY_EXISTS && NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + rv = tmpFile->AppendNative(NS_LITERAL_CSTRING("storage")); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } rv = tmpFile->Create(nsIFile::DIRECTORY_TYPE, 0700); if (rv != NS_ERROR_FILE_ALREADY_EXISTS && NS_WARN_IF(NS_FAILED(rv))) { return rv; @@ -82,18 +94,20 @@ GetGMPStorageDir(nsIFile** aTempDir, con // the profile directory. The record name is a hash of the filename, // and we resolve hash collisions by just adding 1 to the hash code. // The format of records on disk is: // 4 byte, uint32_t $recordNameLength, in little-endian byte order, // record name (i.e. $recordNameLength bytes, no null terminator) // record bytes (entire remainder of file) class GMPDiskStorage : public GMPStorage { public: - explicit GMPDiskStorage(const nsCString& aNodeId) + explicit GMPDiskStorage(const nsCString& aNodeId, + const nsString& aGMPName) : mNodeId(aNodeId) + , mGMPName(aGMPName) { } ~GMPDiskStorage() { // Close all open file handles. for (auto iter = mRecords.ConstIter(); !iter.Done(); iter.Next()) { Record* record = iter.UserData(); if (record->mFileDesc) { @@ -101,39 +115,23 @@ public: record->mFileDesc = nullptr; } } } nsresult Init() { // Build our index of records on disk. nsCOMPtr<nsIFile> storageDir; - nsresult rv = GetGMPStorageDir(getter_AddRefs(storageDir), mNodeId); + nsresult rv = GetGMPStorageDir(getter_AddRefs(storageDir), mGMPName, mNodeId); if (NS_WARN_IF(NS_FAILED(rv))) { return NS_ERROR_FAILURE; } - nsCOMPtr<nsISimpleEnumerator> iter; - rv = storageDir->GetDirectoryEntries(getter_AddRefs(iter)); - if (NS_FAILED(rv)) { - return NS_ERROR_FAILURE; - } - - bool hasMore; - while (NS_SUCCEEDED(iter->HasMoreElements(&hasMore)) && hasMore) { - nsCOMPtr<nsISupports> supports; - rv = iter->GetNext(getter_AddRefs(supports)); - if (NS_FAILED(rv)) { - continue; - } - nsCOMPtr<nsIFile> dirEntry(do_QueryInterface(supports, &rv)); - if (NS_FAILED(rv)) { - continue; - } - + DirectoryEnumerator iter(storageDir, DirectoryEnumerator::FilesAndDirs); + for (nsCOMPtr<nsIFile> dirEntry; (dirEntry = iter.Next()) != nullptr;) { PRFileDesc* fd = nullptr; if (NS_FAILED(dirEntry->OpenNSPRFileDesc(PR_RDONLY, 0, &fd))) { continue; } int32_t recordLength = 0; nsCString recordName; nsresult err = ReadRecordMetadata(fd, recordLength, recordName); PR_Close(fd); @@ -329,17 +327,17 @@ private: // We store records in a file which is a hash of the record name. // If there is a hash collision, we just keep adding 1 to the hash // code, until we find a free slot. nsresult GetUnusedFilename(const nsACString& aRecordName, nsString& aOutFilename) { nsCOMPtr<nsIFile> storageDir; - nsresult rv = GetGMPStorageDir(getter_AddRefs(storageDir), mNodeId); + nsresult rv = GetGMPStorageDir(getter_AddRefs(storageDir), mGMPName, mNodeId); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } uint64_t recordNameHash = HashString(PromiseFlatCString(aRecordName).get()); for (int i = 0; i < 1000000; i++) { nsCOMPtr<nsIFile> f; rv = storageDir->Clone(getter_AddRefs(f)); @@ -374,17 +372,17 @@ private: nsresult OpenStorageFile(const nsAString& aFileLeafName, const OpenFileMode aMode, PRFileDesc** aOutFD) { MOZ_ASSERT(aOutFD); nsCOMPtr<nsIFile> f; - nsresult rv = GetGMPStorageDir(getter_AddRefs(f), mNodeId); + nsresult rv = GetGMPStorageDir(getter_AddRefs(f), mGMPName, mNodeId); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } f->Append(aFileLeafName); auto mode = PR_RDWR | PR_CREATE_FILE; if (aMode == Truncate) { mode |= PR_TRUNCATE; @@ -451,17 +449,17 @@ private: } return NS_OK; } nsresult RemoveStorageFile(const nsString& aFilename) { nsCOMPtr<nsIFile> f; - nsresult rv = GetGMPStorageDir(getter_AddRefs(f), mNodeId); + nsresult rv = GetGMPStorageDir(getter_AddRefs(f), mGMPName, mNodeId); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } rv = f->Append(aFilename); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } return f->Remove(/* bool recursive= */ false); @@ -480,16 +478,17 @@ private: nsString mFilename; nsCString mRecordName; PRFileDesc* mFileDesc; }; // Hash record name to record data. nsClassHashtable<nsCStringHashKey, Record> mRecords; const nsAutoCString mNodeId; + const nsString mGMPName; }; class GMPMemoryStorage : public GMPStorage { public: GMPErr Open(const nsCString& aRecordName) override { MOZ_ASSERT(!IsOpen(aRecordName)); @@ -587,17 +586,18 @@ GMPStorageParent::Init() return NS_ERROR_FAILURE; } bool persistent = false; if (NS_WARN_IF(NS_FAILED(mps->IsPersistentStorageAllowed(mNodeId, &persistent)))) { return NS_ERROR_FAILURE; } if (persistent) { - UniquePtr<GMPDiskStorage> storage = MakeUnique<GMPDiskStorage>(mNodeId); + UniquePtr<GMPDiskStorage> storage = + MakeUnique<GMPDiskStorage>(mNodeId, mPlugin->GetPluginBaseName()); if (NS_FAILED(storage->Init())) { NS_WARNING("Failed to initialize on disk GMP storage"); return NS_ERROR_FAILURE; } mStorage = Move(storage); } else { mStorage = MakeUnique<GMPMemoryStorage>(); }
--- a/dom/media/gmp/GMPUtils.cpp +++ b/dom/media/gmp/GMPUtils.cpp @@ -6,16 +6,17 @@ #include "GMPUtils.h" #include "nsDirectoryServiceDefs.h" #include "nsIFile.h" #include "nsCOMPtr.h" #include "nsLiteralString.h" #include "nsCRTGlue.h" #include "mozilla/Base64.h" +#include "nsISimpleEnumerator.h" namespace mozilla { bool GetEMEVoucherPath(nsIFile** aPath) { nsCOMPtr<nsIFile> path; NS_GetSpecialDirectory(NS_GRE_DIR, getter_AddRefs(path)); @@ -66,9 +67,46 @@ ToBase64(const nsTArray<uint8_t>& aBytes bool FileExists(nsIFile* aFile) { bool exists = false; return aFile && NS_SUCCEEDED(aFile->Exists(&exists)) && exists; } +DirectoryEnumerator::DirectoryEnumerator(nsIFile* aPath, Mode aMode) + : mMode(aMode) +{ + aPath->GetDirectoryEntries(getter_AddRefs(mIter)); +} + +already_AddRefed<nsIFile> +DirectoryEnumerator::Next() +{ + if (!mIter) { + return nullptr; + } + bool hasMore = false; + while (NS_SUCCEEDED(mIter->HasMoreElements(&hasMore)) && hasMore) { + nsCOMPtr<nsISupports> supports; + nsresult rv = mIter->GetNext(getter_AddRefs(supports)); + if (NS_FAILED(rv)) { + continue; + } + + nsCOMPtr<nsIFile> path(do_QueryInterface(supports, &rv)); + if (NS_FAILED(rv)) { + continue; + } + + if (mMode == DirsOnly) { + bool isDirectory = false; + rv = path->IsDirectory(&isDirectory); + if (NS_FAILED(rv) || !isDirectory) { + continue; + } + } + return path.forget(); + } + return nullptr; +} + } // namespace mozilla
--- a/dom/media/gmp/GMPUtils.h +++ b/dom/media/gmp/GMPUtils.h @@ -3,19 +3,21 @@ * 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 GMPUtils_h_ #define GMPUtils_h_ #include "mozilla/UniquePtr.h" #include "nsTArray.h" +#include "nsCOMPtr.h" class nsIFile; class nsCString; +class nsISimpleEnumerator; namespace mozilla { template<typename T> struct DestroyPolicy { void operator()(T* aGMPObject) const { aGMPObject->Destroy(); @@ -35,11 +37,29 @@ SplitAt(const char* aDelims, nsTArray<nsCString>& aOutTokens); nsCString ToBase64(const nsTArray<uint8_t>& aBytes); bool FileExists(nsIFile* aFile); +// Enumerate directory entries for a specified path. +class DirectoryEnumerator { +public: + + enum Mode { + DirsOnly, // Enumeration only includes directories. + FilesAndDirs // Enumeration includes directories and non-directory files. + }; + + DirectoryEnumerator(nsIFile* aPath, Mode aMode); + + already_AddRefed<nsIFile> Next(); + +private: + Mode mMode; + nsCOMPtr<nsISimpleEnumerator> mIter; +}; + } // namespace mozilla #endif
--- a/dom/media/gmp/PGMPService.ipdl +++ b/dom/media/gmp/PGMPService.ipdl @@ -14,16 +14,17 @@ sync protocol PGMPService { parent spawns PGMP as child; parent: sync LoadGMP(nsCString nodeId, nsCString api, nsCString[] tags, ProcessId[] alreadyBridgedTo) returns (ProcessId id, nsCString displayName, uint32_t pluginId); sync GetGMPNodeId(nsString origin, nsString topLevelOrigin, + nsString gmpName, bool inPrivateBrowsing) returns (nsCString id); async UpdateGMPTrialCreateState(nsString keySystem, uint32_t status); }; } // namespace gmp } // namespace mozilla
--- a/dom/media/gmp/mozIGeckoMediaPluginService.idl +++ b/dom/media/gmp/mozIGeckoMediaPluginService.idl @@ -47,17 +47,17 @@ public: [ptr] native TagArray(nsTArray<nsCString>); native GetGMPDecryptorCallback(mozilla::UniquePtr<GetGMPDecryptorCallback>&&); native GetGMPAudioDecoderCallback(mozilla::UniquePtr<GetGMPAudioDecoderCallback>&&); native GetGMPVideoDecoderCallback(mozilla::UniquePtr<GetGMPVideoDecoderCallback>&&); native GetGMPVideoEncoderCallback(mozilla::UniquePtr<GetGMPVideoEncoderCallback>&&); native GetNodeIdCallback(mozilla::UniquePtr<GetNodeIdCallback>&&); -[scriptable, uuid(661492d6-726b-4ba0-8e6e-14bfaf2b62e4)] +[scriptable, uuid(b5492915-2f0e-4973-9f91-a6fe61ac4749)] interface mozIGeckoMediaPluginService : nsISupports { /** * The GMP thread. Callable from any thread. */ readonly attribute nsIThread thread; @@ -140,16 +140,17 @@ interface mozIGeckoMediaPluginService : in GetGMPDecryptorCallback callback); /** * Gets the NodeId for a (origin, urlbarOrigin, isInprivateBrowsing) tuple. */ [noscript] void getNodeId(in AString origin, in AString topLevelOrigin, + in AString gmpName, in bool inPrivateBrowsingMode, in GetNodeIdCallback callback); /** * Stores the result of trying to create a decoder for the given keysystem. */ [noscript] void updateTrialCreateState(in AString keySystem, in uint32_t status);
--- a/dom/media/gtest/TestGMPCrossOrigin.cpp +++ b/dom/media/gtest/TestGMPCrossOrigin.cpp @@ -268,34 +268,41 @@ EnumerateDir(nsIFile* aPath, T&& aDirIte } aDirIter(entry); } return NS_OK; } /** - * Enumerate files under $profileDir/gmp/$aDir/ (non-recursive). + * Enumerate files under $profileDir/gmp/$platform/gmp-fake/$aDir/ (non-recursive). */ template<typename T> static nsresult EnumerateGMPStorageDir(const nsACString& aDir, T&& aDirIter) { RefPtr<GeckoMediaPluginServiceParent> service = GeckoMediaPluginServiceParent::GetSingleton(); MOZ_ASSERT(service); - // $profileDir/gmp/ + // $profileDir/gmp/$platform/ nsCOMPtr<nsIFile> path; nsresult rv = service->GetStorageDir(getter_AddRefs(path)); if (NS_FAILED(rv)) { return rv; } - // $profileDir/gmp/$aDir/ + + // $profileDir/gmp/$platform/gmp-fake/ + rv = path->Append(NS_LITERAL_STRING("gmp-fake")); + if (NS_FAILED(rv)) { + return rv; + } + + // $profileDir/gmp/$platform/gmp-fake/$aDir/ rv = path->AppendNative(aDir); if (NS_FAILED(rv)) { return rv; } return EnumerateDir(path, aDirIter); } @@ -464,16 +471,17 @@ GetNodeId(const nsAString& aOrigin, nsCString nodeId; nsresult result; UniquePtr<GetNodeIdCallback> callback(new TestGetNodeIdCallback(nodeId, result)); // We rely on the fact that the GetNodeId implementation for // GeckoMediaPluginServiceParent is synchronous. nsresult rv = service->GetNodeId(aOrigin, aTopLevelOrigin, + NS_LITERAL_STRING("gmp-fake"), aInPBMode, Move(callback)); EXPECT_TRUE(NS_SUCCEEDED(rv) && NS_SUCCEEDED(result)); return nodeId; } static bool IsGMPStorageIsEmpty() @@ -815,20 +823,20 @@ class GMPStorageTest : public GMPDecrypt rv = EnumerateGMPStorageDir( NS_LITERAL_CSTRING("storage"), StorageVerifier(aSiteInfo)); EXPECT_TRUE(NS_SUCCEEDED(rv)); } /** * 1. Generate some storage data. - * 2. Find the max mtime |t| in $profileDir/gmp/id/. + * 2. Find the max mtime |t| in $profileDir/gmp/$platform/gmp-fake/id/. * 3. Pass |t| to clear recent history. - * 4. Check if all directories in $profileDir/gmp/id/ and - * $profileDir/gmp/storage are removed. + * 4. Check if all directories in $profileDir/gmp/$platform/gmp-fake/id/ and + * $profileDir/gmp/$platform/gmp-fake/storage are removed. */ void TestClearRecentHistory1() { AssertIsOnGMPThread(); EXPECT_TRUE(IsGMPStorageIsEmpty()); // Generate storage data for some site. nsCOMPtr<nsIRunnable> r = NS_NewRunnableMethod( this, &GMPStorageTest::TestClearRecentHistory1_Clear); @@ -837,20 +845,20 @@ class GMPStorageTest : public GMPDecrypt CreateDecryptor(NS_LITERAL_STRING("http://example1.com"), NS_LITERAL_STRING("http://example2.com"), false, NS_LITERAL_CSTRING("test-storage")); } /** * 1. Generate some storage data. - * 2. Find the max mtime |t| in $profileDir/gmp/storage/. + * 2. Find the max mtime |t| in $profileDir/gmp/$platform/gmp-fake/storage/. * 3. Pass |t| to clear recent history. - * 4. Check if all directories in $profileDir/gmp/id/ and - * $profileDir/gmp/storage are removed. + * 4. Check if all directories in $profileDir/gmp/$platform/gmp-fake/id/ and + * $profileDir/gmp/$platform/gmp-fake/storage are removed. */ void TestClearRecentHistory2() { AssertIsOnGMPThread(); EXPECT_TRUE(IsGMPStorageIsEmpty()); // Generate storage data for some site. nsCOMPtr<nsIRunnable> r = NS_NewRunnableMethod( this, &GMPStorageTest::TestClearRecentHistory2_Clear); @@ -859,20 +867,20 @@ class GMPStorageTest : public GMPDecrypt CreateDecryptor(NS_LITERAL_STRING("http://example1.com"), NS_LITERAL_STRING("http://example2.com"), false, NS_LITERAL_CSTRING("test-storage")); } /** * 1. Generate some storage data. - * 2. Find the max mtime |t| in $profileDir/gmp/storage/. + * 2. Find the max mtime |t| in $profileDir/gmp/$platform/gmp-fake/storage/. * 3. Pass |t+1| to clear recent history. - * 4. Check if all directories in $profileDir/gmp/id/ and - * $profileDir/gmp/storage remain unchanged. + * 4. Check if all directories in $profileDir/gmp/$platform/gmp-fake/id/ and + * $profileDir/gmp/$platform/gmp-fake/storage remain unchanged. */ void TestClearRecentHistory3() { AssertIsOnGMPThread(); EXPECT_TRUE(IsGMPStorageIsEmpty()); // Generate storage data for some site. nsCOMPtr<nsIRunnable> r = NS_NewRunnableMethod( this, &GMPStorageTest::TestClearRecentHistory3_Clear); @@ -943,39 +951,39 @@ class GMPStorageTest : public GMPDecrypt private: int mCount; }; void TestClearRecentHistory_CheckEmpty() { FileCounter c1; nsresult rv = EnumerateGMPStorageDir(NS_LITERAL_CSTRING("id"), c1); EXPECT_TRUE(NS_SUCCEEDED(rv)); - // There should be no files under $profileDir/gmp/id/ + // There should be no files under $profileDir/gmp/$platform/gmp-fake/id/ EXPECT_EQ(c1.GetCount(), 0); FileCounter c2; rv = EnumerateGMPStorageDir(NS_LITERAL_CSTRING("storage"), c2); EXPECT_TRUE(NS_SUCCEEDED(rv)); - // There should be no files under $profileDir/gmp/storage/ + // There should be no files under $profileDir/gmp/$platform/gmp-fake/storage/ EXPECT_EQ(c2.GetCount(), 0); SetFinished(); } void TestClearRecentHistory_CheckNonEmpty() { FileCounter c1; nsresult rv = EnumerateGMPStorageDir(NS_LITERAL_CSTRING("id"), c1); EXPECT_TRUE(NS_SUCCEEDED(rv)); - // There should be one directory under $profileDir/gmp/id/ + // There should be one directory under $profileDir/gmp/$platform/gmp-fake/id/ EXPECT_EQ(c1.GetCount(), 1); FileCounter c2; rv = EnumerateGMPStorageDir(NS_LITERAL_CSTRING("storage"), c2); EXPECT_TRUE(NS_SUCCEEDED(rv)); - // There should be one directory under $profileDir/gmp/storage/ + // There should be one directory under $profileDir/gmp/$platform/gmp-fake/storage/ EXPECT_EQ(c2.GetCount(), 1); SetFinished(); } void TestCrossOriginStorage() { EXPECT_TRUE(!mDecryptor);
--- a/dom/media/test/mochitest.ini +++ b/dom/media/test/mochitest.ini @@ -614,16 +614,18 @@ skip-if = (toolkit == 'android' && proce [test_defaultMuted.html] [test_delay_load.html] skip-if = buildapp == 'b2g' && toolkit != 'gonk' # bug 1082984 [test_dormant_playback.html] skip-if = (os == 'win' && os_version == '5.1') || (os != 'win' && toolkit != 'gonk') [test_eme_session_callable_value.html] [test_eme_canvas_blocked.html] skip-if = toolkit == 'android' # bug 1149374 +[test_eme_key_ids_initdata.html] +skip-if = toolkit == 'android' # bug 1149374 [test_eme_non_mse_fails.html] skip-if = toolkit == 'android' # bug 1149374 [test_eme_request_notifications.html] skip-if = toolkit == 'android' # bug 1149374 [test_eme_persistent_sessions.html] skip-if = toolkit == 'android' # bug 1149374 [test_eme_playback.html] skip-if = toolkit == 'android' || toolkit == 'gonk' # android: bug 1149374; gonk: bug 1193351
new file mode 100644 --- /dev/null +++ b/dom/media/test/test_eme_key_ids_initdata.html @@ -0,0 +1,111 @@ +<!DOCTYPE HTML> +<html> +<head> + <title>Test Encrypted Media Extensions</title> + <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> + <script type="text/javascript" src="manifest.js"></script> + <script type="text/javascript" src="eme.js"></script> +</head> +<body> +<pre id="test"> +<script class="testbody" type="text/javascript"> + +var tests = [ + { + name: "One keyId", + initData: '{"kids":["LwVHf8JLtPrv2GUXFW2v_A"]}', + expectedRequest: '{"kids":["LwVHf8JLtPrv2GUXFW2v_A"],"type":"temporary"}', + sessionType: 'temporary', + expectPass: true, + }, + { + name: "Two keyIds", + initData: '{"kids":["LwVHf8JLtPrv2GUXFW2v_A", "0DdtU9od-Bh5L3xbv0Xf_A"]}', + expectedRequest: '{"kids":["LwVHf8JLtPrv2GUXFW2v_A","0DdtU9od-Bh5L3xbv0Xf_A"],"type":"temporary"}', + sessionType: 'temporary', + expectPass: true, + }, + { + name: "Two keyIds, temporary session", + initData: '{"type":"temporary", "kids":["LwVHf8JLtPrv2GUXFW2v_A", "0DdtU9od-Bh5L3xbv0Xf_A"]}', + expectedRequest: '{"kids":["LwVHf8JLtPrv2GUXFW2v_A","0DdtU9od-Bh5L3xbv0Xf_A"],"type":"temporary"}', + sessionType: 'temporary', + expectPass: true, + }, + { + name: "Two keyIds, persistent session, type before kids", + initData: '{"type":"persistent", "kids":["LwVHf8JLtPrv2GUXFW2v_A", "0DdtU9od-Bh5L3xbv0Xf_A"]}', + expectedRequest: '{"kids":["LwVHf8JLtPrv2GUXFW2v_A","0DdtU9od-Bh5L3xbv0Xf_A"],"type":"persistent"}', + sessionType: 'persistent', + expectPass: true, + }, + { + name: "Invalid keyId", + initData: '{"kids":["0"]}', + sessionType: 'temporary', + expectPass: false, + }, + { + name: "Empty keyId", + initData: '{"kids":[""]}', + sessionType: 'temporary', + expectPass: false, + }, + { + name: "SessionType in license doesn't match MediaKeySession's sessionType", + initData: '{"kids":["LwVHf8JLtPrv2GUXFW2v_A"]}', + sessionType: 'persistent', + expectPass: false, + }, + { + name: "One valid and one invalid kid", + initData: '{"kids":["LwVHf8JLtPrv2GUXFW2v_A", "invalid"]}', + expectedRequest: '{"kids":["LwVHf8JLtPrv2GUXFW2v_A"],"type":"temporary"}', + sessionType: 'temporary', + expectPass: true, + }, + { + name: "Invalid initData", + initData: 'invalid initData', + sessionType: 'temporary', + expectPass: false, + }, +]; + +function Test(test) { + return new Promise(function(resolve, reject) { + navigator.requestMediaKeySystemAccess('org.w3.clearkey', [{initDataTypes: ['keyids']}]).then( + (access) => access.createMediaKeys() + ).then( + (mediaKeys) => { + var session = mediaKeys.createSession(test.sessionType); + var initData = new TextEncoder().encode(test.initData); + session.addEventListener("message", function(event) { + is(event.messageType, "license-request", "'" + test.name + "' MediaKeyMessage type should be license-request."); + var text = new TextDecoder().decode(event.message); + is(text, test.expectedRequest, "'" + test.name + "' got expected response."); + is(text == test.expectedRequest, test.expectPass, + "'" + test.name + "' expected to " + (test.expectPass ? "pass" : "fail")); + resolve(); + }); + return session.generateRequest('keyids', initData); + } + ).catch((x) => { + ok(!test.expectPass, "'" + test.name + "' expected to fail."); + resolve(); + }); + }); +} + +function beginTest() { + Promise.all(tests.map(Test)).then(function() { SimpleTest.finish(); }); +} + +SimpleTest.waitForExplicitFinish(); +SetupEMEPref(beginTest); + +</script> +</pre> +</body> +</html>
--- a/dom/plugins/ipc/PPluginModule.ipdl +++ b/dom/plugins/ipc/PPluginModule.ipdl @@ -2,16 +2,17 @@ /* 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 protocol PPluginInstance; include protocol PPluginScriptableObject; include protocol PCrashReporter; include protocol PContent; +include ProfilerTypes; using NPError from "npapi.h"; using NPNVariable from "npapi.h"; using mozilla::dom::NativeThreadId from "mozilla/dom/TabMessageUtils.h"; using class mac_plugin_interposing::NSCursorInfo from "mozilla/plugins/PluginMessageUtils.h"; using struct nsID from "nsID.h"; namespace mozilla { @@ -88,18 +89,17 @@ child: async SetParentHangTimeout(uint32_t seconds); intr PCrashReporter() returns (NativeThreadId tid, uint32_t processType); /** * Control the Gecko Profiler in the plugin process. */ - async StartProfiler(uint32_t aEntries, double aInterval, nsCString[] aFeatures, - nsCString[] aThreadNameFilters); + async StartProfiler(ProfilerInitParams params); async StopProfiler(); async GatherProfile(); async SettingChanged(PluginSettings settings); parent: async NP_InitializeResult(NPError aError);
--- a/dom/plugins/ipc/PluginModuleChild.cpp +++ b/dom/plugins/ipc/PluginModuleChild.cpp @@ -2519,32 +2519,30 @@ PluginModuleChild::RecvProcessNativeEven #ifdef MOZ_WIDGET_COCOA void PluginModuleChild::ProcessNativeEvents() { CallProcessSomeEvents(); } #endif bool -PluginModuleChild::RecvStartProfiler(const uint32_t& aEntries, - const double& aInterval, - nsTArray<nsCString>&& aFeatures, - nsTArray<nsCString>&& aThreadNameFilters) +PluginModuleChild::RecvStartProfiler(const ProfilerInitParams& params) { nsTArray<const char*> featureArray; - for (size_t i = 0; i < aFeatures.Length(); ++i) { - featureArray.AppendElement(aFeatures[i].get()); + for (size_t i = 0; i < params.features().Length(); ++i) { + featureArray.AppendElement(params.features()[i].get()); } nsTArray<const char*> threadNameFilterArray; - for (size_t i = 0; i < aThreadNameFilters.Length(); ++i) { - threadNameFilterArray.AppendElement(aThreadNameFilters[i].get()); + for (size_t i = 0; i < params.threadFilters().Length(); ++i) { + threadNameFilterArray.AppendElement(params.threadFilters()[i].get()); } - profiler_start(aEntries, aInterval, featureArray.Elements(), featureArray.Length(), + profiler_start(params.entries(), params.interval(), + featureArray.Elements(), featureArray.Length(), threadNameFilterArray.Elements(), threadNameFilterArray.Length()); return true; } bool PluginModuleChild::RecvStopProfiler() {
--- a/dom/plugins/ipc/PluginModuleChild.h +++ b/dom/plugins/ipc/PluginModuleChild.h @@ -142,20 +142,17 @@ protected: virtual void ActorDestroy(ActorDestroyReason why) override; MOZ_NORETURN void QuickExit(); virtual bool RecvProcessNativeEventsInInterruptCall() override; - virtual bool RecvStartProfiler(const uint32_t& aEntries, - const double& aInterval, - nsTArray<nsCString>&& aFeatures, - nsTArray<nsCString>&& aThreadNameFilters) override; + virtual bool RecvStartProfiler(const ProfilerInitParams& params) override; virtual bool RecvStopProfiler() override; virtual bool RecvGatherProfile() override; public: explicit PluginModuleChild(bool aIsChrome); virtual ~PluginModuleChild(); bool CommonInit(base::ProcessId aParentPid,
--- a/dom/plugins/ipc/PluginModuleParent.cpp +++ b/dom/plugins/ipc/PluginModuleParent.cpp @@ -3145,17 +3145,25 @@ PluginProfilerObserver::Observe(nsISuppo if (!strcmp(aTopic, "profiler-started")) { nsCOMPtr<nsIProfilerStartParams> params(do_QueryInterface(aSubject)); uint32_t entries; double interval; params->GetEntries(&entries); params->GetInterval(&interval); const nsTArray<nsCString>& features = params->GetFeatures(); const nsTArray<nsCString>& threadFilterNames = params->GetThreadFilterNames(); - Unused << mPmp->SendStartProfiler(entries, interval, features, threadFilterNames); + + ProfilerInitParams ipcParams; + ipcParams.enabled() = true; + ipcParams.entries() = entries; + ipcParams.interval() = interval; + ipcParams.features() = features; + ipcParams.threadFilters() = threadFilterNames; + + Unused << mPmp->SendStartProfiler(ipcParams); } else if (!strcmp(aTopic, "profiler-stopped")) { Unused << mPmp->SendStopProfiler(); } else if (!strcmp(aTopic, "profiler-subprocess-gather")) { RefPtr<ProfileGatherer> gatherer = static_cast<ProfileGatherer*>(aSubject); mPmp->GatherAsyncProfile(gatherer); } else if (!strcmp(aTopic, "profiler-subprocess")) { nsCOMPtr<nsIProfileSaveEvent> pse = do_QueryInterface(aSubject); mPmp->GatheredAsyncProfile(pse);
--- a/dom/push/PushService.jsm +++ b/dom/push/PushService.jsm @@ -273,17 +273,17 @@ this.PushService = { case "perm-changed": this._onPermissionChange(aSubject, aData).catch(error => { console.error("onPermissionChange: Error updating registrations:", error); }) break; case "clear-origin-data": - this._clearOriginData(data).catch(error => { + this._clearOriginData(aData).catch(error => { console.error("clearOriginData: Error clearing origin data:", error); }); break; } }, _clearOriginData: function(data) { console.log("clearOriginData()");
--- a/dom/workers/ServiceWorkerManager.cpp +++ b/dom/workers/ServiceWorkerManager.cpp @@ -128,128 +128,176 @@ struct ServiceWorkerManager::Registratio nsTArray<nsCString> mOrderedScopes; // Scope to registration. // The scope should be a fully qualified valid URL. nsRefPtrHashtable<nsCStringHashKey, ServiceWorkerRegistrationInfo> mInfos; // Maps scopes to job queues. nsClassHashtable<nsCStringHashKey, ServiceWorkerJobQueue> mJobQueues; - - nsDataHashtable<nsCStringHashKey, bool> mSetOfScopesBeingUpdated; }; struct ServiceWorkerManager::PendingOperation final { nsCOMPtr<nsIRunnable> mRunnable; ServiceWorkerJobQueue* mQueue; RefPtr<ServiceWorkerJob> mJob; ServiceWorkerRegistrationData mRegistration; }; class ServiceWorkerJob : public nsISupports { + friend class ServiceWorkerJobQueue; + +public: + NS_DECL_ISUPPORTS + + enum Type + { + RegisterJob, + UpdateJob, + InstallJob, + UnregisterJob + }; + + virtual void Start() = 0; + + bool + IsRegisterOrInstallJob() const + { + return mJobType == RegisterJob || mJobType == UpdateJob || + mJobType == InstallJob; + } + protected: // The queue keeps the jobs alive, so they can hold a rawptr back to the // queue. ServiceWorkerJobQueue* mQueue; -public: - NS_DECL_ISUPPORTS - - virtual void Start() = 0; - - virtual bool - IsRegisterJob() const { return false; } - -protected: - explicit ServiceWorkerJob(ServiceWorkerJobQueue* aQueue) + Type mJobType; + + explicit ServiceWorkerJob(ServiceWorkerJobQueue* aQueue, Type aJobType) : mQueue(aQueue) + , mJobType(aJobType) {} virtual ~ServiceWorkerJob() {} void Done(nsresult aStatus); }; class ServiceWorkerJobQueue final { friend class ServiceWorkerJob; - nsTArray<RefPtr<ServiceWorkerJob>> mJobs; + struct QueueData final + { + QueueData() + : mPopping(false) + { } + + ~QueueData() + { + if (!mJobs.IsEmpty()) { + NS_WARNING("Pending/running jobs still around on shutdown!"); + } + } + + nsTArray<RefPtr<ServiceWorkerJob>> mJobs; + bool mPopping; + }; + const nsCString mOriginAttributesSuffix; - bool mPopping; + QueueData mRegistrationJobQueue; + QueueData mInstallationJobQueue; public: explicit ServiceWorkerJobQueue(const nsACString& aScopeKey) : mOriginAttributesSuffix(aScopeKey) - , mPopping(false) {} ~ServiceWorkerJobQueue() - { - if (!mJobs.IsEmpty()) { - NS_WARNING("Pending/running jobs still around on shutdown!"); - } - } + { } void Append(ServiceWorkerJob* aJob) { MOZ_ASSERT(aJob); - MOZ_ASSERT(!mJobs.Contains(aJob)); - bool wasEmpty = mJobs.IsEmpty(); - mJobs.AppendElement(aJob); + QueueData& queue = GetQueue(aJob->mJobType); + MOZ_ASSERT(!queue.mJobs.Contains(aJob)); + + bool wasEmpty = queue.mJobs.IsEmpty(); + queue.mJobs.AppendElement(aJob); if (wasEmpty) { aJob->Start(); } } void CancelJobs(); - // Only used by HandleError, keep it that way! - ServiceWorkerJob* - Peek() - { - if (mJobs.IsEmpty()) { - return nullptr; - } - return mJobs[0]; - } - private: void - Pop() + CancelJobs(QueueData& aQueue); + + // Internal helper function used to assign jobs to the correct queue. + QueueData& + GetQueue(ServiceWorkerJob::Type aType) { - MOZ_ASSERT(!mPopping, + switch (aType) { + case ServiceWorkerJob::Type::RegisterJob: + case ServiceWorkerJob::Type::UpdateJob: + case ServiceWorkerJob::Type::UnregisterJob: + return mRegistrationJobQueue; + case ServiceWorkerJob::Type::InstallJob: + return mInstallationJobQueue; + default: + MOZ_CRASH("Invalid job queue type."); + return mRegistrationJobQueue; + } + } + + bool + IsEmpty() + { + return mRegistrationJobQueue.mJobs.IsEmpty() && + mInstallationJobQueue.mJobs.IsEmpty(); + } + + void + Pop(QueueData& aQueue) + { + MOZ_ASSERT(!aQueue.mPopping, "Pop() called recursively, did you write a job which calls Done() synchronously from Start()?"); - AutoRestore<bool> savePopping(mPopping); - mPopping = true; - MOZ_ASSERT(!mJobs.IsEmpty()); - mJobs.RemoveElementAt(0); - if (!mJobs.IsEmpty()) { - mJobs[0]->Start(); - } else { + + AutoRestore<bool> savePopping(aQueue.mPopping); + aQueue.mPopping = true; + MOZ_ASSERT(!aQueue.mJobs.IsEmpty()); + aQueue.mJobs.RemoveElementAt(0); + if (!aQueue.mJobs.IsEmpty()) { + aQueue.mJobs[0]->Start(); + } else if (IsEmpty()) { RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance(); MOZ_ASSERT(swm); swm->MaybeRemoveRegistrationInfo(mOriginAttributesSuffix); } } void Done(ServiceWorkerJob* aJob) { - MOZ_ASSERT(!mJobs.IsEmpty()); - MOZ_ASSERT(mJobs[0] == aJob); - Pop(); + MOZ_ASSERT(aJob); + QueueData& queue = GetQueue(aJob->mJobType); + MOZ_ASSERT(!queue.mJobs.IsEmpty()); + MOZ_ASSERT(queue.mJobs[0] == aJob); + Pop(queue); } }; namespace { nsresult PopulateRegistrationData(nsIPrincipal* aPrincipal, const ServiceWorkerRegistrationInfo* aRegistration, @@ -370,16 +418,17 @@ ServiceWorkerRegistrationInfo::Clear() } ServiceWorkerRegistrationInfo::ServiceWorkerRegistrationInfo(const nsACString& aScope, nsIPrincipal* aPrincipal) : mControlledDocumentsCounter(0) , mScope(aScope) , mPrincipal(aPrincipal) , mLastUpdateCheckTime(0) + , mUpdating(false) , mPendingUninstall(false) {} ServiceWorkerRegistrationInfo::~ServiceWorkerRegistrationInfo() { if (IsControllingDocuments()) { NS_WARNING("ServiceWorkerRegistrationInfo is still controlling documents. This can be a bug or a leak in ServiceWorker API or in any other API that takes the document alive."); } @@ -551,24 +600,24 @@ protected: {} public: virtual void ContinueAfterWorkerEvent(bool aSuccess) = 0; }; NS_IMPL_ISUPPORTS0(ContinueLifecycleTask); -class ServiceWorkerRegisterJob; +class ServiceWorkerInstallJob; class ContinueInstallTask final : public ContinueLifecycleTask { - RefPtr<ServiceWorkerRegisterJob> mJob; + RefPtr<ServiceWorkerInstallJob> mJob; public: - explicit ContinueInstallTask(ServiceWorkerRegisterJob* aJob) + explicit ContinueInstallTask(ServiceWorkerInstallJob* aJob) : mJob(aJob) {} void ContinueAfterWorkerEvent(bool aSuccess) override; }; class ContinueActivateTask final : public ContinueLifecycleTask { @@ -626,38 +675,45 @@ public: : mWindow(aWindow) , mPromise(aPromise) {} void UpdateSucceeded(ServiceWorkerRegistrationInfo* aInfo) override { RefPtr<ServiceWorkerRegistrationMainThread> swr = - new ServiceWorkerRegistrationMainThread(mWindow, - NS_ConvertUTF8toUTF16(aInfo->mScope)); + mWindow->GetServiceWorkerRegistration(NS_ConvertUTF8toUTF16(aInfo->mScope)); mPromise->MaybeResolve(swr); } void UpdateFailed(ErrorResult& aStatus) override { mPromise->MaybeReject(aStatus); } }; -class ContinueUpdateRunnable final : public nsRunnable +class ContinueUpdateRunnable final : public LifeCycleEventCallback { nsMainThreadPtrHandle<nsISupports> mJob; + bool mScriptEvaluationResult; public: explicit ContinueUpdateRunnable(const nsMainThreadPtrHandle<nsISupports> aJob) : mJob(aJob) + , mScriptEvaluationResult(false) { AssertIsOnMainThread(); } + void + SetResult(bool aResult) + { + mScriptEvaluationResult = aResult; + } + NS_IMETHOD Run(); }; namespace { /** * The spec mandates slightly different behaviors for computing the scope * prefix string in case a Service-Worker-Allowed header is specified versus @@ -850,118 +906,323 @@ public: private: ~PropagateRemoveAllRunnable() {} }; } // namespace -class ServiceWorkerRegisterJob final : public ServiceWorkerJob, +class ServiceWorkerJobBase : public ServiceWorkerJob +{ +public: + ServiceWorkerJobBase(ServiceWorkerJobQueue* aQueue, + ServiceWorkerJob::Type aJobType, + ServiceWorkerUpdateFinishCallback* aCallback) + : ServiceWorkerJobBase(aQueue, aJobType, aCallback, nullptr, nullptr) + { } + + ServiceWorkerJobBase(ServiceWorkerJobQueue* aQueue, + ServiceWorkerJob::Type aJobType, + ServiceWorkerUpdateFinishCallback* aCallback, + ServiceWorkerRegistrationInfo* aRegistration, + ServiceWorkerInfo* aServiceWorkerInfo) + : ServiceWorkerJob(aQueue, aJobType) + , mCallback(aCallback) + , mCanceled(false) + , mRegistration(aRegistration) + , mUpdateAndInstallInfo(aServiceWorkerInfo) + { + AssertIsOnMainThread(); + } + + void + Cancel() + { + mQueue = nullptr; + mCanceled = true; + } + +protected: + RefPtr<ServiceWorkerUpdateFinishCallback> mCallback; + bool mCanceled; + RefPtr<ServiceWorkerRegistrationInfo> mRegistration; + RefPtr<ServiceWorkerInfo> mUpdateAndInstallInfo; + + ~ServiceWorkerJobBase() + { } + + // This MUST only be called when the job is still performing actions related + // to registration or update. After the spec resolves the update promise, use + // Done() with the failure code instead. + // Callers MUST hold a strong ref before calling this! + void + Fail(ErrorResult& aRv) + { + AssertIsOnMainThread(); + MOZ_ASSERT(mRegistration); + + // With cancellation support, we may only be running with one reference + // from another object like a stream loader or something. + RefPtr<ServiceWorkerJob> kungFuDeathGrip = this; + + // Save off the plain error code to pass to Done() where its logged to + // stderr as a warning. + nsresult origStatus = static_cast<nsresult>(aRv.ErrorCodeAsInt()); + + // Ensure that we only surface SecurityErr or TypeErr to script. + if (aRv.Failed() && !aRv.ErrorCodeIs(NS_ERROR_DOM_SECURITY_ERR) && + !aRv.ErrorCodeIs(NS_ERROR_DOM_TYPE_ERR)) { + + // Remove the old error code so we can replace it with a TypeError. + aRv.SuppressException(); + + NS_ConvertUTF8toUTF16 scriptSpec(mRegistration->mScriptSpec); + NS_ConvertUTF8toUTF16 scope(mRegistration->mScope); + + // Throw the type error with a generic error message. + aRv.ThrowTypeError<MSG_SW_INSTALL_ERROR>(scriptSpec, scope); + } + + if (mCallback) { + mCallback->UpdateFailed(aRv); + mCallback = nullptr; + } + // In case the callback does not consume the exception + aRv.SuppressException(); + + mUpdateAndInstallInfo = nullptr; + if (mRegistration->mInstallingWorker) { + nsresult rv = serviceWorkerScriptCache::PurgeCache(mRegistration->mPrincipal, + mRegistration->mInstallingWorker->CacheName()); + if (NS_FAILED(rv)) { + NS_WARNING("Failed to purge the installing worker cache."); + } + } + + RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance(); + swm->MaybeRemoveRegistration(mRegistration); + // Ensures that the job can't do anything useful from this point on. + mRegistration = nullptr; + Done(origStatus); + } + + void + Fail(nsresult aRv) + { + ErrorResult rv(aRv); + Fail(rv); + } + + void + Succeed() + { + AssertIsOnMainThread(); + // We don't have a callback for soft updates. + if (mCallback) { + mCallback->UpdateSucceeded(mRegistration); + mCallback = nullptr; + } + } +}; + +class ServiceWorkerInstallJob final : public ServiceWorkerJobBase +{ + friend class ContinueInstallTask; + +public: + ServiceWorkerInstallJob(ServiceWorkerJobQueue* aQueue, + ServiceWorkerUpdateFinishCallback* aCallback, + ServiceWorkerRegistrationInfo* aRegistration, + ServiceWorkerInfo* aServiceWorkerInfo) + : ServiceWorkerJobBase(aQueue, Type::InstallJob, aCallback, + aRegistration, aServiceWorkerInfo) + { + MOZ_ASSERT(aRegistration); + } + + void + Start() + { + AssertIsOnMainThread(); + nsCOMPtr<nsIRunnable> r = + NS_NewRunnableMethod(this, &ServiceWorkerInstallJob::Install); + MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToMainThread(r))); + } + + void + Install() + { + RefPtr<ServiceWorkerJob> kungFuDeathGrip = this; + if (mCanceled) { + return Fail(NS_ERROR_DOM_ABORT_ERR); + } + MOZ_ASSERT(mRegistration); + + // Begin [[Install]] atomic step 3. + if (mRegistration->mInstallingWorker) { + mRegistration->mInstallingWorker->UpdateState(ServiceWorkerState::Redundant); + mRegistration->mInstallingWorker->WorkerPrivate()->TerminateWorker(); + } + + RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance(); + swm->InvalidateServiceWorkerRegistrationWorker(mRegistration, + WhichServiceWorker::INSTALLING_WORKER); + + mRegistration->mInstallingWorker = mUpdateAndInstallInfo.forget(); + mRegistration->mInstallingWorker->UpdateState(ServiceWorkerState::Installing); + mRegistration->NotifyListenersOnChange(); + + Succeed(); + + // The job should NOT call fail from this point on. + + // Step 8 "Queue a task..." for updatefound. + nsCOMPtr<nsIRunnable> upr = + NS_NewRunnableMethodWithArg<ServiceWorkerRegistrationInfo*>( + swm, + &ServiceWorkerManager::FireUpdateFoundOnServiceWorkerRegistrations, + mRegistration); + + NS_DispatchToMainThread(upr); + + // Call ContinueAfterInstallEvent(false) on main thread if the SW + // script fails to load. + nsCOMPtr<nsIRunnable> failRunnable = NS_NewRunnableMethodWithArgs<bool> + (this, &ServiceWorkerInstallJob::ContinueAfterInstallEvent, false); + + nsMainThreadPtrHandle<ContinueLifecycleTask> installTask( + new nsMainThreadPtrHolder<ContinueLifecycleTask>(new ContinueInstallTask(this))); + RefPtr<LifeCycleEventCallback> callback = new ContinueLifecycleRunnable(installTask); + + // This triggers Step 4.7 "Queue a task to run the following substeps..." + // which sends the install event to the worker. + ServiceWorkerPrivate* workerPrivate = + mRegistration->mInstallingWorker->WorkerPrivate(); + nsresult rv = workerPrivate->SendLifeCycleEvent(NS_LITERAL_STRING("install"), + callback, failRunnable); + + if (NS_WARN_IF(NS_FAILED(rv))) { + ContinueAfterInstallEvent(false /* aSuccess */); + } + } + + void + ContinueAfterInstallEvent(bool aInstallEventSuccess) + { + if (mCanceled) { + return Done(NS_ERROR_DOM_ABORT_ERR); + } + + if (!mRegistration->mInstallingWorker) { + NS_WARNING("mInstallingWorker was null."); + return Done(NS_ERROR_DOM_ABORT_ERR); + } + + RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance(); + + // "If installFailed is true" + if (NS_WARN_IF(!aInstallEventSuccess)) { + mRegistration->mInstallingWorker->UpdateState(ServiceWorkerState::Redundant); + mRegistration->mInstallingWorker = nullptr; + swm->InvalidateServiceWorkerRegistrationWorker(mRegistration, + WhichServiceWorker::INSTALLING_WORKER); + swm->MaybeRemoveRegistration(mRegistration); + return Done(NS_ERROR_DOM_ABORT_ERR); + } + + // "If registration's waiting worker is not null" + if (mRegistration->mWaitingWorker) { + mRegistration->mWaitingWorker->WorkerPrivate()->TerminateWorker(); + mRegistration->mWaitingWorker->UpdateState(ServiceWorkerState::Redundant); + + nsresult rv = + serviceWorkerScriptCache::PurgeCache(mRegistration->mPrincipal, + mRegistration->mWaitingWorker->CacheName()); + if (NS_FAILED(rv)) { + NS_WARNING("Failed to purge the old waiting cache."); + } + } + + mRegistration->mWaitingWorker = mRegistration->mInstallingWorker.forget(); + mRegistration->mWaitingWorker->UpdateState(ServiceWorkerState::Installed); + mRegistration->NotifyListenersOnChange(); + swm->InvalidateServiceWorkerRegistrationWorker(mRegistration, + WhichServiceWorker::INSTALLING_WORKER | WhichServiceWorker::WAITING_WORKER); + + // "If registration's waiting worker's skip waiting flag is set" + if (mRegistration->mWaitingWorker->SkipWaitingFlag()) { + mRegistration->PurgeActiveWorker(); + } + + Done(NS_OK); + // Activate() is invoked out of band of atomic. + mRegistration->TryToActivate(); + } +}; + +class ServiceWorkerRegisterJob final : public ServiceWorkerJobBase, public serviceWorkerScriptCache::CompareCallback { - friend class ContinueInstallTask; + friend class ContinueUpdateRunnable; nsCString mScope; nsCString mScriptSpec; - RefPtr<ServiceWorkerRegistrationInfo> mRegistration; - nsTArray<RefPtr<ServiceWorkerUpdateFinishCallback>> mCallbacks; nsCOMPtr<nsIPrincipal> mPrincipal; - RefPtr<ServiceWorkerInfo> mUpdateAndInstallInfo; nsCOMPtr<nsILoadGroup> mLoadGroup; ~ServiceWorkerRegisterJob() - {} - - enum - { - REGISTER_JOB = 0, - UPDATE_JOB = 1, - } mJobType; - - bool mCanceled; + { } public: NS_DECL_ISUPPORTS_INHERITED // [[Register]] ServiceWorkerRegisterJob(ServiceWorkerJobQueue* aQueue, const nsCString& aScope, const nsCString& aScriptSpec, ServiceWorkerUpdateFinishCallback* aCallback, nsIPrincipal* aPrincipal, nsILoadGroup* aLoadGroup) - : ServiceWorkerJob(aQueue) + : ServiceWorkerJobBase(aQueue, Type::RegisterJob, aCallback) , mScope(aScope) , mScriptSpec(aScriptSpec) , mPrincipal(aPrincipal) , mLoadGroup(aLoadGroup) - , mJobType(REGISTER_JOB) - , mCanceled(false) { AssertIsOnMainThread(); MOZ_ASSERT(mLoadGroup); MOZ_ASSERT(aCallback); - - mCallbacks.AppendElement(aCallback); } // [[Update]] ServiceWorkerRegisterJob(ServiceWorkerJobQueue* aQueue, ServiceWorkerRegistrationInfo* aRegistration, ServiceWorkerUpdateFinishCallback* aCallback) - : ServiceWorkerJob(aQueue) - , mRegistration(aRegistration) - , mJobType(UPDATE_JOB) - , mCanceled(false) + : ServiceWorkerJobBase(aQueue, Type::UpdateJob, aCallback, + aRegistration, nullptr) { AssertIsOnMainThread(); - MOZ_ASSERT(aCallback); - - mCallbacks.AppendElement(aCallback); - } - - bool - IsRegisterJob() const override - { - return true; - } - - void - AppendCallback(ServiceWorkerUpdateFinishCallback* aCallback) - { - AssertIsOnMainThread(); - MOZ_ASSERT(aCallback); - MOZ_ASSERT(!mCallbacks.Contains(aCallback)); - - mCallbacks.AppendElement(aCallback); - } - - void - Cancel() - { - mQueue = nullptr; - mCanceled = true; } void Start() override { AssertIsOnMainThread(); MOZ_ASSERT(!mCanceled); RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance(); if (!swm->HasBackgroundActor()) { nsCOMPtr<nsIRunnable> runnable = NS_NewRunnableMethod(this, &ServiceWorkerRegisterJob::Start); swm->AppendPendingOperation(runnable); return; } - if (mJobType == REGISTER_JOB) { + if (mJobType == RegisterJob) { mRegistration = swm->GetRegistration(mPrincipal, mScope); if (mRegistration) { mRegistration->mPendingUninstall = false; RefPtr<ServiceWorkerInfo> newest = mRegistration->Newest(); if (newest && mScriptSpec.Equals(newest->ScriptSpec()) && mScriptSpec.Equals(mRegistration->mScriptSpec)) { swm->StoreRegistration(mPrincipal, mRegistration); @@ -980,21 +1241,17 @@ public: } else { mRegistration = swm->CreateNewRegistration(mScope, mPrincipal); } mRegistration->mScriptSpec = mScriptSpec; mRegistration->NotifyListenersOnChange(); swm->StoreRegistration(mPrincipal, mRegistration); } else { - MOZ_ASSERT(mJobType == UPDATE_JOB); - MOZ_ASSERT(mRegistration); - MOZ_ASSERT(mRegistration->mUpdateJob == nullptr); - - mRegistration->mUpdateJob = this; + MOZ_ASSERT(mJobType == UpdateJob); } Update(); } void ComparisonResult(nsresult aStatus, bool aInCacheAndEqual, const nsAString& aNewCacheName, @@ -1066,242 +1323,95 @@ public: return Fail(NS_ERROR_FAILURE); } ServiceWorkerManager::RegistrationDataPerPrincipal* data; if (!swm->mRegistrationInfos.Get(scopeKey, &data)) { return Fail(NS_ERROR_FAILURE); } - nsAutoString cacheName; - // We have to create a ServiceWorker here simply to ensure there are no - // errors. Ideally we should just pass this worker on to ContinueInstall. - MOZ_ASSERT(!data->mSetOfScopesBeingUpdated.Contains(mRegistration->mScope)); - data->mSetOfScopesBeingUpdated.Put(mRegistration->mScope, true); - - // Call FailScopeUpdate on main thread if the SW script load fails below. - nsCOMPtr<nsIRunnable> failRunnable = NS_NewRunnableMethodWithArgs - <StorensRefPtrPassByPtr<ServiceWorkerManager>, nsCString> - (this, &ServiceWorkerRegisterJob::FailScopeUpdate, swm, scopeKey); - MOZ_ASSERT(!mUpdateAndInstallInfo); mUpdateAndInstallInfo = new ServiceWorkerInfo(mRegistration, mRegistration->mScriptSpec, aNewCacheName); RefPtr<ServiceWorkerJob> upcasted = this; nsMainThreadPtrHandle<nsISupports> handle( new nsMainThreadPtrHolder<nsISupports>(upcasted)); - RefPtr<nsRunnable> callback = new ContinueUpdateRunnable(handle); + RefPtr<LifeCycleEventCallback> callback = new ContinueUpdateRunnable(handle); ServiceWorkerPrivate* workerPrivate = mUpdateAndInstallInfo->WorkerPrivate(); - rv = workerPrivate->ContinueOnSuccessfulScriptEvaluation(callback); + rv = workerPrivate->CheckScriptEvaluation(callback); if (NS_WARN_IF(NS_FAILED(rv))) { - return FailScopeUpdate(swm, scopeKey); + Fail(NS_ERROR_DOM_ABORT_ERR); } } +private: + // This will perform steps 27 and 28 from [[Update]] + // Remove the job from the registration queue and invoke [[Install]] void - FailScopeUpdate(ServiceWorkerManager* aSwm, const nsACString& aScopeKey) - { - AssertIsOnMainThread(); - MOZ_ASSERT(aSwm); - ServiceWorkerManager::RegistrationDataPerPrincipal* data; - if (aSwm->mRegistrationInfos.Get(aScopeKey, &data)) { - data->mSetOfScopesBeingUpdated.Remove(aScopeKey); - } - Fail(NS_ERROR_DOM_ABORT_ERR); - } - - // This MUST only be called when the job is still performing actions related - // to registration or update. After the spec resolves the update promise, use - // Done() with the failure code instead. - // Callers MUST hold a strong ref before calling this! - void - Fail(ErrorResult& aRv) + ContinueInstall(bool aScriptEvaluationResult) { AssertIsOnMainThread(); - MOZ_ASSERT(mCallbacks.Length()); - - // With cancellation support, we may only be running with one reference - // from another object like a stream loader or something. - RefPtr<ServiceWorkerRegisterJob> kungFuDeathGrip = this; - - // Save off the plain error code to pass to Done() where its logged to - // stderr as a warning. - nsresult origStatus = static_cast<nsresult>(aRv.ErrorCodeAsInt()); - - // Ensure that we only surface SecurityErr or TypeErr to script. - if (aRv.Failed() && !aRv.ErrorCodeIs(NS_ERROR_DOM_SECURITY_ERR) && - !aRv.ErrorCodeIs(NS_ERROR_DOM_TYPE_ERR)) { - - // Remove the old error code so we can replace it with a TypeError. - aRv.SuppressException(); - - // Depending on how the job was created and where we are in the - // state machine the spec and scope may be stored in different ways. - // Extract the current scope and script spec. - nsString scriptSpec; - nsString scope; - if (mRegistration) { - CopyUTF8toUTF16(mRegistration->mScriptSpec, scriptSpec); - CopyUTF8toUTF16(mRegistration->mScope, scope); - } else { - CopyUTF8toUTF16(mScriptSpec, scriptSpec); - CopyUTF8toUTF16(mScope, scope); - } - - // Throw the type error with a generic error message. - aRv.ThrowTypeError<MSG_SW_INSTALL_ERROR>(scriptSpec, scope); - } - - for (uint32_t i = 1; i < mCallbacks.Length(); ++i) { - ErrorResult rv; - aRv.CloneTo(rv); - mCallbacks[i]->UpdateFailed(rv); - rv.SuppressException(); - } - - mCallbacks[0]->UpdateFailed(aRv); - - // In case the callback does not consume the exception - aRv.SuppressException(); - - mUpdateAndInstallInfo = nullptr; - if (mRegistration->mInstallingWorker) { - nsresult rv = serviceWorkerScriptCache::PurgeCache(mRegistration->mPrincipal, - mRegistration->mInstallingWorker->CacheName()); - if (NS_FAILED(rv)) { - NS_WARNING("Failed to purge the installing worker cache."); - } - } - - RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance(); - swm->MaybeRemoveRegistration(mRegistration); - // Ensures that the job can't do anything useful from this point on. - mRegistration->mUpdateJob = nullptr; - mRegistration = nullptr; - Done(origStatus); - } - - void - Fail(nsresult aRv) - { - ErrorResult rv(aRv); - Fail(rv); - } - - // Public so our error handling code can continue with a successful worker. - void - ContinueInstall() - { - // mRegistration will be null if we have already Fail()ed. - if (!mRegistration) { - return; - } - - // Even if we are canceled, ensure integrity of mSetOfScopesBeingUpdated - // first. - RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance(); - - nsAutoCString scopeKey; - nsresult rv = swm->PrincipalToScopeKey(mRegistration->mPrincipal, scopeKey); - if (NS_WARN_IF(NS_FAILED(rv))) { - return Fail(NS_ERROR_FAILURE); - } - - ServiceWorkerManager::RegistrationDataPerPrincipal* data; - if (!swm->mRegistrationInfos.Get(scopeKey, &data)) { - return Fail(NS_ERROR_FAILURE); - } - - MOZ_ASSERT(data->mSetOfScopesBeingUpdated.Contains(mRegistration->mScope)); - data->mSetOfScopesBeingUpdated.Remove(mRegistration->mScope); - // This is effectively the end of Step 4.3 of the [[Update]] algorithm. - // The invocation of [[Install]] is not part of the atomic block. + MOZ_ASSERT(mRegistration); + mRegistration->mUpdating = false; RefPtr<ServiceWorkerRegisterJob> kungFuDeathGrip = this; if (mCanceled) { return Fail(NS_ERROR_DOM_ABORT_ERR); } - // Begin [[Install]] atomic step 4. - if (mRegistration->mInstallingWorker) { - mRegistration->mInstallingWorker->UpdateState(ServiceWorkerState::Redundant); - mRegistration->mInstallingWorker->WorkerPrivate()->TerminateWorker(); + if (NS_WARN_IF(!aScriptEvaluationResult)) { + ErrorResult error; + + NS_ConvertUTF8toUTF16 scriptSpec(mRegistration->mScriptSpec); + NS_ConvertUTF8toUTF16 scope(mRegistration->mScope); + error.ThrowTypeError<MSG_SW_SCRIPT_THREW>(scriptSpec, scope); + return Fail(error); } - swm->InvalidateServiceWorkerRegistrationWorker(mRegistration, - WhichServiceWorker::INSTALLING_WORKER); - - mRegistration->mInstallingWorker = mUpdateAndInstallInfo.forget(); - mRegistration->mInstallingWorker->UpdateState(ServiceWorkerState::Installing); - mRegistration->NotifyListenersOnChange(); - - Succeed(); - // The job should NOT call fail from this point on. - - // Step 4.6 "Queue a task..." for updatefound. - nsCOMPtr<nsIRunnable> upr = - NS_NewRunnableMethodWithArg<ServiceWorkerRegistrationInfo*>( - swm, - &ServiceWorkerManager::FireUpdateFoundOnServiceWorkerRegistrations, - mRegistration); - - NS_DispatchToMainThread(upr); - - // Call ContinueAfterInstallEvent(false) on main thread if the SW - // script fails to load. - nsCOMPtr<nsIRunnable> failRunnable = NS_NewRunnableMethodWithArgs<bool> - (this, &ServiceWorkerRegisterJob::ContinueAfterInstallEvent, false); - - nsMainThreadPtrHandle<ContinueLifecycleTask> installTask( - new nsMainThreadPtrHolder<ContinueLifecycleTask>(new ContinueInstallTask(this))); - RefPtr<LifeCycleEventCallback> callback = new ContinueLifecycleRunnable(installTask); - - // This triggers Step 4.7 "Queue a task to run the following substeps..." - // which sends the install event to the worker. - ServiceWorkerPrivate* workerPrivate = - mRegistration->mInstallingWorker->WorkerPrivate(); - rv = workerPrivate->SendLifeCycleEvent(NS_LITERAL_STRING("install"), - callback, failRunnable); - - if (NS_WARN_IF(NS_FAILED(rv))) { - ContinueAfterInstallEvent(false /* aSuccess */); - } - } - -private: + RefPtr<ServiceWorkerInstallJob> job = + new ServiceWorkerInstallJob(mQueue, mCallback, + mRegistration, mUpdateAndInstallInfo); + mQueue->Append(job); + Done(NS_OK); + } + void Update() { + AssertIsOnMainThread(); + // Since Update() is called synchronously from Start(), we can assert this. MOZ_ASSERT(!mCanceled); MOZ_ASSERT(mRegistration); nsCOMPtr<nsIRunnable> r = NS_NewRunnableMethod(this, &ServiceWorkerRegisterJob::ContinueUpdate); NS_DispatchToMainThread(r); + + mRegistration->mUpdating = true; } // Aspects of (actually the whole algorithm) of [[Update]] after // "Run the following steps in parallel." void ContinueUpdate() { AssertIsOnMainThread(); RefPtr<ServiceWorkerRegisterJob> kungFuDeathGrip = this; if (mCanceled) { return Fail(NS_ERROR_DOM_ABORT_ERR); } if (mRegistration->mInstallingWorker) { mRegistration->mInstallingWorker->UpdateState(ServiceWorkerState::Redundant); - // This will terminate the installing worker thread. + mRegistration->mInstallingWorker->WorkerPrivate()->TerminateWorker(); mRegistration->mInstallingWorker = nullptr; } RefPtr<ServiceWorkerInfo> workerInfo = mRegistration->Newest(); nsAutoString cacheName; // 9.2.20 If newestWorker is not null, and newestWorker's script url is // equal to registration's registering script url and response is a @@ -1315,123 +1425,67 @@ private: NS_ConvertUTF8toUTF16(mRegistration->mScriptSpec), this, mLoadGroup); if (NS_WARN_IF(NS_FAILED(rv))) { return Fail(rv); } } void - Succeed() + Done(nsresult aStatus) { AssertIsOnMainThread(); - MOZ_ASSERT(mCallbacks.Length()); - - for (uint32_t i = 0; i < mCallbacks.Length(); ++i) { - mCallbacks[i]->UpdateSucceeded(mRegistration); - } - mCallbacks.Clear(); - } - - void - ContinueAfterInstallEvent(bool aInstallEventSuccess) - { - if (mCanceled) { - return Done(NS_ERROR_DOM_ABORT_ERR); - } - - if (!mRegistration->mInstallingWorker) { - NS_WARNING("mInstallingWorker was null."); - return Done(NS_ERROR_DOM_ABORT_ERR); - } - - RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance(); - - // "If installFailed is true" - if (NS_WARN_IF(!aInstallEventSuccess)) { - mRegistration->mInstallingWorker->UpdateState(ServiceWorkerState::Redundant); - mRegistration->mInstallingWorker = nullptr; - swm->InvalidateServiceWorkerRegistrationWorker(mRegistration, - WhichServiceWorker::INSTALLING_WORKER); - swm->MaybeRemoveRegistration(mRegistration); - return Done(NS_ERROR_DOM_ABORT_ERR); + + if (mRegistration) { + mRegistration->mUpdating = false; } - // "If registration's waiting worker is not null" - if (mRegistration->mWaitingWorker) { - mRegistration->mWaitingWorker->WorkerPrivate()->TerminateWorker(); - mRegistration->mWaitingWorker->UpdateState(ServiceWorkerState::Redundant); - - nsresult rv = serviceWorkerScriptCache::PurgeCache(mRegistration->mPrincipal, - mRegistration->mWaitingWorker->CacheName()); - if (NS_FAILED(rv)) { - NS_WARNING("Failed to purge the old waiting cache."); - } - } - - mRegistration->mWaitingWorker = mRegistration->mInstallingWorker.forget(); - mRegistration->mWaitingWorker->UpdateState(ServiceWorkerState::Installed); - mRegistration->NotifyListenersOnChange(); - swm->InvalidateServiceWorkerRegistrationWorker(mRegistration, - WhichServiceWorker::INSTALLING_WORKER | WhichServiceWorker::WAITING_WORKER); - - // "If registration's waiting worker's skip waiting flag is set" - if (mRegistration->mWaitingWorker->SkipWaitingFlag()) { - mRegistration->PurgeActiveWorker(); - } - - Done(NS_OK); - // Activate() is invoked out of band of atomic. - mRegistration->TryToActivate(); - } - - void - Done(nsresult aStatus) - { ServiceWorkerJob::Done(aStatus); - - if (mJobType == UPDATE_JOB && mRegistration) { - MOZ_ASSERT(NS_IsMainThread()); - MOZ_ASSERT(mRegistration->mUpdateJob); - mRegistration->mUpdateJob = nullptr; - } } }; NS_IMPL_ISUPPORTS_INHERITED0(ServiceWorkerRegisterJob, ServiceWorkerJob); void ServiceWorkerJobQueue::CancelJobs() { - if (mJobs.IsEmpty()) { + // The order doesn't matter. Cancel() just sets a flag on these jobs. + CancelJobs(mRegistrationJobQueue); + CancelJobs(mInstallationJobQueue); +} + +void +ServiceWorkerJobQueue::CancelJobs(QueueData& aQueue) +{ + if (aQueue.mJobs.IsEmpty()) { return; } // We have to treat the first job specially. It is the running job and needs // to be notified correctly. - RefPtr<ServiceWorkerJob> runningJob = mJobs[0]; + RefPtr<ServiceWorkerJob> runningJob = aQueue.mJobs[0]; // We can just let an Unregister job run to completion. - if (runningJob->IsRegisterJob()) { - ServiceWorkerRegisterJob* job = static_cast<ServiceWorkerRegisterJob*>(runningJob.get()); + if (runningJob->IsRegisterOrInstallJob()) { + ServiceWorkerJobBase* job = static_cast<ServiceWorkerJobBase*>(runningJob.get()); job->Cancel(); } // Get rid of everything. Non-main thread objects may still be holding a ref // to the running register job. Since we called Cancel() on it, the job's // main thread functions will just exit. - mJobs.Clear(); + aQueue.mJobs.Clear(); } NS_IMETHODIMP ContinueUpdateRunnable::Run() { AssertIsOnMainThread(); RefPtr<ServiceWorkerJob> job = static_cast<ServiceWorkerJob*>(mJob.get()); RefPtr<ServiceWorkerRegisterJob> upjob = static_cast<ServiceWorkerRegisterJob*>(job.get()); - upjob->ContinueInstall(); + upjob->ContinueInstall(mScriptEvaluationResult); return NS_OK; } void ContinueInstallTask::ContinueAfterWorkerEvent(bool aSuccess) { // This does not start the job immediately if there are other jobs in the // queue, which captures the "atomic" behaviour we want. @@ -1800,17 +1854,17 @@ public: rv = principal->CheckMayLoad(scopeURI, true /* report */, false /* allowIfInheritsPrincipal */); if (NS_WARN_IF(NS_FAILED(rv))) { continue; } RefPtr<ServiceWorkerRegistrationMainThread> swr = - new ServiceWorkerRegistrationMainThread(mWindow, scope); + mWindow->GetServiceWorkerRegistration(scope); array.AppendElement(swr); } mPromise->MaybeResolve(array); return NS_OK; } }; @@ -1907,17 +1961,17 @@ public: if (!registration) { mPromise->MaybeResolve(JS::UndefinedHandleValue); return NS_OK; } NS_ConvertUTF8toUTF16 scope(registration->mScope); RefPtr<ServiceWorkerRegistrationMainThread> swr = - new ServiceWorkerRegistrationMainThread(mWindow, scope); + mWindow->GetServiceWorkerRegistration(scope); mPromise->MaybeResolve(swr); return NS_OK; } }; // If we return an error code here, the ServiceWorkerContainer will // automatically reject the Promise. @@ -2169,17 +2223,17 @@ ServiceWorkerManager::CheckReadyPromise( MOZ_ASSERT(principal); RefPtr<ServiceWorkerRegistrationInfo> registration = GetServiceWorkerRegistrationInfo(principal, aURI); if (registration && registration->mActiveWorker) { NS_ConvertUTF8toUTF16 scope(registration->mScope); RefPtr<ServiceWorkerRegistrationMainThread> swr = - new ServiceWorkerRegistrationMainThread(aWindow, scope); + aWindow->GetServiceWorkerRegistration(scope); aPromise->MaybeResolve(swr); return true; } return false; } ServiceWorkerInfo* @@ -2227,17 +2281,17 @@ class ServiceWorkerUnregisterJob final : ~ServiceWorkerUnregisterJob() {} public: ServiceWorkerUnregisterJob(ServiceWorkerJobQueue* aQueue, const nsACString& aScope, nsIServiceWorkerUnregisterCallback* aCallback, nsIPrincipal* aPrincipal) - : ServiceWorkerJob(aQueue) + : ServiceWorkerJob(aQueue, Type::UnregisterJob) , mScope(aScope) , mCallback(aCallback) , mPrincipal(aPrincipal) { AssertIsOnMainThread(); } void @@ -2582,38 +2636,16 @@ ServiceWorkerManager::HandleError(JSCont return; } ServiceWorkerManager::RegistrationDataPerPrincipal* data; if (NS_WARN_IF(!mRegistrationInfos.Get(scopeKey, &data))) { return; } - // If this is a failure, we may need to cancel an in-progress registration. - if (!JSREPORT_IS_WARNING(aFlags) && - data->mSetOfScopesBeingUpdated.Contains(aScope)) { - - data->mSetOfScopesBeingUpdated.Remove(aScope); - - ServiceWorkerJobQueue* queue = data->mJobQueues.Get(aScope); - MOZ_ASSERT(queue); - - ServiceWorkerJob* job = queue->Peek(); - if (job) { - MOZ_ASSERT(job->IsRegisterJob()); - RefPtr<ServiceWorkerRegisterJob> regJob = - static_cast<ServiceWorkerRegisterJob*>(job); - - ErrorResult rv; - NS_ConvertUTF8toUTF16 scope(aScope); - rv.ThrowTypeError<MSG_SW_SCRIPT_THREW>(aWorkerURL, scope); - regJob->Fail(rv); - } - } - // Always report any uncaught exceptions or errors to the console of // each client. ReportToAllClients(aScope, aMessage, aFilename, aLine, aLineNumber, aColumnNumber, aFlags); } void ServiceWorkerRegistrationInfo::FinishActivate(bool aSuccess) @@ -2659,33 +2691,16 @@ void ServiceWorkerRegistrationInfo::NotifyListenersOnChange() { nsTArray<nsCOMPtr<nsIServiceWorkerRegistrationInfoListener>> listeners(mListeners); for (size_t index = 0; index < listeners.Length(); ++index) { listeners[index]->OnChange(); } } -bool -ServiceWorkerRegistrationInfo::IsUpdating() const -{ - MOZ_ASSERT(NS_IsMainThread()); - return mUpdateJob != nullptr; -} - -void -ServiceWorkerRegistrationInfo::AppendUpdateCallback(ServiceWorkerUpdateFinishCallback* aCallback) -{ - MOZ_ASSERT(NS_IsMainThread()); - MOZ_ASSERT(aCallback); - MOZ_ASSERT(mUpdateJob); - - mUpdateJob->AppendCallback(aCallback); -} - void ServiceWorkerManager::LoadRegistration( const ServiceWorkerRegistrationData& aRegistration) { AssertIsOnMainThread(); nsCOMPtr<nsIPrincipal> principal = PrincipalInfoToPrincipal(aRegistration.principal()); @@ -3010,16 +3025,17 @@ ServiceWorkerManager::RemoveScopeAndRegi RefPtr<ServiceWorkerRegistrationInfo> info; data->mInfos.Get(aRegistration->mScope, getter_AddRefs(info)); data->mInfos.Remove(aRegistration->mScope); data->mOrderedScopes.RemoveElement(aRegistration->mScope); swm->NotifyListenersOnUnregister(info); swm->MaybeRemoveRegistrationInfo(scopeKey); + swm->NotifyServiceWorkerRegistrationRemoved(aRegistration); } void ServiceWorkerManager::MaybeRemoveRegistrationInfo(const nsACString& aScopeKey) { RegistrationDataPerPrincipal* data; if (!mRegistrationInfos.Get(aScopeKey, &data)) { return; @@ -3522,65 +3538,44 @@ ServiceWorkerManager::InvalidateServiceW if (utf8Scope.Equals(aRegistration->mScope)) { target->InvalidateWorkers(aWhichOnes); } } } void -ServiceWorkerManager::SoftUpdate(nsIPrincipal* aPrincipal, - const nsACString& aScope, - ServiceWorkerUpdateFinishCallback* aCallback) +ServiceWorkerManager::NotifyServiceWorkerRegistrationRemoved(ServiceWorkerRegistrationInfo* aRegistration) { - MOZ_ASSERT(aPrincipal); - - nsAutoCString scopeKey; - nsresult rv = PrincipalToScopeKey(aPrincipal, scopeKey); - if (NS_WARN_IF(NS_FAILED(rv))) { - return; - } - - SoftUpdate(scopeKey, aScope, aCallback); + AssertIsOnMainThread(); + nsTObserverArray<ServiceWorkerRegistrationListener*>::ForwardIterator it(mServiceWorkerRegistrationListeners); + while (it.HasMore()) { + RefPtr<ServiceWorkerRegistrationListener> target = it.GetNext(); + nsAutoString regScope; + target->GetScope(regScope); + MOZ_ASSERT(!regScope.IsEmpty()); + + NS_ConvertUTF16toUTF8 utf8Scope(regScope); + + if (utf8Scope.Equals(aRegistration->mScope)) { + target->RegistrationRemoved(); + } + } } void -ServiceWorkerManager::SoftUpdate(const PrincipalOriginAttributes& aOriginAttributes, - const nsACString& aScope, - ServiceWorkerUpdateFinishCallback* aCallback) +ServiceWorkerManager::SoftUpdate(const OriginAttributes& aOriginAttributes, + const nsACString& aScope) { + AssertIsOnMainThread(); nsAutoCString scopeKey; aOriginAttributes.CreateSuffix(scopeKey); - SoftUpdate(scopeKey, aScope, aCallback); -} - -namespace { - -// Empty callback. Only use when you really want to ignore errors. -class EmptyUpdateFinishCallback final : public ServiceWorkerUpdateFinishCallback -{ -public: - void - UpdateSucceeded(ServiceWorkerRegistrationInfo* aInfo) override - {} - - void - UpdateFailed(ErrorResult& aStatus) override - {} -}; - -} // anonymous namespace - -void -ServiceWorkerManager::SoftUpdate(const nsACString& aScopeKey, - const nsACString& aScope, - ServiceWorkerUpdateFinishCallback* aCallback) -{ + RefPtr<ServiceWorkerRegistrationInfo> registration = - GetRegistration(aScopeKey, aScope); + GetRegistration(scopeKey, aScope); if (NS_WARN_IF(!registration)) { return; } // "If registration's uninstalling flag is set, abort these steps." if (registration->mPendingUninstall) { return; } @@ -3596,38 +3591,81 @@ ServiceWorkerManager::SoftUpdate(const n RefPtr<ServiceWorkerInfo> newest = registration->Newest(); if (!newest) { return; } // "Set registration's registering script url to newestWorker's script url." registration->mScriptSpec = newest->ScriptSpec(); + // "If the registration queue for registration is empty, invoke Update algorithm, + // or its equivalent, with client, registration as its argument." + // TODO(catalinb): We don't implement the force bypass cache flag. + // See: https://github.com/slightlyoff/ServiceWorker/issues/759 + if (!registration->mUpdating) { + ServiceWorkerJobQueue* queue = GetOrCreateJobQueue(scopeKey, aScope); + MOZ_ASSERT(queue); + + RefPtr<ServiceWorkerRegisterJob> job = + new ServiceWorkerRegisterJob(queue, registration, nullptr); + queue->Append(job); + } +} + +void +ServiceWorkerManager::Update(nsIPrincipal* aPrincipal, + const nsACString& aScope, + ServiceWorkerUpdateFinishCallback* aCallback) +{ + MOZ_ASSERT(aPrincipal); + MOZ_ASSERT(aCallback); + + nsAutoCString scopeKey; + nsresult rv = PrincipalToScopeKey(aPrincipal, scopeKey); + if (NS_WARN_IF(NS_FAILED(rv))) { + return; + } + + RefPtr<ServiceWorkerRegistrationInfo> registration = + GetRegistration(scopeKey, aScope); + if (NS_WARN_IF(!registration)) { + return; + } + + // "If registration's uninstalling flag is set, abort these steps." + if (registration->mPendingUninstall) { + return; + } + + // "Let newestWorker be the result of running Get Newest Worker algorithm + // passing registration as its argument. + // If newestWorker is null, return a promise rejected with "InvalidStateError" + RefPtr<ServiceWorkerInfo> newest = registration->Newest(); + if (!newest) { + ErrorResult error(NS_ERROR_DOM_INVALID_STATE_ERR); + aCallback->UpdateFailed(error); + + // In case the callback does not consume the exception + error.SuppressException(); + + return; + } + + // "Set registration's registering script url to newestWorker's script url." + registration->mScriptSpec = newest->ScriptSpec(); + ServiceWorkerJobQueue* queue = - GetOrCreateJobQueue(aScopeKey, aScope); + GetOrCreateJobQueue(scopeKey, aScope); MOZ_ASSERT(queue); - RefPtr<ServiceWorkerUpdateFinishCallback> cb(aCallback); - if (!cb) { - cb = new EmptyUpdateFinishCallback(); - } - // "Invoke Update algorithm, or its equivalent, with client, registration as // its argument." - if (registration->IsUpdating()) { - // This is used to reduce burst of update events. If there is an update - // job in queue when we try to create a new one, drop current one and - // merge the callback function to existing update job. - // See. https://github.com/slightlyoff/ServiceWorker/issues/759 - registration->AppendUpdateCallback(cb); - } else { - RefPtr<ServiceWorkerRegisterJob> job = - new ServiceWorkerRegisterJob(queue, registration, cb); - queue->Append(job); - } + RefPtr<ServiceWorkerRegisterJob> job = + new ServiceWorkerRegisterJob(queue, registration, aCallback); + queue->Append(job); } namespace { static void FireControllerChangeOnDocument(nsIDocument* aDocument) { AssertIsOnMainThread(); @@ -3753,30 +3791,31 @@ ServiceWorkerManager::ClaimClients(nsIPr nsresult ServiceWorkerManager::SetSkipWaitingFlag(nsIPrincipal* aPrincipal, const nsCString& aScope, uint64_t aServiceWorkerID) { RefPtr<ServiceWorkerRegistrationInfo> registration = GetRegistration(aPrincipal, aScope); - if (!registration) { + if (NS_WARN_IF(!registration)) { return NS_ERROR_FAILURE; } if (registration->mInstallingWorker && (registration->mInstallingWorker->ID() == aServiceWorkerID)) { registration->mInstallingWorker->SetSkipWaitingFlag(); } else if (registration->mWaitingWorker && (registration->mWaitingWorker->ID() == aServiceWorkerID)) { registration->mWaitingWorker->SetSkipWaitingFlag(); if (registration->mWaitingWorker->State() == ServiceWorkerState::Installed) { registration->TryToActivate(); } } else { + NS_WARNING("Failed to set skipWaiting flag, no matching worker."); return NS_ERROR_FAILURE; } return NS_OK; } void ServiceWorkerManager::FireControllerChange(ServiceWorkerRegistrationInfo* aRegistration) @@ -4528,16 +4567,38 @@ ServiceWorkerInfo::GetScriptSpec(nsAStri NS_IMETHODIMP ServiceWorkerInfo::GetCacheName(nsAString& aCacheName) { AssertIsOnMainThread(); aCacheName = mCacheName; return NS_OK; } +NS_IMETHODIMP +ServiceWorkerInfo::GetDebugger(nsIWorkerDebugger** aResult) +{ + if (NS_WARN_IF(!aResult)) { + return NS_ERROR_FAILURE; + } + + return mServiceWorkerPrivate->GetDebugger(aResult); +} + +NS_IMETHODIMP +ServiceWorkerInfo::AttachDebugger() +{ + return mServiceWorkerPrivate->AttachDebugger(); +} + +NS_IMETHODIMP +ServiceWorkerInfo::DetachDebugger() +{ + return mServiceWorkerPrivate->DetachDebugger(); +} + void ServiceWorkerInfo::AppendWorker(ServiceWorker* aWorker) { MOZ_ASSERT(aWorker); #ifdef DEBUG nsAutoString workerURL; aWorker->GetScriptURL(workerURL); MOZ_ASSERT(workerURL.Equals(NS_ConvertUTF8toUTF16(mScriptSpec)));
--- a/dom/workers/ServiceWorkerManager.h +++ b/dom/workers/ServiceWorkerManager.h @@ -42,21 +42,19 @@ namespace dom { class ServiceWorkerRegistrationListener; namespace workers { class ServiceWorker; class ServiceWorkerClientInfo; class ServiceWorkerInfo; class ServiceWorkerJob; -class ServiceWorkerRegisterJob; class ServiceWorkerJobQueue; class ServiceWorkerManagerChild; class ServiceWorkerPrivate; -class ServiceWorkerUpdateFinishCallback; class ServiceWorkerRegistrationInfo final : public nsIServiceWorkerRegistrationInfo { uint32_t mControlledDocumentsCounter; virtual ~ServiceWorkerRegistrationInfo(); @@ -74,17 +72,21 @@ public: RefPtr<ServiceWorkerInfo> mActiveWorker; RefPtr<ServiceWorkerInfo> mWaitingWorker; RefPtr<ServiceWorkerInfo> mInstallingWorker; nsTArray<nsCOMPtr<nsIServiceWorkerRegistrationInfoListener>> mListeners; uint64_t mLastUpdateCheckTime; - RefPtr<ServiceWorkerRegisterJob> mUpdateJob; + // According to the spec, Soft Update shouldn't queue an update job + // if the registration queue is not empty. Because our job queue + // works slightly different, we use a flag to determine if the registration + // is already updating. + bool mUpdating; // When unregister() is called on a registration, it is not immediately // removed since documents may be controlled. It is marked as // pendingUninstall and when all controlling documents go away, removed. bool mPendingUninstall; ServiceWorkerRegistrationInfo(const nsACString& aScope, nsIPrincipal* aPrincipal); @@ -144,22 +146,16 @@ public: void RefreshLastUpdateCheckTime(); bool IsLastUpdateCheckTimeOverOneDay() const; void NotifyListenersOnChange(); - - bool - IsUpdating() const; - - void - AppendUpdateCallback(ServiceWorkerUpdateFinishCallback* aCallback); }; class ServiceWorkerUpdateFinishCallback { protected: virtual ~ServiceWorkerUpdateFinishCallback() {} @@ -311,17 +307,19 @@ class ServiceWorkerManager final : public nsIServiceWorkerManager , public nsIIPCBackgroundChildCreateCallback , public nsIObserver { friend class GetReadyPromiseRunnable; friend class GetRegistrationsRunnable; friend class GetRegistrationRunnable; friend class ServiceWorkerJobQueue; + friend class ServiceWorkerInstallJob; friend class ServiceWorkerRegisterJob; + friend class ServiceWorkerJobBase; friend class ServiceWorkerRegistrationInfo; friend class ServiceWorkerUnregisterJob; public: NS_DECL_ISUPPORTS NS_DECL_NSISERVICEWORKERMANAGER NS_DECL_NSIIPCBACKGROUNDCHILDCREATECALLBACK NS_DECL_NSIOBSERVER @@ -368,24 +366,23 @@ public: ErrorResult& aRv); void DispatchPreparedFetchEvent(nsIInterceptedChannel* aChannel, nsIRunnable* aPreparedRunnable, ErrorResult& aRv); void - SoftUpdate(nsIPrincipal* aPrincipal, - const nsACString& aScope, - ServiceWorkerUpdateFinishCallback* aCallback = nullptr); + Update(nsIPrincipal* aPrincipal, + const nsACString& aScope, + ServiceWorkerUpdateFinishCallback* aCallback); void - SoftUpdate(const PrincipalOriginAttributes& aOriginAttributes, - const nsACString& aScope, - ServiceWorkerUpdateFinishCallback* aCallback = nullptr); + SoftUpdate(const OriginAttributes& aOriginAttributes, + const nsACString& aScope); void PropagateSoftUpdate(const PrincipalOriginAttributes& aOriginAttributes, const nsAString& aScope); void PropagateRemove(const nsACString& aHost); @@ -484,21 +481,16 @@ private: ServiceWorkerJobQueue* GetOrCreateJobQueue(const nsACString& aOriginSuffix, const nsACString& aScope); void MaybeRemoveRegistrationInfo(const nsACString& aScopeKey); - void - SoftUpdate(const nsACString& aScopeKey, - const nsACString& aScope, - ServiceWorkerUpdateFinishCallback* aCallback = nullptr); - already_AddRefed<ServiceWorkerRegistrationInfo> GetRegistration(const nsACString& aScopeKey, const nsACString& aScope) const; void AbortCurrentUpdate(ServiceWorkerRegistrationInfo* aRegistration); nsresult @@ -521,16 +513,19 @@ private: ServiceWorkerInfo* GetActiveWorkerInfoForDocument(nsIDocument* aDocument); void InvalidateServiceWorkerRegistrationWorker(ServiceWorkerRegistrationInfo* aRegistration, WhichServiceWorker aWhichOnes); void + NotifyServiceWorkerRegistrationRemoved(ServiceWorkerRegistrationInfo* aRegistration); + + void StartControllingADocument(ServiceWorkerRegistrationInfo* aRegistration, nsIDocument* aDoc); void StopControllingADocument(ServiceWorkerRegistrationInfo* aRegistration); already_AddRefed<ServiceWorkerRegistrationInfo> GetServiceWorkerRegistrationInfo(nsPIDOMWindow* aWindow);
--- a/dom/workers/ServiceWorkerManagerChild.cpp +++ b/dom/workers/ServiceWorkerManagerChild.cpp @@ -37,17 +37,17 @@ ServiceWorkerManagerChild::RecvNotifySof { if (mShuttingDown) { return true; } RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance(); MOZ_ASSERT(swm); - swm->SoftUpdate(aOriginAttributes, NS_ConvertUTF16toUTF8(aScope), nullptr); + swm->SoftUpdate(aOriginAttributes, NS_ConvertUTF16toUTF8(aScope)); return true; } bool ServiceWorkerManagerChild::RecvNotifyUnregister(const PrincipalInfo& aPrincipalInfo, const nsString& aScope) { if (mShuttingDown) {
--- a/dom/workers/ServiceWorkerPrivate.cpp +++ b/dom/workers/ServiceWorkerPrivate.cpp @@ -56,16 +56,17 @@ private: RefPtr<ServiceWorkerPrivate> mPrivate; }; NS_IMPL_ISUPPORTS0(KeepAliveToken) ServiceWorkerPrivate::ServiceWorkerPrivate(ServiceWorkerInfo* aInfo) : mInfo(aInfo) , mIsPushWorker(false) + , mDebuggerCount(0) , mTokenCount(0) { AssertIsOnMainThread(); MOZ_ASSERT(aInfo); mIdleWorkerTimer = do_CreateInstance(NS_TIMER_CONTRACTID); MOZ_ASSERT(mIdleWorkerTimer); } @@ -98,56 +99,74 @@ ServiceWorkerPrivate::SendMessageEvent(J return rv.StealNSResult(); } namespace { class CheckScriptEvaluationWithCallback final : public WorkerRunnable { nsMainThreadPtrHandle<KeepAliveToken> mKeepAliveToken; - RefPtr<nsRunnable> mCallback; + RefPtr<LifeCycleEventCallback> mCallback; + DebugOnly<bool> mDone; public: CheckScriptEvaluationWithCallback(WorkerPrivate* aWorkerPrivate, KeepAliveToken* aKeepAliveToken, - nsRunnable* aCallback) + LifeCycleEventCallback* aCallback) : WorkerRunnable(aWorkerPrivate, WorkerThreadModifyBusyCount) , mKeepAliveToken(new nsMainThreadPtrHolder<KeepAliveToken>(aKeepAliveToken)) , mCallback(aCallback) + , mDone(false) { AssertIsOnMainThread(); } + ~CheckScriptEvaluationWithCallback() + { + MOZ_ASSERT(mDone); + } + bool WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override { aWorkerPrivate->AssertIsOnWorkerThread(); - if (aWorkerPrivate->WorkerScriptExecutedSuccessfully()) { - nsresult rv = NS_DispatchToMainThread(mCallback); - if (NS_FAILED(rv)) { - NS_WARNING("Failed to dispatch CheckScriptEvaluation callback."); - } - } + Done(aWorkerPrivate->WorkerScriptExecutedSuccessfully()); return true; } + + NS_IMETHOD + Cancel() override + { + Done(false); + return WorkerRunnable::Cancel(); + } + +private: + void + Done(bool aResult) + { + mDone = true; + mCallback->SetResult(aResult); + MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToMainThread(mCallback))); + } }; } // anonymous namespace nsresult -ServiceWorkerPrivate::ContinueOnSuccessfulScriptEvaluation(nsRunnable* aCallback) +ServiceWorkerPrivate::CheckScriptEvaluation(LifeCycleEventCallback* aCallback) { nsresult rv = SpawnWorkerIfNeeded(LifeCycleEvent, nullptr); NS_ENSURE_SUCCESS(rv, rv); MOZ_ASSERT(mKeepAliveToken); RefPtr<WorkerRunnable> r = new CheckScriptEvaluationWithCallback(mWorkerPrivate, - mKeepAliveToken, - aCallback); + mKeepAliveToken, + aCallback); AutoJSAPI jsapi; jsapi.Init(); if (NS_WARN_IF(!r->Dispatch(jsapi.cx()))) { return NS_ERROR_FAILURE; } return NS_OK; } @@ -347,78 +366,151 @@ public: bool WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override { MOZ_ASSERT(aWorkerPrivate); return DispatchLifecycleEvent(aCx, aWorkerPrivate); } + NS_IMETHOD + Cancel() override + { + mCallback->SetResult(false); + MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToMainThread(mCallback))); + + return WorkerRunnable::Cancel(); + } + private: bool DispatchLifecycleEvent(JSContext* aCx, WorkerPrivate* aWorkerPrivate); }; /* - * Used to handle ExtendableEvent::waitUntil() and proceed with - * installation/activation. + * Used to handle ExtendableEvent::waitUntil() and catch abnormal worker + * termination during the execution of life cycle events. It is responsible + * with advancing the job queue for install/activate tasks. */ -class LifecycleEventPromiseHandler final : public PromiseNativeHandler +class LifeCycleEventWatcher final : public PromiseNativeHandler, + public WorkerFeature { + WorkerPrivate* mWorkerPrivate; RefPtr<LifeCycleEventCallback> mCallback; + bool mDone; - virtual - ~LifecycleEventPromiseHandler() - { } + ~LifeCycleEventWatcher() + { + if (mDone) { + return; + } + + MOZ_ASSERT(GetCurrentThreadWorkerPrivate() == mWorkerPrivate); + // XXXcatalinb: If all the promises passed to waitUntil go out of scope, + // the resulting Promise.all will be cycle collected and it will drop its + // native handlers (including this object). Instead of waiting for a timeout + // we report the failure now. + JSContext* cx = mWorkerPrivate->GetJSContext(); + ReportResult(cx, false); + } public: NS_DECL_ISUPPORTS - explicit LifecycleEventPromiseHandler(LifeCycleEventCallback* aCallback) - : mCallback(aCallback) + LifeCycleEventWatcher(WorkerPrivate* aWorkerPrivate, + LifeCycleEventCallback* aCallback) + : mWorkerPrivate(aWorkerPrivate) + , mCallback(aCallback) + , mDone(false) + { + MOZ_ASSERT(aWorkerPrivate); + aWorkerPrivate->AssertIsOnWorkerThread(); + } + + bool + Init() { - MOZ_ASSERT(!NS_IsMainThread()); + MOZ_ASSERT(mWorkerPrivate); + mWorkerPrivate->AssertIsOnWorkerThread(); + JSContext* cx = mWorkerPrivate->GetJSContext(); + + // We need to listen for worker termination in case the event handler + // never completes or never resolves the waitUntil promise. There are + // two possible scenarios: + // 1. The keepAlive token expires and the worker is terminated, in which + // case the registration/update promise will be rejected + // 2. A new service worker is registered which will terminate the current + // installing worker. + if (NS_WARN_IF(!mWorkerPrivate->AddFeature(cx, this))) { + NS_WARNING("LifeCycleEventWatcher failed to add feature."); + ReportResult(cx, false); + return false; + } + + return true; + } + + bool + Notify(JSContext* aCx, Status aStatus) override + { + if (aStatus < Terminating) { + return true; + } + + MOZ_ASSERT(GetCurrentThreadWorkerPrivate() == mWorkerPrivate); + ReportResult(aCx, false); + + return true; + } + + void + ReportResult(JSContext* aCx, bool aResult) + { + mWorkerPrivate->AssertIsOnWorkerThread(); + + if (mDone) { + return; + } + mDone = true; + + mCallback->SetResult(aResult); + nsresult rv = NS_DispatchToMainThread(mCallback); + if (NS_WARN_IF(NS_FAILED(rv))) { + NS_RUNTIMEABORT("Failed to dispatch life cycle event handler."); + } + + mWorkerPrivate->RemoveFeature(aCx, this); } void ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override { - WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate(); - MOZ_ASSERT(workerPrivate); - workerPrivate->AssertIsOnWorkerThread(); + MOZ_ASSERT(GetCurrentThreadWorkerPrivate() == mWorkerPrivate); + mWorkerPrivate->AssertIsOnWorkerThread(); - mCallback->SetResult(true); - nsresult rv = NS_DispatchToMainThread(mCallback); - if (NS_WARN_IF(NS_FAILED(rv))) { - NS_RUNTIMEABORT("Failed to dispatch life cycle event handler."); - } + ReportResult(aCx, true); } void RejectedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override { - WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate(); - MOZ_ASSERT(workerPrivate); - workerPrivate->AssertIsOnWorkerThread(); + MOZ_ASSERT(GetCurrentThreadWorkerPrivate() == mWorkerPrivate); + mWorkerPrivate->AssertIsOnWorkerThread(); - mCallback->SetResult(false); - nsresult rv = NS_DispatchToMainThread(mCallback); - if (NS_WARN_IF(NS_FAILED(rv))) { - NS_RUNTIMEABORT("Failed to dispatch life cycle event handler."); - } + ReportResult(aCx, false); // Note, all WaitUntil() rejections are reported to client consoles // by the WaitUntilHandler in ServiceWorkerEvents. This ensures that // errors in non-lifecycle events like FetchEvent and PushEvent are // reported properly. } }; -NS_IMPL_ISUPPORTS0(LifecycleEventPromiseHandler) +NS_IMPL_ISUPPORTS0(LifeCycleEventWatcher) bool LifecycleEventWorkerRunnable::DispatchLifecycleEvent(JSContext* aCx, WorkerPrivate* aWorkerPrivate) { aWorkerPrivate->AssertIsOnWorkerThread(); MOZ_ASSERT(aWorkerPrivate->IsServiceWorker()); @@ -431,26 +523,33 @@ LifecycleEventWorkerRunnable::DispatchLi init.mCancelable = false; event = ExtendableEvent::Constructor(target, mEventName, init); } else { MOZ_CRASH("Unexpected lifecycle event"); } event->SetTrusted(true); + // It is important to initialize the watcher before actually dispatching + // the event in order to catch worker termination while the event handler + // is still executing. This can happen with infinite loops, for example. + RefPtr<LifeCycleEventWatcher> watcher = + new LifeCycleEventWatcher(aWorkerPrivate, mCallback); + + if (!watcher->Init()) { + return true; + } + RefPtr<Promise> waitUntil; DispatchExtendableEventOnWorkerScope(aCx, aWorkerPrivate->GlobalScope(), event, getter_AddRefs(waitUntil)); if (waitUntil) { - RefPtr<LifecycleEventPromiseHandler> handler = - new LifecycleEventPromiseHandler(mCallback); - waitUntil->AppendNativeHandler(handler); + waitUntil->AppendNativeHandler(watcher); } else { - mCallback->SetResult(false); - MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToMainThread(mCallback))); + watcher->ReportResult(aCx, false); } return true; } } // anonymous namespace nsresult @@ -1326,17 +1425,17 @@ ServiceWorkerPrivate::SpawnWorkerIfNeede // XXXcatalinb: We need to have a separate load group that's linked to // an existing tab child to pass security checks on b2g. // This should be fixed in bug 1125961, but for now we enforce updating // the overriden load group when intercepting a fetch. MOZ_ASSERT_IF(aWhy == FetchEvent, aLoadGroup); if (mWorkerPrivate) { mWorkerPrivate->UpdateOverridenLoadGroup(aLoadGroup); - ResetIdleTimeout(aWhy); + RenewKeepAliveToken(aWhy); return NS_OK; } // Sanity check: mSupportsArray should be empty if we're about to // spin up a new worker. MOZ_ASSERT(mSupportsArray.IsEmpty()); @@ -1406,17 +1505,17 @@ ServiceWorkerPrivate::SpawnWorkerIfNeede scriptSpec, false, WorkerTypeService, mInfo->Scope(), &info, error); if (NS_WARN_IF(error.Failed())) { return error.StealNSResult(); } mIsPushWorker = false; - ResetIdleTimeout(aWhy); + RenewKeepAliveToken(aWhy); return NS_OK; } void ServiceWorkerPrivate::StoreISupports(nsISupports* aSupports) { AssertIsOnMainThread(); @@ -1472,17 +1571,17 @@ ServiceWorkerPrivate::NoteDeadServiceWor mInfo = nullptr; TerminateWorker(); } void ServiceWorkerPrivate::NoteStoppedControllingDocuments() { AssertIsOnMainThread(); - if (mIsPushWorker) { + if (mIsPushWorker || mDebuggerCount) { return; } TerminateWorker(); } void ServiceWorkerPrivate::Activated() @@ -1502,16 +1601,78 @@ ServiceWorkerPrivate::Activated() AutoJSAPI jsapi; jsapi.Init(); if (NS_WARN_IF(!r->Dispatch(jsapi.cx()))) { NS_WARNING("Failed to dispatch pending functional event!"); } } } +nsresult +ServiceWorkerPrivate::GetDebugger(nsIWorkerDebugger** aResult) +{ + AssertIsOnMainThread(); + MOZ_ASSERT(aResult); + + if (!mDebuggerCount) { + return NS_OK; + } + + MOZ_ASSERT(mWorkerPrivate); + + nsCOMPtr<nsIWorkerDebugger> debugger = do_QueryInterface(mWorkerPrivate->Debugger()); + debugger.forget(aResult); + + return NS_OK; +} + +nsresult +ServiceWorkerPrivate::AttachDebugger() +{ + AssertIsOnMainThread(); + + // When the first debugger attaches to a worker, we spawn a worker if needed, + // and cancel the idle timeout. The idle timeout should not be reset until + // the last debugger detached from the worker. + if (!mDebuggerCount) { + nsresult rv = SpawnWorkerIfNeeded(AttachEvent, nullptr); + NS_ENSURE_SUCCESS(rv, rv); + + mIdleWorkerTimer->Cancel(); + } + + ++mDebuggerCount; + + return NS_OK; +} + +nsresult +ServiceWorkerPrivate::DetachDebugger() +{ + AssertIsOnMainThread(); + + if (!mDebuggerCount) { + return NS_ERROR_UNEXPECTED; + } + + --mDebuggerCount; + + // When the last debugger detaches from a worker, we either reset the idle + // timeout, or terminate the worker if there are no more active tokens. + if (!mDebuggerCount) { + if (mTokenCount) { + ResetIdleTimeout(); + } else { + TerminateWorker(); + } + } + + return NS_OK; +} + /* static */ void ServiceWorkerPrivate::NoteIdleWorkerCallback(nsITimer* aTimer, void* aPrivate) { AssertIsOnMainThread(); MOZ_ASSERT(aPrivate); RefPtr<ServiceWorkerPrivate> swp = static_cast<ServiceWorkerPrivate*>(aPrivate); @@ -1545,34 +1706,46 @@ ServiceWorkerPrivate::TerminateWorkerCal MOZ_ASSERT(aTimer == serviceWorkerPrivate->mIdleWorkerTimer, "Invalid timer!"); serviceWorkerPrivate->TerminateWorker(); } void -ServiceWorkerPrivate::ResetIdleTimeout(WakeUpReason aWhy) +ServiceWorkerPrivate::RenewKeepAliveToken(WakeUpReason aWhy) { - // We should have an active worker if we're reseting the idle timeout + // We should have an active worker if we're renewing the keep alive token. MOZ_ASSERT(mWorkerPrivate); if (aWhy == PushEvent || aWhy == PushSubscriptionChangeEvent) { mIsPushWorker = true; } + // If there is at least one debugger attached to the worker, the idle worker + // timeout was canceled when the first debugger attached to the worker. It + // should not be reset until the last debugger detaches from the worker. + if (!mDebuggerCount) { + ResetIdleTimeout(); + } + + if (!mKeepAliveToken) { + mKeepAliveToken = new KeepAliveToken(this); + } +} + +void +ServiceWorkerPrivate::ResetIdleTimeout() +{ uint32_t timeout = Preferences::GetInt("dom.serviceWorkers.idle_timeout"); DebugOnly<nsresult> rv = mIdleWorkerTimer->InitWithFuncCallback(ServiceWorkerPrivate::NoteIdleWorkerCallback, this, timeout, nsITimer::TYPE_ONE_SHOT); MOZ_ASSERT(NS_SUCCEEDED(rv)); - if (!mKeepAliveToken) { - mKeepAliveToken = new KeepAliveToken(this); - } } void ServiceWorkerPrivate::AddToken() { AssertIsOnMainThread(); ++mTokenCount; }
--- a/dom/workers/ServiceWorkerPrivate.h +++ b/dom/workers/ServiceWorkerPrivate.h @@ -67,21 +67,19 @@ public: explicit ServiceWorkerPrivate(ServiceWorkerInfo* aInfo); nsresult SendMessageEvent(JSContext* aCx, JS::Handle<JS::Value> aMessage, const Optional<Sequence<JS::Value>>& aTransferable, UniquePtr<ServiceWorkerClientInfo>&& aClientInfo); // This is used to validate the worker script and continue the installation - // process. Note that the callback is dispatched to the main thread - // ONLY if the evaluation was successful. Failure is handled by the JS - // exception handler which will call ServiceWorkerManager::HandleError. + // process. nsresult - ContinueOnSuccessfulScriptEvaluation(nsRunnable* aCallback); + CheckScriptEvaluation(LifeCycleEventCallback* aCallback); nsresult SendLifeCycleEvent(const nsAString& aEventType, LifeCycleEventCallback* aCallback, nsIRunnable* aLoadFailure); nsresult SendPushEvent(const Maybe<nsTArray<uint8_t>>& aData, @@ -132,35 +130,48 @@ public: GetWorkerPrivate() const { return mWorkerPrivate; } void Activated(); + nsresult + GetDebugger(nsIWorkerDebugger** aResult); + + nsresult + AttachDebugger(); + + nsresult + DetachDebugger(); + private: enum WakeUpReason { FetchEvent = 0, PushEvent, PushSubscriptionChangeEvent, MessageEvent, NotificationClickEvent, - LifeCycleEvent + LifeCycleEvent, + AttachEvent }; // Timer callbacks static void NoteIdleWorkerCallback(nsITimer* aTimer, void* aPrivate); static void TerminateWorkerCallback(nsITimer* aTimer, void *aPrivate); void - ResetIdleTimeout(WakeUpReason aWhy); + RenewKeepAliveToken(WakeUpReason aWhy); + + void + ResetIdleTimeout(); void AddToken(); void ReleaseToken(); // |aLoadFailedRunnable| is a runnable dispatched to the main thread @@ -188,16 +199,18 @@ private: // woken up. The flag is reset to false every time a new WorkerPrivate // is created. bool mIsPushWorker; // We keep a token for |dom.serviceWorkers.idle_timeout| seconds to give the // worker a grace period after each event. RefPtr<KeepAliveToken> mKeepAliveToken; + uint64_t mDebuggerCount; + uint64_t mTokenCount; // Meant for keeping objects alive while handling requests from the worker // on the main thread. Access to this array is provided through // |StoreISupports| and |RemoveISupports|. Note that the array is also // cleared whenever the worker is terminated. nsTArray<nsCOMPtr<nsISupports>> mSupportsArray;
--- a/dom/workers/ServiceWorkerRegistration.cpp +++ b/dom/workers/ServiceWorkerRegistration.cpp @@ -245,34 +245,46 @@ ServiceWorkerRegistrationMainThread::Inv if (aWhichOnes & WhichServiceWorker::WAITING_WORKER) { mWaitingWorker = nullptr; } if (aWhichOnes & WhichServiceWorker::ACTIVE_WORKER) { mActiveWorker = nullptr; } + +} + +void +ServiceWorkerRegistrationMainThread::RegistrationRemoved() +{ + // If the registration is being removed completely, remove it from the + // window registration hash table so that a new registration would get a new + // wrapper JS object. + nsCOMPtr<nsPIDOMWindow> window = GetOwner(); + if (window) { + window->InvalidateServiceWorkerRegistration(mScope); + } } namespace { void UpdateInternal(nsIPrincipal* aPrincipal, const nsAString& aScope, ServiceWorkerUpdateFinishCallback* aCallback) { AssertIsOnMainThread(); MOZ_ASSERT(aPrincipal); MOZ_ASSERT(aCallback); RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance(); MOZ_ASSERT(swm); - // The spec defines ServiceWorkerRegistration.update() exactly as Soft Update. - swm->SoftUpdate(aPrincipal, NS_ConvertUTF16toUTF8(aScope), aCallback); + swm->Update(aPrincipal, NS_ConvertUTF16toUTF8(aScope), aCallback); } class MainThreadUpdateCallback final : public ServiceWorkerUpdateFinishCallback { RefPtr<Promise> mPromise; ~MainThreadUpdateCallback() { } @@ -388,24 +400,32 @@ public: {} NS_IMETHOD Run() override { AssertIsOnMainThread(); ErrorResult result; - MutexAutoLock lock(mPromiseProxy->Lock()); - if (mPromiseProxy->CleanedUp()) { - return NS_OK; + nsCOMPtr<nsIPrincipal> principal; + // UpdateInternal may try to reject the promise synchronously leading + // to a deadlock. + { + MutexAutoLock lock(mPromiseProxy->Lock()); + if (mPromiseProxy->CleanedUp()) { + return NS_OK; + } + + principal = mPromiseProxy->GetWorkerPrivate()->GetPrincipal(); } + MOZ_ASSERT(principal); RefPtr<WorkerThreadUpdateCallback> cb = new WorkerThreadUpdateCallback(mPromiseProxy); - UpdateInternal(mPromiseProxy->GetWorkerPrivate()->GetPrincipal(), mScope, cb); + UpdateInternal(principal, mScope, cb); return NS_OK; } private: ~UpdateRunnable() {} RefPtr<PromiseWorkerProxy> mPromiseProxy; @@ -853,16 +873,22 @@ public: void InvalidateWorkers(WhichServiceWorker aWhichOnes) override { AssertIsOnMainThread(); // FIXME(nsm); } void + RegistrationRemoved() override + { + AssertIsOnMainThread(); + } + + void GetScope(nsAString& aScope) const override { aScope = mScope; } ServiceWorkerRegistrationWorkerThread* GetRegistration() const {
--- a/dom/workers/ServiceWorkerRegistration.h +++ b/dom/workers/ServiceWorkerRegistration.h @@ -61,16 +61,19 @@ public: virtual void UpdateFound() = 0; virtual void InvalidateWorkers(WhichServiceWorker aWhichOnes) = 0; virtual void + RegistrationRemoved() = 0; + + virtual void GetScope(nsAString& aScope) const = 0; }; class ServiceWorkerRegistrationBase : public DOMEventTargetHelper { public: NS_DECL_ISUPPORTS_INHERITED @@ -101,19 +104,16 @@ protected: class ServiceWorkerRegistrationMainThread final : public ServiceWorkerRegistrationBase, public ServiceWorkerRegistrationListener { public: NS_DECL_ISUPPORTS_INHERITED NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(ServiceWorkerRegistrationMainThread, ServiceWorkerRegistrationBase) - ServiceWorkerRegistrationMainThread(nsPIDOMWindow* aWindow, - const nsAString& aScope); - already_AddRefed<Promise> Update(ErrorResult& aRv); already_AddRefed<Promise> Unregister(ErrorResult& aRv); JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override; @@ -150,22 +150,28 @@ public: // ServiceWorkerRegistrationListener void UpdateFound() override; void InvalidateWorkers(WhichServiceWorker aWhichOnes) override; void + RegistrationRemoved() override; + + void GetScope(nsAString& aScope) const override { aScope = mScope; } private: + friend nsPIDOMWindow; + ServiceWorkerRegistrationMainThread(nsPIDOMWindow* aWindow, + const nsAString& aScope); ~ServiceWorkerRegistrationMainThread(); already_AddRefed<workers::ServiceWorker> GetWorkerReference(WhichServiceWorker aWhichOne); void StartListeningForEvents();
--- a/dom/workers/WorkerScope.cpp +++ b/dom/workers/WorkerScope.cpp @@ -588,17 +588,19 @@ public: swm->SetSkipWaitingFlag(workerPrivate->GetPrincipal(), mScope, workerPrivate->ServiceWorkerID()); RefPtr<SkipWaitingResultRunnable> runnable = new SkipWaitingResultRunnable(workerPrivate, mPromiseProxy); AutoJSAPI jsapi; jsapi.Init(); - runnable->Dispatch(jsapi.cx()); + if (!runnable->Dispatch(jsapi.cx())) { + NS_WARNING("Failed to dispatch SkipWaitingResultRunnable to the worker."); + } return NS_OK; } }; } // namespace already_AddRefed<Promise> ServiceWorkerGlobalScope::SkipWaiting(ErrorResult& aRv)
--- a/dom/workers/test/serviceworkers/chrome.ini +++ b/dom/workers/test/serviceworkers/chrome.ini @@ -1,17 +1,19 @@ [DEFAULT] skip-if = buildapp == 'b2g' || os == 'android' support-files = app/* app2/* chrome_helpers.js + serviceworkerinfo_iframe.html serviceworkermanager_iframe.html serviceworkerregistrationinfo_iframe.html worker.js worker2.js [test_aboutserviceworkers.html] skip-if = true #bug 1193319 [test_app_installation.html] [test_privateBrowsing.html] +[test_serviceworkerinfo.xul] [test_serviceworkermanager.xul] [test_serviceworkerregistrationinfo.xul]
--- a/dom/workers/test/serviceworkers/chrome_helpers.js +++ b/dom/workers/test/serviceworkers/chrome_helpers.js @@ -52,8 +52,23 @@ function waitForServiceWorkerRegistratio callback(); } resolve(callback ? callback() : undefined); } }; registration.addListener(listener); }); } + +function waitForServiceWorkerShutdown() { + return new Promise(function (resolve) { + let observer = { + observe: function (subject, topic, data) { + if (topic !== "service-worker-shutdown") { + return; + } + SpecialPowers.removeObserver(observer, "service-worker-shutdown"); + resolve(); + } + }; + SpecialPowers.addObserver(observer, "service-worker-shutdown", false); + }); +}
new file mode 100644 --- /dev/null +++ b/dom/workers/test/serviceworkers/serviceworkerinfo_iframe.html @@ -0,0 +1,26 @@ +<!DOCTYPE html> +<html lang="en"> + <head> + <meta charset="utf-8"> + <script> + window.onmessage = function (event) { + if (event.data !== "register") { + return; + } + var promise = navigator.serviceWorker.register("worker.js"); + window.onmessage = function (event) { + if (event.data !== "unregister") { + return; + } + promise.then(function (registration) { + registration.unregister(); + }); + window.onmessage = null; + }; + }; + </script> + </head> + <body> + This is a test page. + </body> +<html>
--- a/dom/workers/test/serviceworkers/test_install_event.html +++ b/dom/workers/test/serviceworkers/test_install_event.html @@ -19,23 +19,36 @@ var p = navigator.serviceWorker.register("worker.js", { scope: "./install_event" }); return p; } function nextRegister(reg) { ok(reg instanceof ServiceWorkerRegistration, "reg should be a ServiceWorkerRegistration"); var p = navigator.serviceWorker.register("install_event_worker.js", { scope: "./install_event" }); return p.then(function(swr) { - ok(reg.scope === swr.scope, "Scope for registrations should match."); - return new Promise(function(resolve, reject) { + ok(reg === swr, "register should resolve to the same registration object"); + var update_found_promise = new Promise(function(resolve, reject) { swr.addEventListener('updatefound', function(e) { ok(true, "Received onupdatefound"); resolve(); }); }); + + var worker_activating = new Promise(function(res, reject) { + ok(swr.installing instanceof ServiceWorker, "There should be an installing worker if promise resolves."); + ok(swr.installing.state == "installing", "Installing worker's state should be 'installing'"); + swr.installing.onstatechange = function(e) { + if (e.target.state == "activating") { + e.target.onstatechange = null; + res(); + } + } + }); + + return Promise.all([update_found_promise, worker_activating]); }, function(e) { ok(false, "Unexpected Error in nextRegister! " + e); }); } function installError() { // Silence worker errors so they don't cause the test to fail. window.onerror = function(e) {}
new file mode 100644 --- /dev/null +++ b/dom/workers/test/serviceworkers/test_serviceworkerinfo.xul @@ -0,0 +1,101 @@ +<?xml version="1.0"?> +<!-- + Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ +--> +<window title="Test for ServiceWorkerInfo" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" + onload="test();"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/> + <script type="application/javascript" src="chrome_helpers.js"/> + <script type="application/javascript"> + <![CDATA[ + + let IFRAME_URL = EXAMPLE_URL + "serviceworkerinfo_iframe.html"; + + function wait_for_active_worker(registration) { + ok(registration, "Registration is valid."); + return new Promise(function(res, rej) { + if (registration.activeWorker) { + res(registration); + return; + } + let listener = { + onChange: function() { + if (registration.activeWorker) { + registration.removeListener(listener); + res(registration); + } + } + } + registration.addListener(listener); + }); + } + + function test() { + SimpleTest.waitForExplicitFinish(); + + SpecialPowers.pushPrefEnv({'set': [ + ["dom.serviceWorkers.enabled", true], + ["dom.serviceWorkers.idle_extended_timeout", 1000000], + ["dom.serviceWorkers.idle_timeout", 0], + ["dom.serviceWorkers.testing.enabled", true], + ]}, function () { + Task.spawn(function *() { + let iframe = $("iframe"); + let promise = new Promise(function (resolve) { + iframe.onload = function () { + resolve(); + }; + }); + iframe.src = IFRAME_URL; + yield promise; + + info("Check that a service worker eventually shuts down."); + promise = Promise.all([ + waitForRegister(EXAMPLE_URL), + waitForServiceWorkerShutdown() + ]); + iframe.contentWindow.postMessage("register", "*"); + let [registration] = yield promise; + + // Make sure the worker is active. + registration = yield wait_for_active_worker(registration); + + let activeWorker = registration.activeWorker; + ok(activeWorker !== null, "Worker is not active!"); + ok(activeWorker.debugger === null); + + info("Attach a debugger to the service worker, and check that the " + + "service worker is restarted."); + activeWorker.attachDebugger(); + ok(activeWorker.debugger !== null); + + info("Detach the debugger from the service worker, and check that " + + "the service worker eventually shuts down again."); + promise = waitForServiceWorkerShutdown(); + activeWorker.detachDebugger(); + yield promise; + ok(activeWorker.debugger === null); + + promise = waitForUnregister(EXAMPLE_URL); + iframe.contentWindow.postMessage("unregister", "*"); + registration = yield promise; + + SimpleTest.finish(); + }); + }); + } + + ]]> + </script> + + <body xmlns="http://www.w3.org/1999/xhtml"> + <p id="display"></p> + <div id="content" style="display:none;"></div> + <pre id="test"></pre> + <iframe id="iframe"></iframe> + </body> + <label id="test-result"/> +</window>
--- a/gfx/layers/apz/util/APZCCallbackHelper.cpp +++ b/gfx/layers/apz/util/APZCCallbackHelper.cpp @@ -417,44 +417,60 @@ APZCCallbackHelper::GetRootContentDocume CSSPoint APZCCallbackHelper::ApplyCallbackTransform(const CSSPoint& aInput, const ScrollableLayerGuid& aGuid) { CSSPoint input = aInput; if (aGuid.mScrollId == FrameMetrics::NULL_SCROLL_ID) { return input; } + nsCOMPtr<nsIContent> content = nsLayoutUtils::FindContentFor(aGuid.mScrollId); if (!content) { return input; } +#if !defined(MOZ_SINGLE_PROCESS_APZ) // First, scale inversely by the root content document's pres shell // resolution to cancel the scale-to-resolution transform that the // compositor adds to the layer with the pres shell resolution. The points // sent to Gecko by APZ don't have this transform unapplied (unlike other // compositor-side transforms) because APZ doesn't know about it. if (nsIPresShell* shell = GetRootContentDocumentPresShellForContent(content)) { input = input / shell->GetResolution(); } +#endif - // Now apply the callback-transform. + // Apply the callback-transform. // XXX: technically we need to walk all the way up the layer tree from the layer // represented by |aGuid.mScrollId| up to the root of the layer tree and apply // the input transforms at each level in turn. However, it is quite difficult // to do this given that the structure of the layer tree may be different from // the structure of the content tree. Also it may be impossible to do correctly // at this point because there are other CSS transforms and such interleaved in // between so applying the inputTransforms all in a row at the end may leave // some things transformed improperly. In practice we should rarely hit scenarios // where any of this matters, so I'm skipping it for now and just doing the single // transform for the layer that the input hit. + void* property = content->GetProperty(nsGkAtoms::apzCallbackTransform); if (property) { CSSPoint delta = (*static_cast<CSSPoint*>(property)); + +#if defined(MOZ_SINGLE_PROCESS_APZ) + // The delta is in root content document coordinate space while the + // aInput point is in root document coordinate space so convert the + // delta to root document space before adding it to the aInput point. + float resolution = 1.0f; + if (nsIPresShell* shell = GetRootContentDocumentPresShellForContent(content)) { + resolution = shell->GetResolution(); + } + delta.x = delta.x * resolution; + delta.y = delta.y * resolution; +#endif // MOZ_SINGLE_PROCESS_APZ input += delta; } return input; } LayoutDeviceIntPoint APZCCallbackHelper::ApplyCallbackTransform(const LayoutDeviceIntPoint& aPoint, const ScrollableLayerGuid& aGuid,
--- a/gfx/layers/apz/util/ChromeProcessController.cpp +++ b/gfx/layers/apz/util/ChromeProcessController.cpp @@ -142,16 +142,26 @@ ChromeProcessController::HandleDoubleTap } nsCOMPtr<nsIDocument> document = GetRootContentDocument(aGuid.mScrollId); if (!document.get()) { return; } CSSPoint point = APZCCallbackHelper::ApplyCallbackTransform(aPoint, aGuid); +#if defined(MOZ_SINGLE_PROCESS_APZ) + // CalculateRectToZoomTo performs a hit test on the frame associated with the + // Root Content Document. Unfortunately that frame does not know about the + // resolution of the document and so we must remove it before calculating + // the zoomToRect. + nsIPresShell* presShell = document->GetShell(); + const float resolution = presShell->ScaleToResolution() ? presShell->GetResolution () : 1.0f; + point.x = point.x / resolution; + point.y = point.y / resolution; +#endif // MOZ_SINGLE_PROCESS_APZ CSSRect zoomToRect = CalculateRectToZoomTo(document, point); uint32_t presShellId; FrameMetrics::ViewID viewId; if (APZCCallbackHelper::GetOrCreateScrollIdentifiers( document->GetDocumentElement(), &presShellId, &viewId)) { mAPZCTreeManager->ZoomToRect( ScrollableLayerGuid(aGuid.mLayersId, presShellId, viewId), zoomToRect);
--- a/gfx/layers/basic/BasicLayerManager.cpp +++ b/gfx/layers/basic/BasicLayerManager.cpp @@ -123,16 +123,26 @@ BasicLayerManager::PushGroupForLayer(gfx group.mMaskSurface = GetMaskForLayer(aLayer, &group.mMaskTransform); return group; } } Matrix maskTransform; RefPtr<SourceSurface> maskSurf = GetMaskForLayer(aLayer, &maskTransform); + if (maskSurf) { + // The returned transform will transform the mask to device space on the + // destination. Since the User->Device space transform will be applied + // to the mask by PopGroupAndBlend we need to adjust the transform to + // transform the mask to user space. + Matrix currentTransform = ToMatrix(group.mFinalTarget->CurrentMatrix()); + currentTransform.Invert(); + maskTransform = maskTransform * currentTransform; + } + if (aLayer->CanUseOpaqueSurface() && ((didCompleteClip && aRegion.GetNumRects() == 1) || !aContext->CurrentMatrix().HasNonIntegerTranslation())) { // If the layer is opaque in its visible region we can push a gfxContentType::COLOR // group. We need to make sure that only pixels inside the layer's visible // region are copied back to the destination. Remember if we've already // clipped precisely to the visible region. group.mNeedsClipToVisibleRegion = !didCompleteClip || aRegion.GetNumRects() > 1; @@ -167,18 +177,22 @@ BasicLayerManager::PopGroupForLayer(Push DrawTarget* dt = group.mFinalTarget->GetDrawTarget(); RefPtr<DrawTarget> sourceDT = group.mGroupTarget->GetDrawTarget(); group.mGroupTarget = nullptr; RefPtr<SourceSurface> src = sourceDT->Snapshot(); if (group.mMaskSurface) { - dt->SetTransform(group.mMaskTransform * Matrix::Translation(-group.mFinalTarget->GetDeviceOffset())); - dt->MaskSurface(SurfacePattern(src, ExtendMode::CLAMP, Matrix::Translation(group.mGroupOffset.x, group.mGroupOffset.y)), + Point finalOffset = group.mFinalTarget->GetDeviceOffset(); + dt->SetTransform(group.mMaskTransform * Matrix::Translation(-finalOffset)); + Matrix surfTransform = group.mMaskTransform; + surfTransform.Invert(); + dt->MaskSurface(SurfacePattern(src, ExtendMode::CLAMP, surfTransform * + Matrix::Translation(group.mGroupOffset.x, group.mGroupOffset.y)), group.mMaskSurface, Point(0, 0), DrawOptions(group.mOpacity, group.mOperator)); } else { // For now this is required since our group offset is in device space of the final target, // context but that may still have its own device offset. Once PushGroup/PopGroup logic is // migrated to DrawTargets this can go as gfxContext::GetDeviceOffset will essentially // always become null. dt->SetTransform(Matrix::Translation(-group.mFinalTarget->GetDeviceOffset())); dt->DrawSurface(src, Rect(group.mGroupOffset.x, group.mGroupOffset.y, src->GetSize().width, src->GetSize().height),
--- a/gfx/layers/ipc/CompositorParent.cpp +++ b/gfx/layers/ipc/CompositorParent.cpp @@ -1659,21 +1659,23 @@ CompositorParent::SetControllerForLayerT aLayersId, aController)); } /*static*/ APZCTreeManager* CompositorParent::GetAPZCTreeManager(uint64_t aLayersId) { EnsureLayerTreeMapReady(); - const CompositorParent::LayerTreeState* state = CompositorParent::GetIndirectShadowTree(aLayersId); - if (state && state->mParent) { - return state->mParent->mApzcTreeManager; + MonitorAutoLock lock(*sIndirectLayerTreesLock); + LayerTreeMap::iterator cit = sIndirectLayerTrees.find(aLayersId); + if (sIndirectLayerTrees.end() == cit) { + return nullptr; } - return nullptr; + LayerTreeState* lts = &cit->second; + return (lts->mParent ? lts->mParent->mApzcTreeManager.get() : nullptr); } float CompositorParent::ComputeRenderIntegrity() { if (mLayerManager) { return mLayerManager->ComputeRenderIntegrity(); }
--- a/gfx/src/nsPoint.h +++ b/gfx/src/nsPoint.h @@ -32,16 +32,21 @@ struct nsPoint : public mozilla::gfx::Ba /** * Return this point scaled to a different appunits per pixel (APP) ratio. * @param aFromAPP the APP to scale from * @param aToAPP the APP to scale to */ MOZ_WARN_UNUSED_RESULT inline nsPoint ScaleToOtherAppUnits(int32_t aFromAPP, int32_t aToAPP) const; + + MOZ_WARN_UNUSED_RESULT inline nsPoint + RemoveResolution(const float resolution) const; + MOZ_WARN_UNUSED_RESULT inline nsPoint + ApplyResolution(const float resolution) const; }; inline nsPoint ToAppUnits(const nsIntPoint& aPoint, nscoord aAppUnitsPerPixel); inline nsIntPoint nsPoint::ScaleToNearestPixels(float aXScale, float aYScale, nscoord aAppUnitsPerPixel) const { @@ -63,16 +68,38 @@ nsPoint::ScaleToOtherAppUnits(int32_t aF nsPoint point; point.x = NSToCoordRound(NSCoordScale(x, aFromAPP, aToAPP)); point.y = NSToCoordRound(NSCoordScale(y, aFromAPP, aToAPP)); return point; } return *this; } +inline nsPoint +nsPoint::RemoveResolution(const float resolution) const { + if (resolution != 1.0f) { + nsPoint point; + point.x = NSToCoordRound(NSCoordToFloat(x) / resolution); + point.y = NSToCoordRound(NSCoordToFloat(y) / resolution); + return point; + } + return *this; +} + +inline nsPoint +nsPoint::ApplyResolution(const float resolution) const { + if (resolution != 1.0f) { + nsPoint point; + point.x = NSToCoordRound(NSCoordToFloat(x) * resolution); + point.y = NSToCoordRound(NSCoordToFloat(y) * resolution); + return point; + } + return *this; +} + // app units are integer multiples of pixels, so no rounding needed inline nsPoint ToAppUnits(const nsIntPoint& aPoint, nscoord aAppUnitsPerPixel) { return nsPoint(NSIntPixelsToAppUnits(aPoint.x, aAppUnitsPerPixel), NSIntPixelsToAppUnits(aPoint.y, aAppUnitsPerPixel)); }
--- a/gfx/src/nsRect.h +++ b/gfx/src/nsRect.h @@ -166,16 +166,18 @@ struct nsRect : MOZ_WARN_UNUSED_RESULT inline mozilla::gfx::IntRect ToInsidePixels(nscoord aAppUnitsPerPixel) const; // This is here only to keep IPDL-generated code happy. DO NOT USE. bool operator==(const nsRect& aRect) const { return IsEqualEdges(aRect); } + + MOZ_WARN_UNUSED_RESULT inline nsRect RemoveResolution(const float aResolution) const; }; /* * App Unit/Pixel conversions */ inline nsRect nsRect::ScaleToOtherAppUnitsRoundOut(int32_t aFromAPP, int32_t aToAPP) const @@ -274,16 +276,35 @@ nsRect::ToOutsidePixels(nscoord aAppUnit } inline mozilla::gfx::IntRect nsRect::ToInsidePixels(nscoord aAppUnitsPerPixel) const { return ScaleToInsidePixels(1.0f, 1.0f, aAppUnitsPerPixel); } +inline nsRect +nsRect::RemoveResolution(const float aResolution) const +{ + MOZ_ASSERT(aResolution > 0.0f); + nsRect rect; + rect.x = NSToCoordRound(NSCoordToFloat(x) / aResolution); + rect.y = NSToCoordRound(NSCoordToFloat(y) / aResolution); + // A 1x1 rect indicates we are just hit testing a point, so pass down a 1x1 + // rect as well instead of possibly rounding the width or height to zero. + if (width == 1 && height == 1) { + rect.width = rect.height = 1; + } else { + rect.width = NSToCoordCeil(NSCoordToFloat(width) / aResolution); + rect.height = NSToCoordCeil(NSCoordToFloat(height) / aResolution); + } + + return rect; +} + const mozilla::gfx::IntRect& GetMaxSizedIntRect(); // app units are integer multiples of pixels, so no rounding needed nsRect ToAppUnits(const mozilla::gfx::IntRect& aRect, nscoord aAppUnitsPerPixel); #ifdef DEBUG // Diagnostics
--- a/gfx/thebes/gfxUserFontSet.cpp +++ b/gfx/thebes/gfxUserFontSet.cpp @@ -11,16 +11,17 @@ #include "nsNetUtil.h" #include "nsIJARChannel.h" #include "nsIProtocolHandler.h" #include "nsIPrincipal.h" #include "nsIZipReader.h" #include "gfxFontConstants.h" #include "mozilla/Preferences.h" #include "mozilla/Services.h" +#include "mozilla/Telemetry.h" #include "mozilla/gfx/2D.h" #include "gfxPlatformFontList.h" #include "opentype-sanitiser.h" #include "ots-memory-stream.h" using namespace mozilla; @@ -422,16 +423,18 @@ gfxUserFontEntry::LoadNextSrc() fe->mFamilyName = mFamilyName; // For src:local(), we don't care whether the request is from // a private window as there's no issue of caching resources; // local fonts are just available all the time. StoreUserFontData(fe, false, nsString(), nullptr, 0, gfxUserFontData::kUnknownCompression); mPlatformFontEntry = fe; SetLoadState(STATUS_LOADED); + Telemetry::Accumulate(Telemetry::WEBFONT_SRCTYPE, + currSrc.mSourceType + 1); return; } else { LOG(("userfonts (%p) [src %d] failed local: (%s) for (%s)\n", mFontSet, mSrcIndex, NS_ConvertUTF16toUTF8(currSrc.mLocalName).get(), NS_ConvertUTF16toUTF8(mFamilyName).get())); } } @@ -452,16 +455,24 @@ gfxUserFontEntry::LoadNextSrc() gfxFontEntry* fe = gfxUserFontSet:: UserFontCache::GetFont(currSrc.mURI, principal, this, mFontSet->GetPrivateBrowsing()); if (fe) { mPlatformFontEntry = fe; SetLoadState(STATUS_LOADED); + if (LOG_ENABLED()) { + nsAutoCString fontURI; + currSrc.mURI->GetSpec(fontURI); + LOG(("userfonts (%p) [src %d] " + "loaded uri from cache: (%s) for (%s)\n", + mFontSet, mSrcIndex, fontURI.get(), + NS_ConvertUTF16toUTF8(mFamilyName).get())); + } return; } } // record the principal returned by CheckFontLoad, // for use when creating a channel // and when caching the loaded entry mPrincipal = principal; @@ -477,16 +488,18 @@ gfxUserFontEntry::LoadNextSrc() // sync load font immediately rv = mFontSet->SyncLoadFontData(this, &currSrc, buffer, bufferLength); if (NS_SUCCEEDED(rv) && LoadPlatformFont(buffer, bufferLength)) { SetLoadState(STATUS_LOADED); + Telemetry::Accumulate(Telemetry::WEBFONT_SRCTYPE, + currSrc.mSourceType + 1); return; } else { mFontSet->LogMessage(this, "font load failed", nsIScriptError::errorFlag, rv); } @@ -531,16 +544,18 @@ gfxUserFontEntry::LoadNextSrc() uint32_t bufferLength = 0; // sync load font immediately currSrc.mBuffer->TakeBuffer(buffer, bufferLength); if (buffer && LoadPlatformFont(buffer, bufferLength)) { // LoadPlatformFont takes ownership of the buffer, so no need // to free it here. SetLoadState(STATUS_LOADED); + Telemetry::Accumulate(Telemetry::WEBFONT_SRCTYPE, + currSrc.mSourceType + 1); return; } else { mFontSet->LogMessage(this, "font load failed", nsIScriptError::errorFlag); } } @@ -572,34 +587,47 @@ gfxUserFontEntry::LoadPlatformFont(const mUserFontLoadState == STATUS_LOADING) && mFontDataLoadingState < LOADING_FAILED, "attempting to load a font that has either completed or failed"); gfxFontEntry* fe = nullptr; gfxUserFontType fontType = gfxFontUtils::DetermineFontDataType(aFontData, aLength); + Telemetry::Accumulate(Telemetry::WEBFONT_FONTTYPE, uint32_t(fontType)); // Unwrap/decompress/sanitize or otherwise munge the downloaded data // to make a usable sfnt structure. // Because platform font activation code may replace the name table // in the font with a synthetic one, we save the original name so that // it can be reported via the nsIDOMFontFace API. nsAutoString originalFullName; // Call the OTS sanitizer; this will also decode WOFF to sfnt // if necessary. The original data in aFontData is left unchanged. uint32_t saneLen; + uint32_t fontCompressionRatio = 0; const uint8_t* saneData = SanitizeOpenTypeData(aFontData, aLength, saneLen, fontType); if (!saneData) { mFontSet->LogMessage(this, "rejected by sanitizer"); } if (saneData) { + if (saneLen) { + fontCompressionRatio = uint32_t(100.0 * aLength / saneLen + 0.5); + if (fontType == GFX_USERFONT_WOFF || + fontType == GFX_USERFONT_WOFF2) { + Telemetry::Accumulate(fontType == GFX_USERFONT_WOFF ? + Telemetry::WEBFONT_COMPRESSION_WOFF : + Telemetry::WEBFONT_COMPRESSION_WOFF2, + fontCompressionRatio); + } + } + // The sanitizer ensures that we have a valid sfnt and a usable // name table, so this should never fail unless we're out of // memory, and GetFullNameFromSFNT is not directly exposed to // arbitrary/malicious data from the web. gfxFontUtils::GetFullNameFromSFNT(saneData, saneLen, originalFullName); // Here ownership of saneData is passed to the platform, // which will delete it when no longer required @@ -636,21 +664,21 @@ gfxUserFontEntry::LoadPlatformFont(const fe->mFeatureSettings.AppendElements(mFeatureSettings); fe->mLanguageOverride = mLanguageOverride; fe->mFamilyName = mFamilyName; StoreUserFontData(fe, mFontSet->GetPrivateBrowsing(), originalFullName, &metadata, metaOrigLen, compression); if (LOG_ENABLED()) { nsAutoCString fontURI; mSrcList[mSrcIndex].mURI->GetSpec(fontURI); - LOG(("userfonts (%p) [src %d] loaded uri: (%s) for (%s) (%p) gen: %8.8x\n", + LOG(("userfonts (%p) [src %d] loaded uri: (%s) for (%s) " + "(%p) gen: %8.8x compress: %d%%\n", mFontSet, mSrcIndex, fontURI.get(), NS_ConvertUTF16toUTF8(mFamilyName).get(), - this, - uint32_t(mFontSet->mGeneration))); + this, uint32_t(mFontSet->mGeneration), fontCompressionRatio)); } mPlatformFontEntry = fe; SetLoadState(STATUS_LOADED); gfxUserFontSet::UserFontCache::CacheFont(fe); } else { if (LOG_ENABLED()) { nsAutoCString fontURI; mSrcList[mSrcIndex].mURI->GetSpec(fontURI); @@ -733,17 +761,20 @@ gfxUserFontEntry::FontDataDownloadComple void gfxUserFontEntry::GetUserFontSets(nsTArray<gfxUserFontSet*>& aResult) { aResult.Clear(); aResult.AppendElement(mFontSet); } gfxUserFontSet::gfxUserFontSet() - : mFontFamilies(4), mLocalRulesUsed(false) + : mFontFamilies(4), + mLocalRulesUsed(false), + mDownloadCount(0), + mDownloadSize(0) { IncrementGeneration(true); gfxPlatformFontList* fp = gfxPlatformFontList::PlatformFontList(); if (fp) { fp->AddUserFontSet(this); } }
--- a/gfx/thebes/gfxUserFontSet.h +++ b/gfx/thebes/gfxUserFontSet.h @@ -463,16 +463,25 @@ public: }; void SetLocalRulesUsed() { mLocalRulesUsed = true; } static mozilla::LogModule* GetUserFontsLog(); + // record statistics about font completion + virtual void RecordFontLoadDone(uint32_t aFontSize, + mozilla::TimeStamp aDoneTime) {} + + void GetLoadStatistics(uint32_t& aLoadCount, uint64_t& aLoadSize) const { + aLoadCount = mDownloadCount; + aLoadSize = mDownloadSize; + } + protected: // Protected destructor, to discourage deletion outside of Release(): virtual ~gfxUserFontSet(); // Return whether the font set is associated with a private-browsing tab. virtual bool GetPrivateBrowsing() = 0; // parse data for a data URL @@ -508,16 +517,20 @@ protected: // font families defined by @font-face rules nsRefPtrHashtable<nsStringHashKey, gfxUserFontFamily> mFontFamilies; uint64_t mGeneration; // bumped on any font load change uint64_t mRebuildGeneration; // only bumped on rebuilds // true when local names have been looked up, false otherwise bool mLocalRulesUsed; + + // performance stats + uint32_t mDownloadCount; + uint64_t mDownloadSize; }; // acts a placeholder until the real font is downloaded class gfxUserFontEntry : public gfxFontEntry { friend class gfxUserFontSet; friend class nsUserFontSet; friend class nsFontFaceLoader;
--- a/intl/unicharutil/tools/genUnicodePropertyData.pl +++ b/intl/unicharutil/tools/genUnicodePropertyData.pl @@ -14,16 +14,17 @@ # (1) Download the current Unicode data files from # # http://www.unicode.org/Public/UNIDATA/ # # NB: not all the files are actually needed; currently, we require # - UnicodeData.txt # - Scripts.txt # - BidiMirroring.txt +# - BidiBrackets.txt # - HangulSyllableType.txt # - ReadMe.txt (to record version/date of the UCD) # - Unihan_Variants.txt (from Unihan.zip) # though this may change if we find a need for additional properties. # # The Unicode data files listed above should be together in one directory. # # We also require the file @@ -329,28 +330,30 @@ my %verticalOrientationCode = ( 'Tr' => 3 # Tr - Transformed typographically, with fallback to Rotated ); # initialize default properties my @script; my @category; my @combining; my @mirror; +my @pairedBracketType; my @hangul; my @casemap; my @xidmod; my @numericvalue; my @hanVariant; my @bidicategory; my @fullWidth; my @verticalOrientation; for (my $i = 0; $i < 0x110000; ++$i) { $script[$i] = $scriptCode{"UNKNOWN"}; $category[$i] = $catCode{"UNASSIGNED"}; $combining[$i] = 0; + $pairedBracketType[$i] = 0; $casemap[$i] = 0; $xidmod[$i] = $xidmodCode{"not-chars"}; $numericvalue[$i] = -1; $hanVariant[$i] = 0; $bidicategory[$i] = $bidicategoryCode{"L"}; $fullWidth[$i] = 0; $verticalOrientation[$i] = 1; # default for unlisted codepoints is 'R' } @@ -518,23 +521,48 @@ while (<FH>) { chomp; push @versionInfo, $_; last if /Date:/; } while (<FH>) { s/#.*//; if (m/([0-9A-F]{4,6});\s*([0-9A-F]{4,6})/) { my $mirrorOffset = hex("0x$2") - hex("0x$1"); - my $offsetIndex = first { $offsets[$_] eq $mirrorOffset } 0..$#offsets; - if ($offsetIndex == undef) { + my $offsetIndex = first { $offsets[$_] eq $mirrorOffset } 0..$#offsets; + if ($offsetIndex == undef) { die "too many offset codes\n" if scalar @offsets == 31; push @offsets, $mirrorOffset; - $offsetIndex = $#offsets; + $offsetIndex = $#offsets; } - $mirror[hex "0x$1"] = $offsetIndex; + $mirror[hex "0x$1"] = $offsetIndex; + } +} +close FH; + +# read BidiBrackets.txt +my %pairedBracketTypeCode = ( + 'N' => 0, + 'O' => 1, + 'C' => 2 +); +open FH, "< $ARGV[1]/BidiBrackets.txt" or die "can't open UCD file BidiBrackets.txt\n"; +push @versionInfo, ""; +while (<FH>) { + chomp; + push @versionInfo, $_; + last if /Date:/; +} +while (<FH>) { + s/#.*//; + if (m/([0-9A-F]{4,6});\s*([0-9A-F]{4,6});\s*(.)/) { + my $mirroredChar = $offsets[$mirror[hex "0x$1"]] + hex "0x$1"; + die "bidi bracket does not match mirrored char\n" unless $mirroredChar == hex "0x$2"; + my $pbt = uc($3); + warn "unknown Bidi Bracket type" unless exists $pairedBracketTypeCode{$pbt}; + $pairedBracketType[hex "0x$1"] = $pairedBracketTypeCode{$pbt}; } } close FH; # read HangulSyllableType.txt my %hangulType = ( 'L' => 0x01, 'V' => 0x02, @@ -731,37 +759,37 @@ my $type = q/ struct nsCharProps1 { unsigned char mMirrorOffsetIndex:5; unsigned char mHangulType:3; unsigned char mCombiningClass:8; }; /; print DATA_TABLES "#ifndef ENABLE_INTL_API\n"; &genTables("CharProp1", $type, "nsCharProps1", 11, 5, \&sprintCharProps1, 1, 2, 1); -+print DATA_TABLES "#endif\n\n"; +print DATA_TABLES "#endif\n\n"; sub sprintCharProps2 { my $usv = shift; return sprintf("{%d,%d,%d,%d,%d,%d,%d},", - $script[$usv], 0, $category[$usv], + $script[$usv], $pairedBracketType[$usv], $category[$usv], $bidicategory[$usv], $xidmod[$usv], $numericvalue[$usv], $verticalOrientation[$usv]); } -$type = q/ +$type = q| struct nsCharProps2 { unsigned char mScriptCode:8; - unsigned char mUnused:3; + unsigned char mPairedBracketType:3; // only 2 bits actually needed unsigned char mCategory:5; unsigned char mBidiCategory:5; unsigned char mXidmod:4; signed char mNumericValue:5; unsigned char mVertOrient:2; }; -/; +|; &genTables("CharProp2", $type, "nsCharProps2", 11, 5, \&sprintCharProps2, 16, 4, 1); print HEADER "#pragma pack()\n\n"; sub sprintHanVariants { my $baseUsv = shift; my $varShift = 0;
--- a/intl/unicharutil/util/nsUnicodeProperties.cpp +++ b/intl/unicharutil/util/nsUnicodeProperties.cpp @@ -165,16 +165,36 @@ GetScriptTagForCode(int32_t aScriptCode) { // this will safely return 0 for negative script codes, too :) if (uint32_t(aScriptCode) > ArrayLength(sScriptCodeToTag)) { return 0; } return sScriptCodeToTag[aScriptCode]; } +PairedBracketType GetPairedBracketType(uint32_t aCh) +{ +#if ENABLE_INTL_API + return PairedBracketType + (u_getIntPropertyValue(aCh, UCHAR_BIDI_PAIRED_BRACKET_TYPE)); +#else + return PairedBracketType(GetCharProps2(aCh).mPairedBracketType); +#endif +} + +uint32_t GetPairedBracket(uint32_t aCh) +{ +#if ENABLE_INTL_API + return u_getBidiPairedBracket(aCh); +#else + return GetPairedBracketType(aCh) != PAIRED_BRACKET_TYPE_NONE + ? GetMirroredChar(aCh) : aCh; +#endif +} + static inline uint32_t GetCaseMapValue(uint32_t aCh) { if (aCh < UNICODE_BMP_LIMIT) { return sCaseMapValues[sCaseMapPages[0][aCh >> kCaseMapCharBits]] [aCh & ((1 << kCaseMapCharBits) - 1)]; } if (aCh < (kCaseMapMaxPlane + 1) * 0x10000) {
--- a/intl/unicharutil/util/nsUnicodeProperties.h +++ b/intl/unicharutil/util/nsUnicodeProperties.h @@ -52,16 +52,26 @@ enum VerticalOrientation { VERTICAL_ORIENTATION_Tu = 2, VERTICAL_ORIENTATION_Tr = 3 }; inline VerticalOrientation GetVerticalOrientation(uint32_t aCh) { return VerticalOrientation(GetCharProps2(aCh).mVertOrient); } +/* This MUST match the values assigned by genUnicodePropertyData.pl! */ +enum PairedBracketType { + PAIRED_BRACKET_TYPE_NONE = 0, + PAIRED_BRACKET_TYPE_OPEN = 1, + PAIRED_BRACKET_TYPE_CLOSE = 2 +}; + +PairedBracketType GetPairedBracketType(uint32_t aCh); +uint32_t GetPairedBracket(uint32_t aCh); + enum XidmodType { XIDMOD_RECOMMENDED, XIDMOD_INCLUSION, XIDMOD_UNCOMMON_USE, XIDMOD_TECHNICAL, XIDMOD_OBSOLETE, XIDMOD_ASPIRATIONAL, XIDMOD_LIMITED_USE,
--- a/intl/unicharutil/util/nsUnicodePropertyData.cpp +++ b/intl/unicharutil/util/nsUnicodePropertyData.cpp @@ -6,17 +6,17 @@ /* * Derived from the Unicode Character Database by genUnicodePropertyData.pl * * For Unicode terms of use, see http://www.unicode.org/terms_of_use.html */ /* - * Created on Mon Sep 7 02:52:23 2015 from UCD data files with version info: + * Created on Tue Nov 17 07:34:16 2015 from UCD data files with version info: * # Date: 2015-06-16, 20:24:00 GMT [KW] # # Unicode Character Database # Copyright (c) 1991-2015 Unicode, Inc. # For terms of use, see http://www.unicode.org/terms_of_use.html # @@ -33,16 +33,19 @@ Standard. # Scripts-8.0.0.txt # Date: 2015-03-11, 22:29:42 GMT [MD] # BidiMirroring-8.0.0.txt # Date: 2015-01-20, 18:30:00 GMT [KW, LI] +# BidiBrackets-8.0.0.txt +# Date: 2015-01-20, 19:00:00 GMT [AG, LI, KW] + # HangulSyllableType-8.0.0.txt # Date: 2014-12-16, 23:07:45 GMT [MD] # File: xidmodifications.txt # Version: 8.0.0 # Generated: 2015-05-17, 03:09:04 GMT # @@ -406,19 +409,19 @@ static const uint16_t sCharProp2Pages[7] {320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,639}, {110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110}, {640,641,641,642,110,110,110,110,643,643,643,643,643,643,643,644,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110}, {377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,645} }; static const nsCharProps2 sCharProp2Values[646][32] = { {{0,0,0,18,12,-1,1},{0,0,0,18,12,-1,1},{0,0,0,18,12,-1,1},{0,0,0,18,12,-1,1},{0,0,0,18,12,-1,1},{0,0,0,18,12,-1,1},{0,0,0,18,12,-1,1},{0,0,0,18,12,-1,1},{0,0,0,18,12,-1,1},{0,0,0,8,8,-1,1},{0,0,0,7,8,-1,1},{0,0,0,8,8,-1,1},{0,0,0,9,8,-1,1},{0,0,0,7,8,-1,1},{0,0,0,18,12,-1,1},{0,0,0,18,12,-1,1},{0,0,0,18,12,-1,1},{0,0,0,18,12,-1,1},{0,0,0,18,12,-1,1},{0,0,0,18,12,-1,1},{0,0,0,18,12,-1,1},{0,0,0,18,12,-1,1},{0,0,0,18,12,-1,1},{0,0,0,18,12,-1,1},{0,0,0,18,12,-1,1},{0,0,0,18,12,-1,1},{0,0,0,18,12,-1,1},{0,0,0,18,12,-1,1},{0,0,0,7,12,-1,1},{0,0,0,7,12,-1,1},{0,0,0,7,12,-1,1},{0,0,0,8,12,-1,1}}, - {{0,0,29,9,8,-1,1},{0,0,21,10,8,-1,1},{0,0,21,10,8,-1,1},{0,0,21,4,8,-1,1},{0,0,23,4,8,-1,1},{0,0,21,4,8,-1,1},{0,0,21,10,8,-1,1},{0,0,21,10,1,-1,1},{0,0,22,10,8,-1,1},{0,0,18,10,8,-1,1},{0,0,21,10,8,-1,1},{0,0,25,3,8,-1,1},{0,0,21,6,8,-1,1},{0,0,17,3,1,-1,1},{0,0,21,6,1,-1,1},{0,0,21,6,8,-1,1},{0,0,13,2,0,0,1},{0,0,13,2,0,1,1},{0,0,13,2,0,2,1},{0,0,13,2,0,3,1},{0,0,13,2,0,4,1},{0,0,13,2,0,5,1},{0,0,13,2,0,6,1},{0,0,13,2,0,7,1},{0,0,13,2,0,8,1},{0,0,13,2,0,9,1},{0,0,21,6,1,-1,1},{0,0,21,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,21,10,8,-1,1}}, - {{0,0,21,10,8,-1,1},{25,0,9,0,0,-1,1},{25,0,9,0,0,-1,1},{25,0,9,0,0,-1,1},{25,0,9,0,0,-1,1},{25,0,9,0,0,-1,1},{25,0,9,0,0,-1,1},{25,0,9,0,0,-1,1},{25,0,9,0,0,-1,1},{25,0,9,0,0,-1,1},{25,0,9,0,0,-1,1},{25,0,9,0,0,-1,1},{25,0,9,0,0,-1,1},{25,0,9,0,0,-1,1},{25,0,9,0,0,-1,1},{25,0,9,0,0,-1,1},{25,0,9,0,0,-1,1},{25,0,9,0,0,-1,1},{25,0,9,0,0,-1,1},{25,0,9,0,0,-1,1},{25,0,9,0,0,-1,1},{25,0,9,0,0,-1,1},{25,0,9,0,0,-1,1},{25,0,9,0,0,-1,1},{25,0,9,0,0,-1,1},{25,0,9,0,0,-1,1},{25,0,9,0,0,-1,1},{0,0,22,10,8,-1,1},{0,0,21,10,8,-1,1},{0,0,18,10,8,-1,1},{0,0,24,10,8,-1,1},{0,0,16,10,0,-1,1}}, - {{0,0,24,10,8,-1,1},{25,0,5,0,0,-1,1},{25,0,5,0,0,-1,1},{25,0,5,0,0,-1,1},{25,0,5,0,0,-1,1},{25,0,5,0,0,-1,1},{25,0,5,0,0,-1,1},{25,0,5,0,0,-1,1},{25,0,5,0,0,-1,1},{25,0,5,0,0,-1,1},{25,0,5,0,0,-1,1},{25,0,5,0,0,-1,1},{25,0,5,0,0,-1,1},{25,0,5,0,0,-1,1},{25,0,5,0,0,-1,1},{25,0,5,0,0,-1,1},{25,0,5,0,0,-1,1},{25,0,5,0,0,-1,1},{25,0,5,0,0,-1,1},{25,0,5,0,0,-1,1},{25,0,5,0,0,-1,1},{25,0,5,0,0,-1,1},{25,0,5,0,0,-1,1},{25,0,5,0,0,-1,1},{25,0,5,0,0,-1,1},{25,0,5,0,0,-1,1},{25,0,5,0,0,-1,1},{0,0,22,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,18,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,0,18,12,-1,1}}, + {{0,0,29,9,8,-1,1},{0,0,21,10,8,-1,1},{0,0,21,10,8,-1,1},{0,0,21,4,8,-1,1},{0,0,23,4,8,-1,1},{0,0,21,4,8,-1,1},{0,0,21,10,8,-1,1},{0,0,21,10,1,-1,1},{0,1,22,10,8,-1,1},{0,2,18,10,8,-1,1},{0,0,21,10,8,-1,1},{0,0,25,3,8,-1,1},{0,0,21,6,8,-1,1},{0,0,17,3,1,-1,1},{0,0,21,6,1,-1,1},{0,0,21,6,8,-1,1},{0,0,13,2,0,0,1},{0,0,13,2,0,1,1},{0,0,13,2,0,2,1},{0,0,13,2,0,3,1},{0,0,13,2,0,4,1},{0,0,13,2,0,5,1},{0,0,13,2,0,6,1},{0,0,13,2,0,7,1},{0,0,13,2,0,8,1},{0,0,13,2,0,9,1},{0,0,21,6,1,-1,1},{0,0,21,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,21,10,8,-1,1}}, + {{0,0,21,10,8,-1,1},{25,0,9,0,0,-1,1},{25,0,9,0,0,-1,1},{25,0,9,0,0,-1,1},{25,0,9,0,0,-1,1},{25,0,9,0,0,-1,1},{25,0,9,0,0,-1,1},{25,0,9,0,0,-1,1},{25,0,9,0,0,-1,1},{25,0,9,0,0,-1,1},{25,0,9,0,0,-1,1},{25,0,9,0,0,-1,1},{25,0,9,0,0,-1,1},{25,0,9,0,0,-1,1},{25,0,9,0,0,-1,1},{25,0,9,0,0,-1,1},{25,0,9,0,0,-1,1},{25,0,9,0,0,-1,1},{25,0,9,0,0,-1,1},{25,0,9,0,0,-1,1},{25,0,9,0,0,-1,1},{25,0,9,0,0,-1,1},{25,0,9,0,0,-1,1},{25,0,9,0,0,-1,1},{25,0,9,0,0,-1,1},{25,0,9,0,0,-1,1},{25,0,9,0,0,-1,1},{0,1,22,10,8,-1,1},{0,0,21,10,8,-1,1},{0,2,18,10,8,-1,1},{0,0,24,10,8,-1,1},{0,0,16,10,0,-1,1}}, + {{0,0,24,10,8,-1,1},{25,0,5,0,0,-1,1},{25,0,5,0,0,-1,1},{25,0,5,0,0,-1,1},{25,0,5,0,0,-1,1},{25,0,5,0,0,-1,1},{25,0,5,0,0,-1,1},{25,0,5,0,0,-1,1},{25,0,5,0,0,-1,1},{25,0,5,0,0,-1,1},{25,0,5,0,0,-1,1},{25,0,5,0,0,-1,1},{25,0,5,0,0,-1,1},{25,0,5,0,0,-1,1},{25,0,5,0,0,-1,1},{25,0,5,0,0,-1,1},{25,0,5,0,0,-1,1},{25,0,5,0,0,-1,1},{25,0,5,0,0,-1,1},{25,0,5,0,0,-1,1},{25,0,5,0,0,-1,1},{25,0,5,0,0,-1,1},{25,0,5,0,0,-1,1},{25,0,5,0,0,-1,1},{25,0,5,0,0,-1,1},{25,0,5,0,0,-1,1},{25,0,5,0,0,-1,1},{0,1,22,10,8,-1,1},{0,0,25,10,8,-1,1},{0,2,18,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,0,18,12,-1,1}}, {{0,0,0,18,12,-1,1},{0,0,0,18,12,-1,1},{0,0,0,18,12,-1,1},{0,0,0,18,12,-1,1},{0,0,0,18,12,-1,1},{0,0,0,7,8,-1,1},{0,0,0,18,12,-1,1},{0,0,0,18,12,-1,1},{0,0,0,18,12,-1,1},{0,0,0,18,12,-1,1},{0,0,0,18,12,-1,1},{0,0,0,18,12,-1,1},{0,0,0,18,12,-1,1},{0,0,0,18,12,-1,1},{0,0,0,18,12,-1,1},{0,0,0,18,12,-1,1},{0,0,0,18,12,-1,1},{0,0,0,18,12,-1,1},{0,0,0,18,12,-1,1},{0,0,0,18,12,-1,1},{0,0,0,18,12,-1,1},{0,0,0,18,12,-1,1},{0,0,0,18,12,-1,1},{0,0,0,18,12,-1,1},{0,0,0,18,12,-1,1},{0,0,0,18,12,-1,1},{0,0,0,18,12,-1,1},{0,0,0,18,12,-1,1},{0,0,0,18,12,-1,1},{0,0,0,18,12,-1,1},{0,0,0,18,12,-1,1},{0,0,0,18,12,-1,1}}, {{0,0,29,6,9,-1,1},{0,0,21,10,8,-1,1},{0,0,23,4,8,-1,1},{0,0,23,4,8,-1,1},{0,0,23,4,8,-1,1},{0,0,23,4,8,-1,1},{0,0,26,10,8,-1,1},{0,0,21,10,8,-1,0},{0,0,24,10,9,-1,1},{0,0,26,10,8,-1,0},{25,0,7,0,9,-1,1},{0,0,20,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,1,18,10,-1,1},{0,0,26,10,8,-1,0},{0,0,24,10,9,-1,1},{0,0,26,4,8,-1,1},{0,0,25,4,8,-1,0},{0,0,15,2,9,2,1},{0,0,15,2,9,3,1},{0,0,24,10,9,-1,1},{0,0,5,0,9,-1,1},{0,0,21,10,8,-1,1},{0,0,21,10,1,-1,1},{0,0,24,10,9,-1,1},{0,0,15,2,9,1,1},{25,0,7,0,9,-1,1},{0,0,19,10,8,-1,1},{0,0,15,10,9,-1,0},{0,0,15,10,9,-1,0},{0,0,15,10,9,-1,0},{0,0,21,10,8,-1,1}}, {{25,0,9,0,0,-1,1},{25,0,9,0,0,-1,1},{25,0,9,0,0,-1,1},{25,0,9,0,0,-1,1},{25,0,9,0,0,-1,1},{25,0,9,0,0,-1,1},{25,0,9,0,0,-1,1},{25,0,9,0,0,-1,1},{25,0,9,0,0,-1,1},{25,0,9,0,0,-1,1},{25,0,9,0,0,-1,1},{25,0,9,0,0,-1,1},{25,0,9,0,0,-1,1},{25,0,9,0,0,-1,1},{25,0,9,0,0,-1,1},{25,0,9,0,0,-1,1},{25,0,9,0,0,-1,1},{25,0,9,0,0,-1,1},{25,0,9,0,0,-1,1},{25,0,9,0,0,-1,1},{25,0,9,0,0,-1,1},{25,0,9,0,0,-1,1},{25,0,9,0,0,-1,1},{0,0,25,10,8,-1,0},{25,0,9,0,0,-1,1},{25,0,9,0,0,-1,1},{25,0,9,0,0,-1,1},{25,0,9,0,0,-1,1},{25,0,9,0,0,-1,1},{25,0,9,0,0,-1,1},{25,0,9,0,0,-1,1},{25,0,5,0,0,-1,1}}, {{25,0,5,0,0,-1,1},{25,0,5,0,0,-1,1},{25,0,5,0,0,-1,1},{25,0,5,0,0,-1,1},{25,0,5,0,0,-1,1},{25,0,5,0,0,-1,1},{25,0,5,0,0,-1,1},{25,0,5,0,0,-1,1},{25,0,5,0,0,-1,1},{25,0,5,0,0,-1,1},{25,0,5,0,0,-1,1},{25,0,5,0,0,-1,1},{25,0,5,0,0,-1,1},{25,0,5,0,0,-1,1},{25,0,5,0,0,-1,1},{25,0,5,0,0,-1,1},{25,0,5,0,0,-1,1},{25,0,5,0,0,-1,1},{25,0,5,0,0,-1,1},{25,0,5,0,0,-1,1},{25,0,5,0,0,-1,1},{25,0,5,0,0,-1,1},{25,0,5,0,0,-1,1},{0,0,25,10,8,-1,0},{25,0,5,0,0,-1,1},{25,0,5,0,0,-1,1},{25,0,5,0,0,-1,1},{25,0,5,0,0,-1,1},{25,0,5,0,0,-1,1},{25,0,5,0,0,-1,1},{25,0,5,0,0,-1,1},{25,0,5,0,0,-1,1}}, {{25,0,9,0,0,-1,1},{25,0,5,0,0,-1,1},{25,0,9,0,0,-1,1},{25,0,5,0,0,-1,1},{25,0,9,0,0,-1,1},{25,0,5,0,0,-1,1},{25,0,9,0,0,-1,1},{25,0,5,0,0,-1,1},{25,0,9,0,0,-1,1},{25,0,5,0,0,-1,1},{25,0,9,0,0,-1,1},{25,0,5,0,0,-1,1},{25,0,9,0,0,-1,1},{25,0,5,0,0,-1,1},{25,0,9,0,0,-1,1},{25,0,5,0,0,-1,1},{25,0,9,0,0,-1,1},{25,0,5,0,0,-1,1},{25,0,9,0,0,-1,1},{25,0,5,0,0,-1,1},{25,0,9,0,0,-1,1},{25,0,5,0,0,-1,1},{25,0,9,0,0,-1,1},{25,0,5,0,0,-1,1},{25,0,9,0,0,-1,1},{25,0,5,0,0,-1,1},{25,0,9,0,0,-1,1},{25,0,5,0,0,-1,1},{25,0,9,0,0,-1,1},{25,0,5,0,0,-1,1},{25,0,9,0,0,-1,1},{25,0,5,0,0,-1,1}}, {{25,0,9,0,0,-1,1},{25,0,5,0,0,-1,1},{25,0,9,0,0,-1,1},{25,0,5,0,0,-1,1},{25,0,9,0,0,-1,1},{25,0,5,0,0,-1,1},{25,0,9,0,0,-1,1},{25,0,5,0,0,-1,1},{25,0,9,0,0,-1,1},{25,0,5,0,0,-1,1},{25,0,9,0,0,-1,1},{25,0,5,0,0,-1,1},{25,0,9,0,0,-1,1},{25,0,5,0,0,-1,1},{25,0,9,0,0,-1,1},{25,0,5,0,0,-1,1},{25,0,9,0,0,-1,1},{25,0,5,0,0,-1,1},{25,0,9,0,9,-1,1},{25,0,5,0,9,-1,1},{25,0,9,0,0,-1,1},{25,0,5,0,0,-1,1},{25,0,9,0,0,-1,1},{25,0,5,0,0,-1,1},{25,0,5,0,0,-1,1},{25,0,9,0,0,-1,1},{25,0,5,0,0,-1,1},{25,0,9,0,0,-1,1},{25,0,5,0,0,-1,1},{25,0,9,0,0,-1,1},{25,0,5,0,0,-1,1},{25,0,9,0,9,-1,1}}, {{25,0,5,0,9,-1,1},{25,0,9,0,0,-1,1},{25,0,5,0,0,-1,1},{25,0,9,0,0,-1,1},{25,0,5,0,0,-1,1},{25,0,9,0,0,-1,1},{25,0,5,0,0,-1,1},{25,0,9,0,0,-1,1},{25,0,5,0,0,-1,1},{25,0,5,0,11,-1,1},{25,0,9,0,0,-1,1},{25,0,5,0,0,-1,1},{25,0,9,0,0,-1,1},{25,0,5,0,0,-1,1},{25,0,9,0,0,-1,1},{25,0,5,0,0,-1,1},{25,0,9,0,0,-1,1},{25,0,5,0,0,-1,1},{25,0,9,0,0,-1,1},{25,0,5,0,0,-1,1},{25,0,9,0,0,-1,1},{25,0,5,0,0,-1,1},{25,0,9,0,0,-1,1},{25,0,5,0,0,-1,1},{25,0,9,0,0,-1,1},{25,0,5,0,0,-1,1},{25,0,9,0,0,-1,1},{25,0,5,0,0,-1,1},{25,0,9,0,0,-1,1},{25,0,5,0,0,-1,1},{25,0,9,0,0,-1,1},{25,0,5,0,0,-1,1}}, {{25,0,9,0,0,-1,1},{25,0,5,0,0,-1,1},{25,0,9,0,0,-1,1},{25,0,5,0,0,-1,1},{25,0,9,0,0,-1,1},{25,0,5,0,0,-1,1},{25,0,9,0,0,-1,1},{25,0,5,0,0,-1,1},{25,0,9,0,0,-1,1},{25,0,5,0,0,-1,1},{25,0,9,0,0,-1,1},{25,0,5,0,0,-1,1},{25,0,9,0,0,-1,1},{25,0,5,0,0,-1,1},{25,0,9,0,0,-1,1},{25,0,5,0,0,-1,1},{25,0,9,0,0,-1,1},{25,0,5,0,0,-1,1},{25,0,9,0,0,-1,1},{25,0,5,0,0,-1,1},{25,0,9,0,0,-1,1},{25,0,5,0,0,-1,1},{25,0,9,0,0,-1,1},{25,0,5,0,0,-1,1},{25,0,9,0,0,-1,1},{25,0,9,0,0,-1,1},{25,0,5,0,0,-1,1},{25,0,9,0,0,-1,1},{25,0,5,0,0,-1,1},{25,0,9,0,0,-1,1},{25,0,5,0,0,-1,1},{25,0,5,0,9,-1,1}}, @@ -520,17 +523,17 @@ static const nsCharProps2 sCharProp2Valu {{61,0,2,0,12,-1,1},{38,0,7,0,0,-1,1},{38,0,7,0,0,-1,1},{38,0,7,0,0,-1,1},{38,0,7,0,0,-1,1},{38,0,7,0,0,-1,1},{38,0,7,0,0,-1,1},{38,0,7,0,0,-1,1},{38,0,7,0,0,-1,1},{38,0,7,0,0,-1,1},{38,0,7,0,0,-1,1},{38,0,7,0,0,-1,1},{38,0,7,0,0,-1,1},{38,0,7,0,0,-1,1},{38,0,7,0,0,-1,1},{38,0,7,0,0,-1,1},{38,0,7,0,0,-1,1},{38,0,7,0,0,-1,1},{38,0,7,0,0,-1,1},{38,0,7,0,0,-1,1},{38,0,7,0,0,-1,1},{38,0,7,0,0,-1,1},{38,0,7,0,0,-1,1},{38,0,7,0,0,-1,1},{38,0,7,0,0,-1,1},{38,0,7,0,0,-1,1},{38,0,7,0,0,-1,1},{38,0,7,0,0,-1,1},{38,0,7,0,0,-1,1},{38,0,7,0,0,-1,1},{38,0,7,0,0,-1,1},{38,0,7,0,0,-1,1}}, {{38,0,7,0,0,-1,1},{38,0,7,0,0,-1,1},{38,0,7,0,0,-1,1},{38,0,7,0,0,-1,1},{38,0,7,0,0,-1,1},{38,0,7,0,0,-1,1},{38,0,7,0,0,-1,1},{38,0,7,0,0,-1,1},{38,0,7,0,0,-1,1},{38,0,7,0,0,-1,1},{38,0,7,0,0,-1,1},{38,0,7,0,0,-1,1},{38,0,7,0,0,-1,1},{38,0,7,0,0,-1,1},{38,0,7,0,0,-1,1},{38,0,7,0,0,-1,1},{38,0,7,0,0,-1,1},{38,0,12,17,0,-1,1},{38,0,7,0,0,-1,1},{38,0,7,0,9,-1,1},{38,0,12,17,0,-1,1},{38,0,12,17,0,-1,1},{38,0,12,17,0,-1,1},{38,0,12,17,0,-1,1},{38,0,12,17,0,-1,1},{38,0,12,17,0,-1,1},{38,0,12,17,0,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{0,0,23,4,8,-1,1}}, {{38,0,7,0,0,-1,1},{38,0,7,0,0,-1,1},{38,0,7,0,0,-1,1},{38,0,7,0,0,-1,1},{38,0,7,0,0,-1,1},{38,0,7,0,0,-1,1},{38,0,6,0,0,-1,1},{38,0,12,17,0,-1,1},{38,0,12,17,0,-1,1},{38,0,12,17,0,-1,1},{38,0,12,17,0,-1,1},{38,0,12,17,0,-1,1},{38,0,12,17,0,-1,1},{38,0,12,17,0,-1,1},{38,0,12,17,0,-1,1},{38,0,21,0,8,-1,1},{38,0,13,0,0,0,1},{38,0,13,0,0,1,1},{38,0,13,0,0,2,1},{38,0,13,0,0,3,1},{38,0,13,0,0,4,1},{38,0,13,0,0,5,1},{38,0,13,0,0,6,1},{38,0,13,0,0,7,1},{38,0,13,0,0,8,1},{38,0,13,0,0,9,1},{38,0,21,0,8,-1,1},{38,0,21,0,8,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1}}, {{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1}}, {{61,0,2,0,12,-1,1},{24,0,7,0,0,-1,1},{24,0,7,0,0,-1,1},{61,0,2,0,12,-1,1},{24,0,7,0,0,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{24,0,7,0,0,-1,1},{24,0,7,0,0,-1,1},{61,0,2,0,12,-1,1},{24,0,7,0,0,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{24,0,7,0,0,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{24,0,7,0,0,-1,1},{24,0,7,0,0,-1,1},{24,0,7,0,0,-1,1},{24,0,7,0,0,-1,1},{61,0,2,0,12,-1,1},{24,0,7,0,0,-1,1},{24,0,7,0,0,-1,1},{24,0,7,0,0,-1,1},{24,0,7,0,0,-1,1},{24,0,7,0,0,-1,1},{24,0,7,0,0,-1,1},{24,0,7,0,0,-1,1}}, {{61,0,2,0,12,-1,1},{24,0,7,0,0,-1,1},{24,0,7,0,0,-1,1},{24,0,7,0,0,-1,1},{61,0,2,0,12,-1,1},{24,0,7,0,0,-1,1},{61,0,2,0,12,-1,1},{24,0,7,0,0,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{24,0,7,0,0,-1,1},{24,0,7,0,0,-1,1},{61,0,2,0,12,-1,1},{24,0,7,0,0,-1,1},{24,0,7,0,0,-1,1},{24,0,7,0,0,-1,1},{24,0,7,0,0,-1,1},{24,0,12,17,0,-1,1},{24,0,7,0,0,-1,1},{24,0,7,0,9,-1,1},{24,0,12,17,0,-1,1},{24,0,12,17,0,-1,1},{24,0,12,17,0,-1,1},{24,0,12,17,0,-1,1},{24,0,12,17,0,-1,1},{24,0,12,17,0,-1,1},{61,0,2,0,12,-1,1},{24,0,12,17,0,-1,1},{24,0,12,17,0,-1,1},{24,0,7,0,0,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1}}, {{24,0,7,0,0,-1,1},{24,0,7,0,0,-1,1},{24,0,7,0,0,-1,1},{24,0,7,0,0,-1,1},{24,0,7,0,0,-1,1},{61,0,2,0,12,-1,1},{24,0,6,0,0,-1,1},{61,0,2,0,12,-1,1},{24,0,12,17,0,-1,1},{24,0,12,17,0,-1,1},{24,0,12,17,0,-1,1},{24,0,12,17,0,-1,1},{24,0,12,17,0,-1,1},{24,0,12,17,0,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{24,0,13,0,0,0,1},{24,0,13,0,0,1,1},{24,0,13,0,0,2,1},{24,0,13,0,0,3,1},{24,0,13,0,0,4,1},{24,0,13,0,0,5,1},{24,0,13,0,0,6,1},{24,0,13,0,0,7,1},{24,0,13,0,0,8,1},{24,0,13,0,0,9,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{24,0,7,0,9,-1,1},{24,0,7,0,9,-1,1},{24,0,7,0,0,-1,1},{24,0,7,0,0,-1,1}}, {{39,0,7,0,0,-1,1},{39,0,26,0,8,-1,1},{39,0,26,0,8,-1,1},{39,0,26,0,8,-1,1},{39,0,21,0,8,-1,1},{39,0,21,0,8,-1,1},{39,0,21,0,8,-1,1},{39,0,21,0,8,-1,1},{39,0,21,0,8,-1,1},{39,0,21,0,8,-1,1},{39,0,21,0,8,-1,1},{39,0,21,0,1,-1,1},{39,0,21,0,9,-1,1},{39,0,21,0,8,-1,1},{39,0,21,0,8,-1,1},{39,0,21,0,8,-1,1},{39,0,21,0,8,-1,1},{39,0,21,0,8,-1,1},{39,0,21,0,8,-1,1},{39,0,26,0,8,-1,1},{39,0,21,0,8,-1,1},{39,0,26,0,8,-1,1},{39,0,26,0,8,-1,1},{39,0,26,0,8,-1,1},{39,0,12,17,3,-1,1},{39,0,12,17,3,-1,1},{39,0,26,0,8,-1,1},{39,0,26,0,8,-1,1},{39,0,26,0,8,-1,1},{39,0,26,0,8,-1,1},{39,0,26,0,8,-1,1},{39,0,26,0,8,-1,1}}, - {{39,0,13,0,0,0,1},{39,0,13,0,0,1,1},{39,0,13,0,0,2,1},{39,0,13,0,0,3,1},{39,0,13,0,0,4,1},{39,0,13,0,0,5,1},{39,0,13,0,0,6,1},{39,0,13,0,0,7,1},{39,0,13,0,0,8,1},{39,0,13,0,0,9,1},{39,0,15,0,8,-1,1},{39,0,15,0,8,-1,1},{39,0,15,0,8,-1,1},{39,0,15,0,8,-1,1},{39,0,15,0,8,-1,1},{39,0,15,0,8,-1,1},{39,0,15,0,8,-1,1},{39,0,15,0,8,-1,1},{39,0,15,0,8,-1,1},{39,0,15,0,8,-1,1},{39,0,26,0,8,-1,1},{39,0,12,17,0,-1,1},{39,0,26,0,8,-1,1},{39,0,12,17,0,-1,1},{39,0,26,0,8,-1,1},{39,0,12,17,2,-1,1},{39,0,22,10,8,-1,1},{39,0,18,10,8,-1,1},{39,0,22,10,8,-1,1},{39,0,18,10,8,-1,1},{39,0,10,0,0,-1,1},{39,0,10,0,0,-1,1}}, + {{39,0,13,0,0,0,1},{39,0,13,0,0,1,1},{39,0,13,0,0,2,1},{39,0,13,0,0,3,1},{39,0,13,0,0,4,1},{39,0,13,0,0,5,1},{39,0,13,0,0,6,1},{39,0,13,0,0,7,1},{39,0,13,0,0,8,1},{39,0,13,0,0,9,1},{39,0,15,0,8,-1,1},{39,0,15,0,8,-1,1},{39,0,15,0,8,-1,1},{39,0,15,0,8,-1,1},{39,0,15,0,8,-1,1},{39,0,15,0,8,-1,1},{39,0,15,0,8,-1,1},{39,0,15,0,8,-1,1},{39,0,15,0,8,-1,1},{39,0,15,0,8,-1,1},{39,0,26,0,8,-1,1},{39,0,12,17,0,-1,1},{39,0,26,0,8,-1,1},{39,0,12,17,0,-1,1},{39,0,26,0,8,-1,1},{39,0,12,17,2,-1,1},{39,1,22,10,8,-1,1},{39,2,18,10,8,-1,1},{39,1,22,10,8,-1,1},{39,2,18,10,8,-1,1},{39,0,10,0,0,-1,1},{39,0,10,0,0,-1,1}}, {{39,0,7,0,0,-1,1},{39,0,7,0,0,-1,1},{39,0,7,0,0,-1,1},{39,0,7,0,9,-1,1},{39,0,7,0,0,-1,1},{39,0,7,0,0,-1,1},{39,0,7,0,0,-1,1},{39,0,7,0,0,-1,1},{61,0,2,0,12,-1,1},{39,0,7,0,0,-1,1},{39,0,7,0,0,-1,1},{39,0,7,0,0,-1,1},{39,0,7,0,0,-1,1},{39,0,7,0,9,-1,1},{39,0,7,0,0,-1,1},{39,0,7,0,0,-1,1},{39,0,7,0,0,-1,1},{39,0,7,0,0,-1,1},{39,0,7,0,9,-1,1},{39,0,7,0,0,-1,1},{39,0,7,0,0,-1,1},{39,0,7,0,0,-1,1},{39,0,7,0,0,-1,1},{39,0,7,0,9,-1,1},{39,0,7,0,0,-1,1},{39,0,7,0,0,-1,1},{39,0,7,0,0,-1,1},{39,0,7,0,0,-1,1},{39,0,7,0,9,-1,1},{39,0,7,0,0,-1,1},{39,0,7,0,0,-1,1},{39,0,7,0,0,-1,1}}, {{39,0,7,0,0,-1,1},{39,0,7,0,0,-1,1},{39,0,7,0,0,-1,1},{39,0,7,0,0,-1,1},{39,0,7,0,0,-1,1},{39,0,7,0,0,-1,1},{39,0,7,0,0,-1,1},{39,0,7,0,0,-1,1},{39,0,7,0,0,-1,1},{39,0,7,0,9,-1,1},{39,0,7,0,0,-1,1},{39,0,7,0,0,-1,1},{39,0,7,0,0,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{39,0,12,17,0,-1,1},{39,0,12,17,0,-1,1},{39,0,12,17,9,-1,1},{39,0,12,17,0,-1,1},{39,0,12,17,9,-1,1},{39,0,12,17,9,-1,1},{39,0,12,17,11,-1,1},{39,0,12,17,9,-1,1},{39,0,12,17,11,-1,1},{39,0,12,17,0,-1,1},{39,0,12,17,0,-1,1},{39,0,12,17,0,-1,1},{39,0,12,17,0,-1,1},{39,0,12,17,0,-1,1},{39,0,10,0,0,-1,1}}, {{39,0,12,17,0,-1,1},{39,0,12,17,9,-1,1},{39,0,12,17,0,-1,1},{39,0,12,17,0,-1,1},{39,0,12,17,0,-1,1},{39,0,21,0,8,-1,1},{39,0,12,17,0,-1,1},{39,0,12,17,0,-1,1},{39,0,7,0,0,-1,1},{39,0,7,0,0,-1,1},{39,0,7,0,0,-1,1},{39,0,7,0,0,-1,1},{39,0,7,0,0,-1,1},{39,0,12,17,0,-1,1},{39,0,12,17,0,-1,1},{39,0,12,17,0,-1,1},{39,0,12,17,0,-1,1},{39,0,12,17,0,-1,1},{39,0,12,17,0,-1,1},{39,0,12,17,9,-1,1},{39,0,12,17,0,-1,1},{39,0,12,17,0,-1,1},{39,0,12,17,0,-1,1},{39,0,12,17,0,-1,1},{61,0,2,0,12,-1,1},{39,0,12,17,0,-1,1},{39,0,12,17,0,-1,1},{39,0,12,17,0,-1,1},{39,0,12,17,0,-1,1},{39,0,12,17,9,-1,1},{39,0,12,17,0,-1,1},{39,0,12,17,0,-1,1}}, {{39,0,12,17,0,-1,1},{39,0,12,17,0,-1,1},{39,0,12,17,9,-1,1},{39,0,12,17,0,-1,1},{39,0,12,17,0,-1,1},{39,0,12,17,0,-1,1},{39,0,12,17,0,-1,1},{39,0,12,17,9,-1,1},{39,0,12,17,0,-1,1},{39,0,12,17,0,-1,1},{39,0,12,17,0,-1,1},{39,0,12,17,0,-1,1},{39,0,12,17,9,-1,1},{39,0,12,17,0,-1,1},{39,0,12,17,0,-1,1},{39,0,12,17,0,-1,1},{39,0,12,17,0,-1,1},{39,0,12,17,0,-1,1},{39,0,12,17,0,-1,1},{39,0,12,17,0,-1,1},{39,0,12,17,0,-1,1},{39,0,12,17,0,-1,1},{39,0,12,17,0,-1,1},{39,0,12,17,0,-1,1},{39,0,12,17,0,-1,1},{39,0,12,17,9,-1,1},{39,0,12,17,0,-1,1},{39,0,12,17,0,-1,1},{39,0,12,17,0,-1,1},{61,0,2,0,12,-1,1},{39,0,26,0,8,-1,1},{39,0,26,0,8,-1,1}}, {{39,0,26,0,8,-1,1},{39,0,26,0,8,-1,1},{39,0,26,0,8,-1,1},{39,0,26,0,8,-1,1},{39,0,26,0,8,-1,1},{39,0,26,0,8,-1,1},{39,0,12,17,0,-1,1},{39,0,26,0,8,-1,1},{39,0,26,0,8,-1,1},{39,0,26,0,8,-1,1},{39,0,26,0,8,-1,1},{39,0,26,0,8,-1,1},{39,0,26,0,8,-1,1},{61,0,2,0,12,-1,1},{39,0,26,0,8,-1,1},{39,0,26,0,8,-1,1},{39,0,21,0,8,-1,1},{39,0,21,0,8,-1,1},{39,0,21,0,8,-1,1},{39,0,21,0,8,-1,1},{39,0,21,0,8,-1,1},{0,0,26,0,8,-1,1},{0,0,26,0,8,-1,1},{0,0,26,0,8,-1,1},{0,0,26,0,8,-1,1},{39,0,21,0,8,-1,1},{39,0,21,0,8,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1}}, {{28,0,7,0,0,-1,1},{28,0,7,0,0,-1,1},{28,0,7,0,0,-1,1},{28,0,7,0,0,-1,1},{28,0,7,0,0,-1,1},{28,0,7,0,0,-1,1},{28,0,7,0,0,-1,1},{28,0,7,0,0,-1,1},{28,0,7,0,0,-1,1},{28,0,7,0,0,-1,1},{28,0,7,0,0,-1,1},{28,0,7,0,0,-1,1},{28,0,7,0,0,-1,1},{28,0,7,0,0,-1,1},{28,0,7,0,0,-1,1},{28,0,7,0,0,-1,1},{28,0,7,0,0,-1,1},{28,0,7,0,0,-1,1},{28,0,7,0,0,-1,1},{28,0,7,0,0,-1,1},{28,0,7,0,0,-1,1},{28,0,7,0,0,-1,1},{28,0,7,0,0,-1,1},{28,0,7,0,0,-1,1},{28,0,7,0,0,-1,1},{28,0,7,0,0,-1,1},{28,0,7,0,0,-1,1},{28,0,7,0,0,-1,1},{28,0,7,0,0,-1,1},{28,0,7,0,0,-1,1},{28,0,7,0,0,-1,1},{28,0,7,0,0,-1,1}}, {{28,0,7,0,0,-1,1},{28,0,7,0,0,-1,1},{28,0,7,0,0,-1,1},{28,0,7,0,0,-1,1},{28,0,7,0,0,-1,1},{28,0,7,0,0,-1,1},{28,0,7,0,0,-1,1},{28,0,7,0,0,-1,1},{28,0,7,0,0,-1,1},{28,0,7,0,0,-1,1},{28,0,7,0,0,-1,1},{28,0,10,0,0,-1,1},{28,0,10,0,0,-1,1},{28,0,12,17,0,-1,1},{28,0,12,17,0,-1,1},{28,0,12,17,0,-1,1},{28,0,12,17,0,-1,1},{28,0,10,0,0,-1,1},{28,0,12,17,0,-1,1},{28,0,12,17,0,-1,1},{28,0,12,17,0,-1,1},{28,0,12,17,0,-1,1},{28,0,12,17,0,-1,1},{28,0,12,17,0,-1,1},{28,0,10,0,0,-1,1},{28,0,12,17,0,-1,1},{28,0,12,17,0,-1,1},{28,0,10,0,0,-1,1},{28,0,10,0,0,-1,1},{28,0,12,17,0,-1,1},{28,0,12,17,0,-1,1},{28,0,7,0,0,-1,1}}, {{28,0,13,0,0,0,1},{28,0,13,0,0,1,1},{28,0,13,0,0,2,1},{28,0,13,0,0,3,1},{28,0,13,0,0,4,1},{28,0,13,0,0,5,1},{28,0,13,0,0,6,1},{28,0,13,0,0,7,1},{28,0,13,0,0,8,1},{28,0,13,0,0,9,1},{28,0,21,0,8,-1,1},{28,0,21,0,8,-1,1},{28,0,21,0,8,-1,1},{28,0,21,0,8,-1,1},{28,0,21,0,8,-1,1},{28,0,21,0,8,-1,1},{28,0,7,0,0,-1,1},{28,0,7,0,0,-1,1},{28,0,7,0,0,-1,1},{28,0,7,0,0,-1,1},{28,0,7,0,0,-1,1},{28,0,7,0,0,-1,1},{28,0,10,0,0,-1,1},{28,0,10,0,0,-1,1},{28,0,12,17,0,-1,1},{28,0,12,17,0,-1,1},{28,0,7,0,0,-1,1},{28,0,7,0,0,-1,1},{28,0,7,0,0,-1,1},{28,0,7,0,0,-1,1},{28,0,12,17,0,-1,1},{28,0,12,17,0,-1,1}}, @@ -551,17 +554,17 @@ static const nsCharProps2 sCharProp2Valu {{11,0,7,0,0,-1,1},{11,0,7,0,0,-1,1},{11,0,7,0,0,-1,1},{11,0,7,0,0,-1,1},{11,0,7,0,0,-1,1},{11,0,7,0,0,-1,1},{11,0,7,0,0,-1,1},{11,0,7,0,0,-1,1},{11,0,7,0,0,-1,1},{11,0,7,0,0,-1,1},{11,0,7,0,0,-1,1},{11,0,7,0,0,-1,1},{11,0,7,0,0,-1,1},{11,0,7,0,0,-1,1},{11,0,7,0,0,-1,1},{11,0,7,0,0,-1,1},{11,0,7,0,0,-1,1},{11,0,7,0,0,-1,1},{11,0,7,0,0,-1,1},{11,0,7,0,0,-1,1},{11,0,7,0,0,-1,1},{11,0,7,0,0,-1,1},{11,0,7,0,0,-1,1},{11,0,7,0,0,-1,1},{11,0,7,0,0,-1,1},{11,0,7,0,0,-1,1},{11,0,7,0,0,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{11,0,12,17,0,-1,1},{11,0,12,17,0,-1,1},{11,0,12,17,0,-1,1}}, {{11,0,21,0,8,-1,1},{11,0,21,0,8,-1,1},{11,0,21,0,8,-1,1},{11,0,21,0,8,-1,1},{11,0,21,0,8,-1,1},{11,0,21,0,8,-1,1},{11,0,21,0,8,-1,1},{11,0,21,0,8,-1,1},{11,0,21,0,8,-1,1},{11,0,15,0,4,1,1},{11,0,15,0,4,2,1},{11,0,15,0,4,3,1},{11,0,15,0,4,4,1},{11,0,15,0,4,5,1},{11,0,15,0,4,6,1},{11,0,15,0,4,7,1},{11,0,15,0,4,8,1},{11,0,15,0,4,9,1},{11,0,15,0,8,-1,1},{11,0,15,0,8,-1,1},{11,0,15,0,8,-1,1},{11,0,15,0,8,-1,1},{11,0,15,0,8,-1,1},{11,0,15,0,8,-1,1},{11,0,15,0,8,-1,1},{11,0,15,0,8,-1,1},{11,0,15,0,8,-1,1},{11,0,15,0,8,-1,1},{11,0,15,0,8,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1}}, {{11,0,7,0,0,-1,1},{11,0,7,0,0,-1,1},{11,0,7,0,0,-1,1},{11,0,7,0,0,-1,1},{11,0,7,0,0,-1,1},{11,0,7,0,0,-1,1},{11,0,7,0,0,-1,1},{11,0,7,0,0,-1,1},{11,0,7,0,0,-1,1},{11,0,7,0,0,-1,1},{11,0,7,0,0,-1,1},{11,0,7,0,0,-1,1},{11,0,7,0,0,-1,1},{11,0,7,0,0,-1,1},{11,0,7,0,0,-1,1},{11,0,7,0,0,-1,1},{11,0,26,10,8,-1,1},{11,0,26,10,8,-1,1},{11,0,26,10,8,-1,1},{11,0,26,10,8,-1,1},{11,0,26,10,8,-1,1},{11,0,26,10,8,-1,1},{11,0,26,10,8,-1,1},{11,0,26,10,8,-1,1},{11,0,26,10,8,-1,1},{11,0,26,10,8,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1}}, {{6,0,9,0,6,-1,1},{6,0,9,0,6,-1,1},{6,0,9,0,6,-1,1},{6,0,9,0,6,-1,1},{6,0,9,0,6,-1,1},{6,0,9,0,6,-1,1},{6,0,9,0,6,-1,1},{6,0,9,0,6,-1,1},{6,0,9,0,6,-1,1},{6,0,9,0,6,-1,1},{6,0,9,0,6,-1,1},{6,0,9,0,6,-1,1},{6,0,9,0,6,-1,1},{6,0,9,0,6,-1,1},{6,0,9,0,6,-1,1},{6,0,9,0,6,-1,1},{6,0,9,0,6,-1,1},{6,0,9,0,6,-1,1},{6,0,9,0,6,-1,1},{6,0,9,0,6,-1,1},{6,0,9,0,6,-1,1},{6,0,9,0,6,-1,1},{6,0,9,0,6,-1,1},{6,0,9,0,6,-1,1},{6,0,9,0,6,-1,1},{6,0,9,0,6,-1,1},{6,0,9,0,6,-1,1},{6,0,9,0,6,-1,1},{6,0,9,0,6,-1,1},{6,0,9,0,6,-1,1},{6,0,9,0,6,-1,1},{6,0,9,0,6,-1,1}}, {{6,0,9,0,6,-1,1},{6,0,9,0,6,-1,1},{6,0,9,0,6,-1,1},{6,0,9,0,6,-1,1},{6,0,9,0,6,-1,1},{6,0,9,0,6,-1,1},{6,0,9,0,6,-1,1},{6,0,9,0,6,-1,1},{6,0,9,0,6,-1,1},{6,0,9,0,6,-1,1},{6,0,9,0,6,-1,1},{6,0,9,0,6,-1,1},{6,0,9,0,6,-1,1},{6,0,9,0,6,-1,1},{6,0,9,0,6,-1,1},{6,0,9,0,6,-1,1},{6,0,9,0,6,-1,1},{6,0,9,0,6,-1,1},{6,0,9,0,6,-1,1},{6,0,9,0,6,-1,1},{6,0,9,0,6,-1,1},{6,0,9,0,6,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{6,0,5,0,6,-1,1},{6,0,5,0,6,-1,1},{6,0,5,0,6,-1,1},{6,0,5,0,6,-1,1},{6,0,5,0,6,-1,1},{6,0,5,0,6,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1}}, {{40,0,17,10,8,-1,1},{40,0,7,0,5,-1,0},{40,0,7,0,5,-1,0},{40,0,7,0,5,-1,0},{40,0,7,0,5,-1,0},{40,0,7,0,5,-1,0},{40,0,7,0,5,-1,0},{40,0,7,0,5,-1,0},{40,0,7,0,5,-1,0},{40,0,7,0,5,-1,0},{40,0,7,0,5,-1,0},{40,0,7,0,5,-1,0},{40,0,7,0,5,-1,0},{40,0,7,0,5,-1,0},{40,0,7,0,5,-1,0},{40,0,7,0,5,-1,0},{40,0,7,0,5,-1,0},{40,0,7,0,5,-1,0},{40,0,7,0,5,-1,0},{40,0,7,0,5,-1,0},{40,0,7,0,5,-1,0},{40,0,7,0,5,-1,0},{40,0,7,0,5,-1,0},{40,0,7,0,5,-1,0},{40,0,7,0,5,-1,0},{40,0,7,0,5,-1,0},{40,0,7,0,5,-1,0},{40,0,7,0,5,-1,0},{40,0,7,0,5,-1,0},{40,0,7,0,5,-1,0},{40,0,7,0,5,-1,0},{40,0,7,0,5,-1,0}}, {{40,0,7,0,5,-1,0},{40,0,7,0,5,-1,0},{40,0,7,0,5,-1,0},{40,0,7,0,5,-1,0},{40,0,7,0,5,-1,0},{40,0,7,0,5,-1,0},{40,0,7,0,5,-1,0},{40,0,7,0,5,-1,0},{40,0,7,0,5,-1,0},{40,0,7,0,5,-1,0},{40,0,7,0,5,-1,0},{40,0,7,0,5,-1,0},{40,0,7,0,5,-1,0},{40,0,7,0,5,-1,0},{40,0,7,0,5,-1,0},{40,0,7,0,5,-1,0},{40,0,7,0,5,-1,0},{40,0,7,0,5,-1,0},{40,0,7,0,5,-1,0},{40,0,7,0,5,-1,0},{40,0,7,0,5,-1,0},{40,0,7,0,5,-1,0},{40,0,7,0,5,-1,0},{40,0,7,0,5,-1,0},{40,0,7,0,5,-1,0},{40,0,7,0,5,-1,0},{40,0,7,0,5,-1,0},{40,0,7,0,5,-1,0},{40,0,7,0,5,-1,0},{40,0,7,0,5,-1,0},{40,0,7,0,5,-1,0},{40,0,7,0,5,-1,0}}, {{40,0,7,0,5,-1,0},{40,0,7,0,5,-1,0},{40,0,7,0,5,-1,0},{40,0,7,0,5,-1,0},{40,0,7,0,5,-1,0},{40,0,7,0,5,-1,0},{40,0,7,0,5,-1,0},{40,0,7,0,5,-1,0},{40,0,7,0,5,-1,0},{40,0,7,0,5,-1,0},{40,0,7,0,5,-1,0},{40,0,7,0,5,-1,0},{40,0,7,0,5,-1,0},{40,0,21,0,8,-1,0},{40,0,21,0,8,-1,0},{40,0,7,0,5,-1,0},{40,0,7,0,5,-1,0},{40,0,7,0,5,-1,0},{40,0,7,0,5,-1,0},{40,0,7,0,5,-1,0},{40,0,7,0,5,-1,0},{40,0,7,0,5,-1,0},{40,0,7,0,5,-1,0},{40,0,7,0,5,-1,0},{40,0,7,0,5,-1,0},{40,0,7,0,5,-1,0},{40,0,7,0,5,-1,0},{40,0,7,0,5,-1,0},{40,0,7,0,5,-1,0},{40,0,7,0,5,-1,0},{40,0,7,0,5,-1,0},{40,0,7,0,5,-1,0}}, - {{29,0,29,9,8,-1,1},{29,0,7,0,7,-1,1},{29,0,7,0,7,-1,1},{29,0,7,0,7,-1,1},{29,0,7,0,7,-1,1},{29,0,7,0,7,-1,1},{29,0,7,0,7,-1,1},{29,0,7,0,7,-1,1},{29,0,7,0,7,-1,1},{29,0,7,0,7,-1,1},{29,0,7,0,7,-1,1},{29,0,7,0,7,-1,1},{29,0,7,0,7,-1,1},{29,0,7,0,7,-1,1},{29,0,7,0,7,-1,1},{29,0,7,0,7,-1,1},{29,0,7,0,7,-1,1},{29,0,7,0,7,-1,1},{29,0,7,0,7,-1,1},{29,0,7,0,7,-1,1},{29,0,7,0,7,-1,1},{29,0,7,0,7,-1,1},{29,0,7,0,7,-1,1},{29,0,7,0,7,-1,1},{29,0,7,0,7,-1,1},{29,0,7,0,7,-1,1},{29,0,7,0,7,-1,1},{29,0,22,10,8,-1,1},{29,0,18,10,8,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1}}, + {{29,0,29,9,8,-1,1},{29,0,7,0,7,-1,1},{29,0,7,0,7,-1,1},{29,0,7,0,7,-1,1},{29,0,7,0,7,-1,1},{29,0,7,0,7,-1,1},{29,0,7,0,7,-1,1},{29,0,7,0,7,-1,1},{29,0,7,0,7,-1,1},{29,0,7,0,7,-1,1},{29,0,7,0,7,-1,1},{29,0,7,0,7,-1,1},{29,0,7,0,7,-1,1},{29,0,7,0,7,-1,1},{29,0,7,0,7,-1,1},{29,0,7,0,7,-1,1},{29,0,7,0,7,-1,1},{29,0,7,0,7,-1,1},{29,0,7,0,7,-1,1},{29,0,7,0,7,-1,1},{29,0,7,0,7,-1,1},{29,0,7,0,7,-1,1},{29,0,7,0,7,-1,1},{29,0,7,0,7,-1,1},{29,0,7,0,7,-1,1},{29,0,7,0,7,-1,1},{29,0,7,0,7,-1,1},{29,1,22,10,8,-1,1},{29,2,18,10,8,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1}}, {{32,0,7,0,7,-1,1},{32,0,7,0,7,-1,1},{32,0,7,0,7,-1,1},{32,0,7,0,7,-1,1},{32,0,7,0,7,-1,1},{32,0,7,0,7,-1,1},{32,0,7,0,7,-1,1},{32,0,7,0,7,-1,1},{32,0,7,0,7,-1,1},{32,0,7,0,7,-1,1},{32,0,7,0,7,-1,1},{32,0,7,0,7,-1,1},{32,0,7,0,7,-1,1},{32,0,7,0,7,-1,1},{32,0,7,0,7,-1,1},{32,0,7,0,7,-1,1},{32,0,7,0,7,-1,1},{32,0,7,0,7,-1,1},{32,0,7,0,7,-1,1},{32,0,7,0,7,-1,1},{32,0,7,0,7,-1,1},{32,0,7,0,7,-1,1},{32,0,7,0,7,-1,1},{32,0,7,0,7,-1,1},{32,0,7,0,7,-1,1},{32,0,7,0,7,-1,1},{32,0,7,0,7,-1,1},{32,0,7,0,7,-1,1},{32,0,7,0,7,-1,1},{32,0,7,0,7,-1,1},{32,0,7,0,7,-1,1},{32,0,7,0,7,-1,1}}, {{32,0,7,0,7,-1,1},{32,0,7,0,7,-1,1},{32,0,7,0,7,-1,1},{32,0,7,0,7,-1,1},{32,0,7,0,7,-1,1},{32,0,7,0,7,-1,1},{32,0,7,0,7,-1,1},{32,0,7,0,7,-1,1},{32,0,7,0,7,-1,1},{32,0,7,0,7,-1,1},{32,0,7,0,7,-1,1},{0,0,21,0,8,-1,1},{0,0,21,0,8,-1,1},{0,0,21,0,8,-1,1},{32,0,14,0,7,-1,1},{32,0,14,0,7,-1,1},{32,0,14,0,7,-1,1},{32,0,7,0,7,-1,1},{32,0,7,0,7,-1,1},{32,0,7,0,7,-1,1},{32,0,7,0,7,-1,1},{32,0,7,0,7,-1,1},{32,0,7,0,7,-1,1},{32,0,7,0,7,-1,1},{32,0,7,0,7,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1}}, {{42,0,7,0,7,-1,1},{42,0,7,0,7,-1,1},{42,0,7,0,7,-1,1},{42,0,7,0,7,-1,1},{42,0,7,0,7,-1,1},{42,0,7,0,7,-1,1},{42,0,7,0,7,-1,1},{42,0,7,0,7,-1,1},{42,0,7,0,7,-1,1},{42,0,7,0,7,-1,1},{42,0,7,0,7,-1,1},{42,0,7,0,7,-1,1},{42,0,7,0,7,-1,1},{61,0,2,0,12,-1,1},{42,0,7,0,7,-1,1},{42,0,7,0,7,-1,1},{42,0,7,0,7,-1,1},{42,0,7,0,7,-1,1},{42,0,12,17,7,-1,1},{42,0,12,17,7,-1,1},{42,0,12,17,7,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1}}, {{43,0,7,0,7,-1,1},{43,0,7,0,7,-1,1},{43,0,7,0,7,-1,1},{43,0,7,0,7,-1,1},{43,0,7,0,7,-1,1},{43,0,7,0,7,-1,1},{43,0,7,0,7,-1,1},{43,0,7,0,7,-1,1},{43,0,7,0,7,-1,1},{43,0,7,0,7,-1,1},{43,0,7,0,7,-1,1},{43,0,7,0,7,-1,1},{43,0,7,0,7,-1,1},{43,0,7,0,7,-1,1},{43,0,7,0,7,-1,1},{43,0,7,0,7,-1,1},{43,0,7,0,7,-1,1},{43,0,7,0,7,-1,1},{43,0,12,17,7,-1,1},{43,0,12,17,7,-1,1},{43,0,12,17,7,-1,1},{0,0,21,0,8,-1,1},{0,0,21,0,8,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1}}, {{44,0,7,0,7,-1,1},{44,0,7,0,7,-1,1},{44,0,7,0,7,-1,1},{44,0,7,0,7,-1,1},{44,0,7,0,7,-1,1},{44,0,7,0,7,-1,1},{44,0,7,0,7,-1,1},{44,0,7,0,7,-1,1},{44,0,7,0,7,-1,1},{44,0,7,0,7,-1,1},{44,0,7,0,7,-1,1},{44,0,7,0,7,-1,1},{44,0,7,0,7,-1,1},{44,0,7,0,7,-1,1},{44,0,7,0,7,-1,1},{44,0,7,0,7,-1,1},{44,0,7,0,7,-1,1},{44,0,7,0,7,-1,1},{44,0,12,17,7,-1,1},{44,0,12,17,7,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1}}, {{45,0,7,0,7,-1,1},{45,0,7,0,7,-1,1},{45,0,7,0,7,-1,1},{45,0,7,0,7,-1,1},{45,0,7,0,7,-1,1},{45,0,7,0,7,-1,1},{45,0,7,0,7,-1,1},{45,0,7,0,7,-1,1},{45,0,7,0,7,-1,1},{45,0,7,0,7,-1,1},{45,0,7,0,7,-1,1},{45,0,7,0,7,-1,1},{45,0,7,0,7,-1,1},{61,0,2,0,12,-1,1},{45,0,7,0,7,-1,1},{45,0,7,0,7,-1,1},{45,0,7,0,7,-1,1},{61,0,2,0,12,-1,1},{45,0,12,17,7,-1,1},{45,0,12,17,7,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1}}, {{23,0,7,0,0,-1,1},{23,0,7,0,0,-1,1},{23,0,7,0,0,-1,1},{23,0,7,0,0,-1,1},{23,0,7,0,0,-1,1},{23,0,7,0,0,-1,1},{23,0,7,0,0,-1,1},{23,0,7,0,0,-1,1},{23,0,7,0,0,-1,1},{23,0,7,0,0,-1,1},{23,0,7,0,0,-1,1},{23,0,7,0,0,-1,1},{23,0,7,0,0,-1,1},{23,0,7,0,0,-1,1},{23,0,7,0,0,-1,1},{23,0,7,0,0,-1,1},{23,0,7,0,0,-1,1},{23,0,7,0,0,-1,1},{23,0,7,0,0,-1,1},{23,0,7,0,0,-1,1},{23,0,7,0,0,-1,1},{23,0,7,0,0,-1,1},{23,0,7,0,0,-1,1},{23,0,7,0,0,-1,1},{23,0,7,0,0,-1,1},{23,0,7,0,0,-1,1},{23,0,7,0,0,-1,1},{23,0,7,0,0,-1,1},{23,0,7,0,0,-1,1},{23,0,7,0,0,-1,1},{23,0,7,0,0,-1,1},{23,0,7,0,0,-1,1}}, {{23,0,7,0,0,-1,1},{23,0,7,0,0,-1,1},{23,0,7,0,0,-1,1},{23,0,7,0,11,-1,1},{23,0,7,0,11,-1,1},{23,0,7,0,0,-1,1},{23,0,7,0,0,-1,1},{23,0,7,0,0,-1,1},{23,0,7,0,4,-1,1},{23,0,7,0,0,-1,1},{23,0,7,0,0,-1,1},{23,0,7,0,0,-1,1},{23,0,7,0,0,-1,1},{23,0,7,0,0,-1,1},{23,0,7,0,0,-1,1},{23,0,7,0,0,-1,1},{23,0,7,0,0,-1,1},{23,0,7,0,0,-1,1},{23,0,7,0,0,-1,1},{23,0,7,0,0,-1,1},{23,0,12,17,10,-1,1},{23,0,12,17,10,-1,1},{23,0,10,0,0,-1,1},{23,0,12,17,0,-1,1},{23,0,12,17,0,-1,1},{23,0,12,17,0,-1,1},{23,0,12,17,0,-1,1},{23,0,12,17,0,-1,1},{23,0,12,17,0,-1,1},{23,0,12,17,0,-1,1},{23,0,10,0,0,-1,1},{23,0,10,0,0,-1,1}}, @@ -616,35 +619,35 @@ static const nsCharProps2 sCharProp2Valu {{14,0,5,0,0,-1,1},{14,0,5,0,0,-1,1},{14,0,5,0,0,-1,1},{14,0,5,0,0,-1,1},{14,0,5,0,0,-1,1},{14,0,5,0,0,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{14,0,9,0,0,-1,1},{14,0,9,0,0,-1,1},{14,0,9,0,0,-1,1},{14,0,9,0,0,-1,1},{14,0,9,0,0,-1,1},{14,0,9,0,0,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{14,0,5,0,0,-1,1},{14,0,5,0,0,-1,1},{14,0,5,0,0,-1,1},{14,0,5,0,0,-1,1},{14,0,5,0,0,-1,1},{14,0,5,0,0,-1,1},{14,0,5,0,0,-1,1},{14,0,5,0,0,-1,1},{61,0,2,0,12,-1,1},{14,0,9,0,0,-1,1},{61,0,2,0,12,-1,1},{14,0,9,0,0,-1,1},{61,0,2,0,12,-1,1},{14,0,9,0,0,-1,1},{61,0,2,0,12,-1,1},{14,0,9,0,0,-1,1}}, {{14,0,5,0,0,-1,1},{14,0,5,0,0,-1,1},{14,0,5,0,0,-1,1},{14,0,5,0,0,-1,1},{14,0,5,0,0,-1,1},{14,0,5,0,0,-1,1},{14,0,5,0,0,-1,1},{14,0,5,0,0,-1,1},{14,0,9,0,0,-1,1},{14,0,9,0,0,-1,1},{14,0,9,0,0,-1,1},{14,0,9,0,0,-1,1},{14,0,9,0,0,-1,1},{14,0,9,0,0,-1,1},{14,0,9,0,0,-1,1},{14,0,9,0,0,-1,1},{14,0,5,0,0,-1,1},{14,0,5,0,9,-1,1},{14,0,5,0,0,-1,1},{14,0,5,0,9,-1,1},{14,0,5,0,0,-1,1},{14,0,5,0,9,-1,1},{14,0,5,0,0,-1,1},{14,0,5,0,9,-1,1},{14,0,5,0,0,-1,1},{14,0,5,0,9,-1,1},{14,0,5,0,0,-1,1},{14,0,5,0,9,-1,1},{14,0,5,0,0,-1,1},{14,0,5,0,9,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1}}, {{14,0,5,0,0,-1,1},{14,0,5,0,0,-1,1},{14,0,5,0,0,-1,1},{14,0,5,0,0,-1,1},{14,0,5,0,0,-1,1},{14,0,5,0,0,-1,1},{14,0,5,0,0,-1,1},{14,0,5,0,0,-1,1},{14,0,8,0,0,-1,1},{14,0,8,0,0,-1,1},{14,0,8,0,0,-1,1},{14,0,8,0,0,-1,1},{14,0,8,0,0,-1,1},{14,0,8,0,0,-1,1},{14,0,8,0,0,-1,1},{14,0,8,0,0,-1,1},{14,0,5,0,0,-1,1},{14,0,5,0,0,-1,1},{14,0,5,0,0,-1,1},{14,0,5,0,0,-1,1},{14,0,5,0,0,-1,1},{14,0,5,0,0,-1,1},{14,0,5,0,0,-1,1},{14,0,5,0,0,-1,1},{14,0,8,0,0,-1,1},{14,0,8,0,0,-1,1},{14,0,8,0,0,-1,1},{14,0,8,0,0,-1,1},{14,0,8,0,0,-1,1},{14,0,8,0,0,-1,1},{14,0,8,0,0,-1,1},{14,0,8,0,0,-1,1}}, {{14,0,5,0,0,-1,1},{14,0,5,0,0,-1,1},{14,0,5,0,0,-1,1},{14,0,5,0,0,-1,1},{14,0,5,0,0,-1,1},{14,0,5,0,0,-1,1},{14,0,5,0,0,-1,1},{14,0,5,0,0,-1,1},{14,0,8,0,0,-1,1},{14,0,8,0,0,-1,1},{14,0,8,0,0,-1,1},{14,0,8,0,0,-1,1},{14,0,8,0,0,-1,1},{14,0,8,0,0,-1,1},{14,0,8,0,0,-1,1},{14,0,8,0,0,-1,1},{14,0,5,0,0,-1,1},{14,0,5,0,0,-1,1},{14,0,5,0,0,-1,1},{14,0,5,0,0,-1,1},{14,0,5,0,0,-1,1},{61,0,2,0,12,-1,1},{14,0,5,0,0,-1,1},{14,0,5,0,0,-1,1},{14,0,9,0,0,-1,1},{14,0,9,0,0,-1,1},{14,0,9,0,0,-1,1},{14,0,9,0,9,-1,1},{14,0,8,0,0,-1,1},{14,0,24,10,9,-1,1},{14,0,5,0,9,-1,1},{14,0,24,10,9,-1,1}}, {{14,0,24,10,9,-1,1},{14,0,24,10,9,-1,1},{14,0,5,0,0,-1,1},{14,0,5,0,0,-1,1},{14,0,5,0,0,-1,1},{61,0,2,0,12,-1,1},{14,0,5,0,0,-1,1},{14,0,5,0,0,-1,1},{14,0,9,0,0,-1,1},{14,0,9,0,9,-1,1},{14,0,9,0,0,-1,1},{14,0,9,0,9,-1,1},{14,0,8,0,0,-1,1},{14,0,24,10,9,-1,1},{14,0,24,10,9,-1,1},{14,0,24,10,9,-1,1},{14,0,5,0,0,-1,1},{14,0,5,0,0,-1,1},{14,0,5,0,0,-1,1},{14,0,5,0,9,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{14,0,5,0,0,-1,1},{14,0,5,0,0,-1,1},{14,0,9,0,0,-1,1},{14,0,9,0,0,-1,1},{14,0,9,0,0,-1,1},{14,0,9,0,9,-1,1},{61,0,2,0,12,-1,1},{14,0,24,10,9,-1,1},{14,0,24,10,9,-1,1},{14,0,24,10,9,-1,1}}, {{14,0,5,0,0,-1,1},{14,0,5,0,0,-1,1},{14,0,5,0,0,-1,1},{14,0,5,0,9,-1,1},{14,0,5,0,0,-1,1},{14,0,5,0,0,-1,1},{14,0,5,0,0,-1,1},{14,0,5,0,0,-1,1},{14,0,9,0,0,-1,1},{14,0,9,0,0,-1,1},{14,0,9,0,0,-1,1},{14,0,9,0,9,-1,1},{14,0,9,0,0,-1,1},{14,0,24,10,9,-1,1},{14,0,24,10,9,-1,1},{14,0,24,10,9,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{14,0,5,0,0,-1,1},{14,0,5,0,0,-1,1},{14,0,5,0,0,-1,1},{61,0,2,0,12,-1,1},{14,0,5,0,0,-1,1},{14,0,5,0,0,-1,1},{14,0,9,0,0,-1,1},{14,0,9,0,9,-1,1},{14,0,9,0,0,-1,1},{14,0,9,0,9,-1,1},{14,0,8,0,0,-1,1},{14,0,24,10,9,-1,1},{14,0,24,10,9,-1,1},{61,0,2,0,12,-1,1}}, {{0,0,29,9,9,-1,1},{0,0,29,9,9,-1,1},{0,0,29,9,9,-1,1},{0,0,29,9,9,-1,1},{0,0,29,9,9,-1,1},{0,0,29,9,9,-1,1},{0,0,29,9,9,-1,1},{0,0,29,9,9,-1,1},{0,0,29,9,9,-1,1},{0,0,29,9,9,-1,1},{0,0,29,9,9,-1,1},{0,0,1,18,10,-1,1},{1,0,1,18,1,-1,1},{1,0,1,18,1,-1,1},{0,0,1,0,10,-1,1},{0,0,1,1,10,-1,1},{0,0,17,10,1,-1,1},{0,0,17,10,9,-1,1},{0,0,17,10,8,-1,1},{0,0,17,10,8,-1,1},{0,0,17,10,8,-1,1},{0,0,17,10,8,-1,1},{0,0,21,10,8,-1,0},{0,0,21,10,9,-1,1},{0,0,20,10,8,-1,1},{0,0,19,10,1,-1,1},{0,0,22,10,8,-1,1},{0,0,20,10,8,-1,1},{0,0,20,10,8,-1,1},{0,0,19,10,8,-1,1},{0,0,22,10,8,-1,1},{0,0,20,10,8,-1,1}}, {{0,0,21,10,8,-1,0},{0,0,21,10,8,-1,0},{0,0,21,10,8,-1,1},{0,0,21,10,8,-1,1},{0,0,21,10,9,-1,1},{0,0,21,10,9,-1,1},{0,0,21,10,9,-1,1},{0,0,21,10,1,-1,1},{0,0,27,9,8,-1,1},{0,0,28,7,8,-1,1},{0,0,1,11,10,-1,1},{0,0,1,14,10,-1,1},{0,0,1,16,10,-1,1},{0,0,1,12,10,-1,1},{0,0,1,15,10,-1,1},{0,0,29,6,9,-1,1},{0,0,21,4,8,-1,0},{0,0,21,4,8,-1,0},{0,0,21,4,8,-1,1},{0,0,21,4,9,-1,1},{0,0,21,4,9,-1,1},{0,0,21,10,8,-1,1},{0,0,21,10,9,-1,1},{0,0,21,10,9,-1,1},{0,0,21,10,8,-1,1},{0,0,20,10,8,-1,1},{0,0,19,10,8,-1,1},{0,0,21,10,8,-1,0},{0,0,21,10,9,-1,0},{0,0,21,10,8,-1,1},{0,0,21,10,9,-1,1},{0,0,16,10,3,-1,1}}, - {{0,0,16,10,3,-1,1},{0,0,21,10,8,-1,1},{0,0,21,10,8,-1,0},{0,0,21,10,8,-1,1},{0,0,25,6,8,-1,1},{0,0,22,10,8,-1,1},{0,0,18,10,8,-1,1},{0,0,21,10,9,-1,0},{0,0,21,10,9,-1,0},{0,0,21,10,9,-1,0},{0,0,21,10,8,-1,1},{0,0,21,10,8,-1,1},{0,0,21,10,8,-1,1},{0,0,21,10,8,-1,1},{0,0,21,10,8,-1,1},{0,0,21,10,8,-1,1},{0,0,21,10,8,-1,1},{0,0,21,10,8,-1,0},{0,0,25,10,8,-1,1},{0,0,21,10,8,-1,1},{0,0,16,10,2,-1,1},{0,0,21,10,8,-1,1},{0,0,21,10,8,-1,1},{0,0,21,10,9,-1,1},{0,0,21,10,8,-1,1},{0,0,21,10,8,-1,1},{0,0,21,10,8,-1,1},{0,0,21,10,8,-1,1},{0,0,21,10,8,-1,1},{0,0,21,10,8,-1,1},{0,0,21,10,8,-1,1},{0,0,29,9,9,-1,1}}, - {{0,0,1,18,10,-1,1},{0,0,1,18,10,-1,1},{0,0,1,18,10,-1,1},{0,0,1,18,10,-1,1},{0,0,1,18,10,-1,1},{61,0,2,0,12,-1,0},{0,0,1,19,10,-1,1},{0,0,1,20,10,-1,1},{0,0,1,21,10,-1,1},{0,0,1,22,10,-1,1},{0,0,1,18,11,-1,1},{0,0,1,18,11,-1,1},{0,0,1,18,11,-1,1},{0,0,1,18,11,-1,1},{0,0,1,18,11,-1,1},{0,0,1,18,11,-1,1},{0,0,15,2,9,0,1},{25,0,6,0,9,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{0,0,15,2,9,4,1},{0,0,15,2,9,5,1},{0,0,15,2,9,6,1},{0,0,15,2,9,7,1},{0,0,15,2,9,8,1},{0,0,15,2,9,9,1},{0,0,25,3,9,-1,1},{0,0,25,3,9,-1,1},{0,0,25,10,9,-1,1},{0,0,22,10,9,-1,1},{0,0,18,10,9,-1,1},{25,0,6,0,9,-1,1}}, - {{0,0,15,2,9,0,1},{0,0,15,2,9,1,1},{0,0,15,2,9,2,1},{0,0,15,2,9,3,1},{0,0,15,2,9,4,1},{0,0,15,2,9,5,1},{0,0,15,2,9,6,1},{0,0,15,2,9,7,1},{0,0,15,2,9,8,1},{0,0,15,2,9,9,1},{0,0,25,3,9,-1,1},{0,0,25,3,9,-1,1},{0,0,25,10,9,-1,1},{0,0,22,10,9,-1,1},{0,0,18,10,9,-1,1},{61,0,2,0,12,-1,1},{25,0,6,0,9,-1,1},{25,0,6,0,9,-1,1},{25,0,6,0,9,-1,1},{25,0,6,0,9,-1,1},{25,0,6,0,9,-1,1},{25,0,6,0,9,-1,1},{25,0,6,0,9,-1,1},{25,0,6,0,9,-1,1},{25,0,6,0,9,-1,1},{25,0,6,0,9,-1,1},{25,0,6,0,9,-1,1},{25,0,6,0,9,-1,1},{25,0,6,0,9,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1}}, + {{0,0,16,10,3,-1,1},{0,0,21,10,8,-1,1},{0,0,21,10,8,-1,0},{0,0,21,10,8,-1,1},{0,0,25,6,8,-1,1},{0,1,22,10,8,-1,1},{0,2,18,10,8,-1,1},{0,0,21,10,9,-1,0},{0,0,21,10,9,-1,0},{0,0,21,10,9,-1,0},{0,0,21,10,8,-1,1},{0,0,21,10,8,-1,1},{0,0,21,10,8,-1,1},{0,0,21,10,8,-1,1},{0,0,21,10,8,-1,1},{0,0,21,10,8,-1,1},{0,0,21,10,8,-1,1},{0,0,21,10,8,-1,0},{0,0,25,10,8,-1,1},{0,0,21,10,8,-1,1},{0,0,16,10,2,-1,1},{0,0,21,10,8,-1,1},{0,0,21,10,8,-1,1},{0,0,21,10,9,-1,1},{0,0,21,10,8,-1,1},{0,0,21,10,8,-1,1},{0,0,21,10,8,-1,1},{0,0,21,10,8,-1,1},{0,0,21,10,8,-1,1},{0,0,21,10,8,-1,1},{0,0,21,10,8,-1,1},{0,0,29,9,9,-1,1}}, + {{0,0,1,18,10,-1,1},{0,0,1,18,10,-1,1},{0,0,1,18,10,-1,1},{0,0,1,18,10,-1,1},{0,0,1,18,10,-1,1},{61,0,2,0,12,-1,0},{0,0,1,19,10,-1,1},{0,0,1,20,10,-1,1},{0,0,1,21,10,-1,1},{0,0,1,22,10,-1,1},{0,0,1,18,11,-1,1},{0,0,1,18,11,-1,1},{0,0,1,18,11,-1,1},{0,0,1,18,11,-1,1},{0,0,1,18,11,-1,1},{0,0,1,18,11,-1,1},{0,0,15,2,9,0,1},{25,0,6,0,9,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{0,0,15,2,9,4,1},{0,0,15,2,9,5,1},{0,0,15,2,9,6,1},{0,0,15,2,9,7,1},{0,0,15,2,9,8,1},{0,0,15,2,9,9,1},{0,0,25,3,9,-1,1},{0,0,25,3,9,-1,1},{0,0,25,10,9,-1,1},{0,1,22,10,9,-1,1},{0,2,18,10,9,-1,1},{25,0,6,0,9,-1,1}}, + {{0,0,15,2,9,0,1},{0,0,15,2,9,1,1},{0,0,15,2,9,2,1},{0,0,15,2,9,3,1},{0,0,15,2,9,4,1},{0,0,15,2,9,5,1},{0,0,15,2,9,6,1},{0,0,15,2,9,7,1},{0,0,15,2,9,8,1},{0,0,15,2,9,9,1},{0,0,25,3,9,-1,1},{0,0,25,3,9,-1,1},{0,0,25,10,9,-1,1},{0,1,22,10,9,-1,1},{0,2,18,10,9,-1,1},{61,0,2,0,12,-1,1},{25,0,6,0,9,-1,1},{25,0,6,0,9,-1,1},{25,0,6,0,9,-1,1},{25,0,6,0,9,-1,1},{25,0,6,0,9,-1,1},{25,0,6,0,9,-1,1},{25,0,6,0,9,-1,1},{25,0,6,0,9,-1,1},{25,0,6,0,9,-1,1},{25,0,6,0,9,-1,1},{25,0,6,0,9,-1,1},{25,0,6,0,9,-1,1},{25,0,6,0,9,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1}}, {{0,0,23,4,8,-1,1},{0,0,23,4,8,-1,1},{0,0,23,4,8,-1,1},{0,0,23,4,8,-1,1},{0,0,23,4,8,-1,1},{0,0,23,4,8,-1,1},{0,0,23,4,8,-1,1},{0,0,23,4,8,-1,1},{0,0,23,4,9,-1,1},{0,0,23,4,8,-1,1},{0,0,23,4,8,-1,1},{0,0,23,4,8,-1,1},{0,0,23,4,8,-1,1},{0,0,23,4,8,-1,1},{0,0,23,4,8,-1,1},{0,0,23,4,8,-1,1},{0,0,23,4,8,-1,1},{0,0,23,4,8,-1,1},{0,0,23,4,8,-1,1},{0,0,23,4,8,-1,1},{0,0,23,4,8,-1,1},{0,0,23,4,8,-1,1},{0,0,23,4,8,-1,1},{0,0,23,4,8,-1,1},{0,0,23,4,8,-1,1},{0,0,23,4,8,-1,1},{0,0,23,4,8,-1,1},{0,0,23,4,8,-1,1},{0,0,23,4,8,-1,1},{0,0,23,4,8,-1,1},{0,0,23,4,8,-1,1},{61,0,2,4,12,-1,1}}, {{61,0,2,4,12,-1,1},{61,0,2,4,12,-1,1},{61,0,2,4,12,-1,1},{61,0,2,4,12,-1,1},{61,0,2,4,12,-1,1},{61,0,2,4,12,-1,1},{61,0,2,4,12,-1,1},{61,0,2,4,12,-1,1},{61,0,2,4,12,-1,1},{61,0,2,4,12,-1,1},{61,0,2,4,12,-1,1},{61,0,2,4,12,-1,1},{61,0,2,4,12,-1,1},{61,0,2,4,12,-1,1},{61,0,2,4,12,-1,1},{61,0,2,4,12,-1,1},{1,0,12,17,7,-1,1},{1,0,12,17,7,-1,1},{1,0,12,17,7,-1,1},{1,0,12,17,7,-1,1},{1,0,12,17,7,-1,1},{1,0,12,17,7,-1,1},{1,0,12,17,7,-1,1},{1,0,12,17,7,-1,1},{1,0,12,17,7,-1,1},{1,0,12,17,7,-1,1},{1,0,12,17,7,-1,1},{1,0,12,17,7,-1,1},{1,0,12,17,7,-1,1},{1,0,11,17,8,-1,0},{1,0,11,17,8,-1,0},{1,0,11,17,8,-1,0}}, {{1,0,11,17,8,-1,0},{1,0,12,17,7,-1,1},{1,0,11,17,8,-1,0},{1,0,11,17,8,-1,0},{1,0,11,17,8,-1,0},{1,0,12,17,7,-1,1},{1,0,12,17,7,-1,1},{1,0,12,17,7,-1,1},{1,0,12,17,7,-1,1},{1,0,12,17,7,-1,1},{1,0,12,17,7,-1,1},{1,0,12,17,7,-1,1},{1,0,12,17,7,-1,1},{1,0,12,17,7,-1,1},{1,0,12,17,7,-1,1},{1,0,12,17,7,-1,1},{1,0,12,17,7,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1}}, {{0,0,26,10,9,-1,0},{0,0,26,10,9,-1,0},{0,0,9,0,9,-1,1},{0,0,26,10,9,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,9,-1,0},{0,0,26,10,9,-1,0},{0,0,9,0,9,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,9,-1,0},{0,0,5,0,9,-1,1},{0,0,9,0,9,-1,1},{0,0,9,0,9,-1,1},{0,0,9,0,9,-1,1},{0,0,5,0,9,-1,1},{0,0,5,0,9,-1,0},{0,0,9,0,9,-1,1},{0,0,9,0,9,-1,1},{0,0,9,0,9,-1,1},{0,0,5,0,9,-1,0},{0,0,26,10,8,-1,0},{0,0,9,0,9,-1,1},{0,0,26,10,9,-1,0},{0,0,26,10,8,-1,0},{0,0,25,10,3,-1,1},{0,0,9,0,9,-1,1},{0,0,9,0,9,-1,1},{0,0,9,0,9,-1,1},{0,0,9,0,9,-1,1},{0,0,9,0,9,-1,1},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0}}, {{0,0,26,10,9,-1,0},{0,0,26,10,9,-1,0},{0,0,26,10,9,-1,0},{0,0,26,10,8,-1,0},{0,0,9,0,9,-1,1},{0,0,26,10,8,-1,0},{14,0,9,0,9,-1,1},{0,0,26,10,8,-1,0},{0,0,9,0,9,-1,1},{0,0,26,10,8,-1,0},{25,0,9,0,9,-1,1},{25,0,9,0,9,-1,1},{0,0,9,0,9,-1,1},{0,0,9,0,9,-1,1},{0,0,26,4,3,-1,0},{0,0,5,0,9,-1,1},{0,0,9,0,9,-1,1},{0,0,9,0,9,-1,1},{25,0,9,0,4,-1,1},{0,0,9,0,9,-1,1},{0,0,5,0,9,-1,1},{0,0,7,0,9,-1,0},{0,0,7,0,9,-1,0},{0,0,7,0,9,-1,0},{0,0,7,0,9,-1,0},{0,0,5,0,9,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,9,-1,0},{0,0,5,0,9,-1,0},{0,0,5,0,9,-1,0},{0,0,9,0,9,-1,0},{0,0,9,0,9,-1,0}}, {{0,0,25,10,9,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,9,0,9,-1,0},{0,0,5,0,9,-1,0},{0,0,5,0,9,-1,0},{0,0,5,0,9,-1,0},{0,0,5,0,9,-1,0},{0,0,26,10,8,-1,0},{0,0,25,10,8,-1,1},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{25,0,5,0,4,-1,1},{0,0,26,0,8,-1,0},{0,0,15,10,9,-1,0},{0,0,15,10,9,-1,0},{0,0,15,10,9,-1,0},{0,0,15,10,9,-1,0},{0,0,15,10,9,-1,0},{0,0,15,10,9,-1,0},{0,0,15,10,9,-1,0},{0,0,15,10,9,-1,0},{0,0,15,10,9,-1,0},{0,0,15,10,9,-1,0},{0,0,15,10,9,-1,0},{0,0,15,10,9,-1,0},{0,0,15,10,9,-1,0},{0,0,15,10,9,-1,0},{0,0,15,10,9,-1,0},{0,0,15,10,9,-1,0}}, {{25,0,14,0,9,-1,0},{25,0,14,0,9,-1,0},{25,0,14,0,9,-1,0},{25,0,14,0,9,-1,0},{25,0,14,0,9,-1,0},{25,0,14,0,9,-1,0},{25,0,14,0,9,-1,0},{25,0,14,0,9,-1,0},{25,0,14,0,9,-1,0},{25,0,14,0,9,-1,0},{25,0,14,0,9,-1,0},{25,0,14,0,9,-1,0},{25,0,14,0,9,-1,0},{25,0,14,0,9,-1,0},{25,0,14,0,9,-1,0},{25,0,14,0,9,-1,0},{25,0,14,0,9,-1,0},{25,0,14,0,9,-1,0},{25,0,14,0,9,-1,0},{25,0,14,0,9,-1,0},{25,0,14,0,9,-1,0},{25,0,14,0,9,-1,0},{25,0,14,0,9,-1,0},{25,0,14,0,9,-1,0},{25,0,14,0,9,-1,0},{25,0,14,0,9,-1,0},{25,0,14,0,9,-1,0},{25,0,14,0,9,-1,0},{25,0,14,0,9,-1,0},{25,0,14,0,9,-1,0},{25,0,14,0,9,-1,0},{25,0,14,0,9,-1,0}}, {{25,0,14,0,4,-1,0},{25,0,14,0,4,-1,0},{25,0,14,0,4,-1,0},{25,0,9,0,4,-1,0},{25,0,5,0,4,-1,0},{25,0,14,0,4,-1,0},{25,0,14,0,4,-1,0},{25,0,14,0,4,-1,0},{25,0,14,0,4,-1,0},{0,0,15,10,9,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{61,0,2,0,12,-1,0},{61,0,2,0,12,-1,0},{61,0,2,0,12,-1,0},{61,0,2,0,12,-1,0},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1}}, {{0,0,25,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1}}, {{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1}}, {{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1}}, {{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,3,8,-1,1},{0,0,25,4,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,0},{0,0,25,10,8,-1,1}}, {{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,9,-1,1},{0,0,25,10,9,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,9,-1,1},{0,0,25,10,9,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,0},{0,0,25,10,8,-1,0},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1}}, {{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1}}, - {{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,22,10,8,-1,1},{0,0,18,10,8,-1,1},{0,0,22,10,8,-1,1},{0,0,18,10,8,-1,1},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0}}, - {{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,22,10,11,-1,3},{0,0,18,10,11,-1,3},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,0,8,-1,1},{0,0,26,0,8,-1,1},{0,0,26,0,8,-1,1},{0,0,26,0,8,-1,1},{0,0,26,0,8,-1,1},{0,0,26,0,8,-1,1},{0,0,26,0,8,-1,1},{0,0,26,0,8,-1,1},{0,0,26,0,8,-1,1},{0,0,26,0,8,-1,1}}, + {{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,1,22,10,8,-1,1},{0,2,18,10,8,-1,1},{0,1,22,10,8,-1,1},{0,2,18,10,8,-1,1},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0}}, + {{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,1,22,10,11,-1,3},{0,2,18,10,11,-1,3},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,0,8,-1,1},{0,0,26,0,8,-1,1},{0,0,26,0,8,-1,1},{0,0,26,0,8,-1,1},{0,0,26,0,8,-1,1},{0,0,26,0,8,-1,1},{0,0,26,0,8,-1,1},{0,0,26,0,8,-1,1},{0,0,26,0,8,-1,1},{0,0,26,0,8,-1,1}}, {{0,0,26,0,8,-1,1},{0,0,26,0,8,-1,1},{0,0,26,0,8,-1,1},{0,0,26,0,8,-1,1},{0,0,26,0,8,-1,1},{0,0,26,0,8,-1,1},{0,0,26,0,8,-1,1},{0,0,26,0,8,-1,1},{0,0,26,0,8,-1,1},{0,0,26,0,8,-1,1},{0,0,26,0,8,-1,1},{0,0,26,0,8,-1,1},{0,0,26,0,8,-1,1},{0,0,26,0,8,-1,1},{0,0,26,0,8,-1,1},{0,0,26,0,8,-1,1},{0,0,26,0,8,-1,1},{0,0,26,0,8,-1,1},{0,0,26,0,8,-1,1},{0,0,26,0,8,-1,1},{0,0,26,0,8,-1,1},{0,0,26,0,8,-1,1},{0,0,26,0,8,-1,1},{0,0,26,0,8,-1,1},{0,0,26,0,8,-1,1},{0,0,26,0,8,-1,1},{0,0,26,0,8,-1,1},{0,0,26,0,8,-1,1},{0,0,26,0,8,-1,1},{0,0,26,0,8,-1,1},{0,0,26,0,8,-1,1},{0,0,26,0,8,-1,1}}, {{0,0,26,0,8,-1,1},{0,0,26,0,8,-1,1},{0,0,26,0,8,-1,1},{0,0,26,0,8,-1,1},{0,0,26,0,8,-1,1},{0,0,26,0,8,-1,1},{0,0,26,0,8,-1,1},{0,0,26,0,8,-1,1},{0,0,26,0,8,-1,1},{0,0,26,0,8,-1,1},{0,0,26,0,8,-1,1},{0,0,26,0,8,-1,1},{0,0,26,0,8,-1,1},{0,0,26,0,8,-1,1},{0,0,26,0,8,-1,1},{0,0,26,0,8,-1,1},{0,0,26,0,8,-1,1},{0,0,26,0,8,-1,1},{0,0,26,0,8,-1,1},{0,0,26,0,8,-1,1},{0,0,26,0,8,-1,1},{0,0,26,0,8,-1,1},{0,0,26,0,8,-1,1},{0,0,26,0,8,-1,1},{0,0,26,0,8,-1,1},{0,0,26,0,8,-1,1},{0,0,26,0,8,-1,1},{0,0,26,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0}}, {{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,0,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1}}, {{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0}}, {{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1}}, {{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{61,0,2,0,12,-1,0},{61,0,2,0,12,-1,0},{61,0,2,0,12,-1,0},{61,0,2,0,12,-1,0},{61,0,2,0,12,-1,0}}, {{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0}}, {{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{61,0,2,0,12,-1,0},{61,0,2,0,12,-1,0},{61,0,2,0,12,-1,0},{61,0,2,0,12,-1,0},{61,0,2,0,12,-1,0},{61,0,2,0,12,-1,0},{61,0,2,0,12,-1,0},{61,0,2,0,12,-1,0},{61,0,2,0,12,-1,0},{61,0,2,0,12,-1,0},{61,0,2,0,12,-1,0},{61,0,2,0,12,-1,0},{61,0,2,0,12,-1,0},{61,0,2,0,12,-1,0},{61,0,2,0,12,-1,0},{61,0,2,0,12,-1,0},{61,0,2,0,12,-1,0},{61,0,2,0,12,-1,0},{61,0,2,0,12,-1,0},{61,0,2,0,12,-1,0},{61,0,2,0,12,-1,0},{61,0,2,0,12,-1,0},{61,0,2,0,12,-1,0},{61,0,2,0,12,-1,0},{61,0,2,0,12,-1,0}}, @@ -655,24 +658,24 @@ static const nsCharProps2 sCharProp2Valu {{0,0,26,0,9,-1,0},{0,0,26,0,9,-1,0},{0,0,26,0,9,-1,0},{0,0,26,0,9,-1,0},{0,0,26,0,9,-1,0},{0,0,26,0,9,-1,0},{0,0,26,0,9,-1,0},{0,0,26,0,9,-1,0},{0,0,26,0,9,-1,0},{0,0,26,0,9,-1,0},{0,0,15,10,9,0,0},{0,0,15,10,8,-1,0},{0,0,15,10,8,-1,0},{0,0,15,10,8,-1,0},{0,0,15,10,8,-1,0},{0,0,15,10,8,-1,0},{0,0,15,10,8,-1,0},{0,0,15,10,8,-1,0},{0,0,15,10,8,-1,0},{0,0,15,10,8,-1,0},{0,0,15,10,8,-1,0},{0,0,15,10,8,1,0},{0,0,15,10,8,2,0},{0,0,15,10,8,3,0},{0,0,15,10,8,4,0},{0,0,15,10,8,5,0},{0,0,15,10,8,6,0},{0,0,15,10,8,7,0},{0,0,15,10,8,8,0},{0,0,15,10,8,9,0},{0,0,15,10,8,-1,0},{0,0,15,10,8,0,0}}, {{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1}}, {{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,25,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0}}, {{0,0,26,10,8,-1,0},{0,0,25,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0}}, {{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,25,10,8,-1,0},{0,0,25,10,8,-1,0},{0,0,25,10,8,-1,0},{0,0,25,10,8,-1,0},{0,0,25,10,8,-1,0},{0,0,25,10,8,-1,0},{0,0,25,10,8,-1,0},{0,0,25,10,8,-1,0}}, {{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1}}, {{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,25,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0}}, {{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,0,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0}}, - {{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,22,10,8,-1,1},{0,0,18,10,8,-1,1},{0,0,22,10,8,-1,1},{0,0,18,10,8,-1,1},{0,0,22,10,8,-1,1},{0,0,18,10,8,-1,1},{0,0,22,10,8,-1,1},{0,0,18,10,8,-1,1},{0,0,22,10,8,-1,1},{0,0,18,10,8,-1,1},{0,0,22,10,8,-1,1},{0,0,18,10,8,-1,1},{0,0,22,10,8,-1,1},{0,0,18,10,8,-1,1},{0,0,15,10,8,1,0},{0,0,15,10,8,2,0},{0,0,15,10,8,3,0},{0,0,15,10,8,4,0},{0,0,15,10,8,5,0},{0,0,15,10,8,6,0},{0,0,15,10,8,7,0},{0,0,15,10,8,8,0},{0,0,15,10,8,9,0},{0,0,15,10,8,-1,0}}, + {{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,1,22,10,8,-1,1},{0,2,18,10,8,-1,1},{0,1,22,10,8,-1,1},{0,2,18,10,8,-1,1},{0,1,22,10,8,-1,1},{0,2,18,10,8,-1,1},{0,1,22,10,8,-1,1},{0,2,18,10,8,-1,1},{0,1,22,10,8,-1,1},{0,2,18,10,8,-1,1},{0,1,22,10,8,-1,1},{0,2,18,10,8,-1,1},{0,1,22,10,8,-1,1},{0,2,18,10,8,-1,1},{0,0,15,10,8,1,0},{0,0,15,10,8,2,0},{0,0,15,10,8,3,0},{0,0,15,10,8,4,0},{0,0,15,10,8,5,0},{0,0,15,10,8,6,0},{0,0,15,10,8,7,0},{0,0,15,10,8,8,0},{0,0,15,10,8,9,0},{0,0,15,10,8,-1,0}}, {{0,0,15,10,8,1,0},{0,0,15,10,8,2,0},{0,0,15,10,8,3,0},{0,0,15,10,8,4,0},{0,0,15,10,8,5,0},{0,0,15,10,8,6,0},{0,0,15,10,8,7,0},{0,0,15,10,8,8,0},{0,0,15,10,8,9,0},{0,0,15,10,8,-1,0},{0,0,15,10,8,1,0},{0,0,15,10,8,2,0},{0,0,15,10,8,3,0},{0,0,15,10,8,4,0},{0,0,15,10,8,5,0},{0,0,15,10,8,6,0},{0,0,15,10,8,7,0},{0,0,15,10,8,8,0},{0,0,15,10,8,9,0},{0,0,15,10,8,-1,0},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1}}, - {{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,22,10,8,-1,1},{0,0,18,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1}}, - {{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,22,10,8,-1,1},{0,0,18,10,8,-1,1},{0,0,22,10,8,-1,1},{0,0,18,10,8,-1,1},{0,0,22,10,8,-1,1},{0,0,18,10,8,-1,1},{0,0,22,10,8,-1,1},{0,0,18,10,8,-1,1},{0,0,22,10,8,-1,1},{0,0,18,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1}}, + {{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,1,22,10,8,-1,1},{0,2,18,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1}}, + {{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,1,22,10,8,-1,1},{0,2,18,10,8,-1,1},{0,1,22,10,8,-1,1},{0,2,18,10,8,-1,1},{0,1,22,10,8,-1,1},{0,2,18,10,8,-1,1},{0,1,22,10,8,-1,1},{0,2,18,10,8,-1,1},{0,1,22,10,8,-1,1},{0,2,18,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1}}, {{46,0,26,0,8,-1,1},{46,0,26,0,8,-1,1},{46,0,26,0,8,-1,1},{46,0,26,0,8,-1,1},{46,0,26,0,8,-1,1},{46,0,26,0,8,-1,1},{46,0,26,0,8,-1,1},{46,0,26,0,8,-1,1},{46,0,26,0,8,-1,1},{46,0,26,0,8,-1,1},{46,0,26,0,8,-1,1},{46,0,26,0,8,-1,1},{46,0,26,0,8,-1,1},{46,0,26,0,8,-1,1},{46,0,26,0,8,-1,1},{46,0,26,0,8,-1,1},{46,0,26,0,8,-1,1},{46,0,26,0,8,-1,1},{46,0,26,0,8,-1,1},{46,0,26,0,8,-1,1},{46,0,26,0,8,-1,1},{46,0,26,0,8,-1,1},{46,0,26,0,8,-1,1},{46,0,26,0,8,-1,1},{46,0,26,0,8,-1,1},{46,0,26,0,8,-1,1},{46,0,26,0,8,-1,1},{46,0,26,0,8,-1,1},{46,0,26,0,8,-1,1},{46,0,26,0,8,-1,1},{46,0,26,0,8,-1,1},{46,0,26,0,8,-1,1}}, - {{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,22,10,8,-1,1},{0,0,18,10,8,-1,1},{0,0,22,10,8,-1,1},{0,0,18,10,8,-1,1},{0,0,22,10,8,-1,1},{0,0,18,10,8,-1,1},{0,0,22,10,8,-1,1},{0,0,18,10,8,-1,1},{0,0,22,10,8,-1,1},{0,0,18,10,8,-1,1},{0,0,22,10,8,-1,1},{0,0,18,10,8,-1,1},{0,0,22,10,8,-1,1},{0,0,18,10,8,-1,1},{0,0,22,10,8,-1,1},{0,0,18,10,8,-1,1},{0,0,22,10,8,-1,1},{0,0,18,10,8,-1,1},{0,0,22,10,8,-1,1},{0,0,18,10,8,-1,1},{0,0,22,10,8,-1,1},{0,0,18,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1}}, - {{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,22,10,8,-1,1},{0,0,18,10,8,-1,1},{0,0,22,10,8,-1,1},{0,0,18,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1}}, - {{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,22,10,8,-1,1},{0,0,18,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1}}, + {{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,1,22,10,8,-1,1},{0,2,18,10,8,-1,1},{0,1,22,10,8,-1,1},{0,2,18,10,8,-1,1},{0,1,22,10,8,-1,1},{0,2,18,10,8,-1,1},{0,1,22,10,8,-1,1},{0,2,18,10,8,-1,1},{0,1,22,10,8,-1,1},{0,2,18,10,8,-1,1},{0,1,22,10,8,-1,1},{0,2,18,10,8,-1,1},{0,1,22,10,8,-1,1},{0,2,18,10,8,-1,1},{0,1,22,10,8,-1,1},{0,2,18,10,8,-1,1},{0,1,22,10,8,-1,1},{0,2,18,10,8,-1,1},{0,1,22,10,8,-1,1},{0,2,18,10,8,-1,1},{0,1,22,10,8,-1,1},{0,2,18,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1}}, + {{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,1,22,10,8,-1,1},{0,2,18,10,8,-1,1},{0,1,22,10,8,-1,1},{0,2,18,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1}}, + {{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,1,22,10,8,-1,1},{0,2,18,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1}}, {{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,9,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1}}, {{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,9,-1,1},{0,0,25,10,9,-1,1},{0,0,25,10,9,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1}}, {{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,9,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1}}, {{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0}}, {{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1}}, {{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,25,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1}}, {{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1}}, {{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1},{0,0,26,10,8,-1,1}}, @@ -688,25 +691,25 @@ static const nsCharProps2 sCharProp2Valu {{12,0,5,0,4,-1,1},{12,0,5,0,4,-1,1},{12,0,5,0,4,-1,1},{12,0,5,0,4,-1,1},{12,0,5,0,4,-1,1},{12,0,5,0,4,-1,1},{12,0,5,0,4,-1,1},{12,0,5,0,4,-1,1},{12,0,5,0,4,-1,1},{12,0,5,0,4,-1,1},{12,0,5,0,4,-1,1},{12,0,5,0,4,-1,1},{12,0,5,0,4,-1,1},{12,0,5,0,4,-1,1},{12,0,5,0,4,-1,1},{12,0,5,0,4,-1,1},{12,0,5,0,4,-1,1},{12,0,5,0,4,-1,1},{12,0,5,0,4,-1,1},{12,0,5,0,4,-1,1},{12,0,5,0,4,-1,1},{12,0,5,0,4,-1,1},{12,0,5,0,4,-1,1},{12,0,5,0,4,-1,1},{12,0,5,0,4,-1,1},{12,0,5,0,4,-1,1},{12,0,5,0,4,-1,1},{12,0,5,0,4,-1,1},{12,0,5,0,4,-1,1},{12,0,5,0,4,-1,1},{12,0,5,0,4,-1,1},{12,0,5,0,4,-1,1}}, {{12,0,5,0,4,-1,1},{12,0,5,0,4,-1,1},{12,0,5,0,4,-1,1},{12,0,5,0,4,-1,1},{12,0,5,0,4,-1,1},{12,0,5,0,4,-1,1},{61,0,2,0,12,-1,1},{12,0,5,0,0,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{12,0,5,0,0,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{57,0,7,0,5,-1,1},{57,0,7,0,5,-1,1},{57,0,7,0,5,-1,1},{57,0,7,0,5,-1,1},{57,0,7,0,5,-1,1},{57,0,7,0,5,-1,1},{57,0,7,0,5,-1,1},{57,0,7,0,5,-1,1},{57,0,7,0,5,-1,1},{57,0,7,0,5,-1,1},{57,0,7,0,5,-1,1},{57,0,7,0,5,-1,1},{57,0,7,0,5,-1,1},{57,0,7,0,5,-1,1},{57,0,7,0,5,-1,1},{57,0,7,0,5,-1,1}}, {{57,0,7,0,5,-1,1},{57,0,7,0,5,-1,1},{57,0,7,0,5,-1,1},{57,0,7,0,5,-1,1},{57,0,7,0,5,-1,1},{57,0,7,0,5,-1,1},{57,0,7,0,5,-1,1},{57,0,7,0,5,-1,1},{57,0,7,0,5,-1,1},{57,0,7,0,5,-1,1},{57,0,7,0,5,-1,1},{57,0,7,0,5,-1,1},{57,0,7,0,5,-1,1},{57,0,7,0,5,-1,1},{57,0,7,0,5,-1,1},{57,0,7,0,5,-1,1},{57,0,7,0,5,-1,1},{57,0,7,0,5,-1,1},{57,0,7,0,5,-1,1},{57,0,7,0,5,-1,1},{57,0,7,0,5,-1,1},{57,0,7,0,5,-1,1},{57,0,7,0,5,-1,1},{57,0,7,0,5,-1,1},{57,0,7,0,5,-1,1},{57,0,7,0,5,-1,1},{57,0,7,0,5,-1,1},{57,0,7,0,5,-1,1},{57,0,7,0,5,-1,1},{57,0,7,0,5,-1,1},{57,0,7,0,5,-1,1},{57,0,7,0,5,-1,1}}, {{57,0,7,0,5,-1,1},{57,0,7,0,5,-1,1},{57,0,7,0,5,-1,1},{57,0,7,0,5,-1,1},{57,0,7,0,5,-1,1},{57,0,7,0,5,-1,1},{57,0,7,0,5,-1,1},{57,0,7,0,5,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{57,0,6,0,9,-1,1},{57,0,21,0,8,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{57,0,12,17,5,-1,1}}, {{11,0,7,0,0,-1,1},{11,0,7,0,0,-1,1},{11,0,7,0,0,-1,1},{11,0,7,0,0,-1,1},{11,0,7,0,0,-1,1},{11,0,7,0,0,-1,1},{11,0,7,0,0,-1,1},{11,0,7,0,0,-1,1},{11,0,7,0,0,-1,1},{11,0,7,0,0,-1,1},{11,0,7,0,0,-1,1},{11,0,7,0,0,-1,1},{11,0,7,0,0,-1,1},{11,0,7,0,0,-1,1},{11,0,7,0,0,-1,1},{11,0,7,0,0,-1,1},{11,0,7,0,0,-1,1},{11,0,7,0,0,-1,1},{11,0,7,0,0,-1,1},{11,0,7,0,0,-1,1},{11,0,7,0,0,-1,1},{11,0,7,0,0,-1,1},{11,0,7,0,0,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1}}, {{11,0,7,0,0,-1,1},{11,0,7,0,0,-1,1},{11,0,7,0,0,-1,1},{11,0,7,0,0,-1,1},{11,0,7,0,0,-1,1},{11,0,7,0,0,-1,1},{11,0,7,0,0,-1,1},{61,0,2,0,12,-1,1},{11,0,7,0,0,-1,1},{11,0,7,0,0,-1,1},{11,0,7,0,0,-1,1},{11,0,7,0,0,-1,1},{11,0,7,0,0,-1,1},{11,0,7,0,0,-1,1},{11,0,7,0,0,-1,1},{61,0,2,0,12,-1,1},{11,0,7,0,0,-1,1},{11,0,7,0,0,-1,1},{11,0,7,0,0,-1,1},{11,0,7,0,0,-1,1},{11,0,7,0,0,-1,1},{11,0,7,0,0,-1,1},{11,0,7,0,0,-1,1},{61,0,2,0,12,-1,1},{11,0,7,0,0,-1,1},{11,0,7,0,0,-1,1},{11,0,7,0,0,-1,1},{11,0,7,0,0,-1,1},{11,0,7,0,0,-1,1},{11,0,7,0,0,-1,1},{11,0,7,0,0,-1,1},{61,0,2,0,12,-1,1}}, {{8,0,12,17,4,-1,1},{8,0,12,17,4,-1,1},{8,0,12,17,4,-1,1},{8,0,12,17,4,-1,1},{8,0,12,17,4,-1,1},{8,0,12,17,4,-1,1},{8,0,12,17,4,-1,1},{8,0,12,17,4,-1,1},{8,0,12,17,4,-1,1},{8,0,12,17,4,-1,1},{8,0,12,17,4,-1,1},{8,0,12,17,4,-1,1},{8,0,12,17,4,-1,1},{8,0,12,17,4,-1,1},{8,0,12,17,4,-1,1},{8,0,12,17,4,-1,1},{8,0,12,17,4,-1,1},{8,0,12,17,4,-1,1},{8,0,12,17,4,-1,1},{8,0,12,17,4,-1,1},{8,0,12,17,4,-1,1},{8,0,12,17,4,-1,1},{8,0,12,17,4,-1,1},{8,0,12,17,4,-1,1},{8,0,12,17,4,-1,1},{8,0,12,17,4,-1,1},{8,0,12,17,4,-1,1},{8,0,12,17,4,-1,1},{8,0,12,17,4,-1,1},{8,0,12,17,4,-1,1},{8,0,12,17,4,-1,1},{8,0,12,17,4,-1,1}}, {{0,0,21,10,8,-1,1},{0,0,21,10,8,-1,1},{0,0,20,10,8,-1,1},{0,0,19,10,8,-1,1},{0,0,20,10,8,-1,1},{0,0,19,10,8,-1,1},{0,0,21,10,8,-1,1},{0,0,21,10,8,-1,1},{0,0,21,10,8,-1,1},{0,0,20,10,8,-1,1},{0,0,19,10,8,-1,1},{0,0,21,10,8,-1,1},{0,0,20,10,8,-1,1},{0,0,19,10,8,-1,1},{0,0,21,10,8,-1,1},{0,0,21,10,8,-1,1},{0,0,21,10,8,-1,1},{0,0,21,10,8,-1,1},{0,0,21,10,8,-1,1},{0,0,21,10,8,-1,1},{0,0,21,10,8,-1,1},{0,0,21,10,8,-1,1},{0,0,21,10,8,-1,1},{0,0,17,10,8,-1,1},{0,0,21,10,8,-1,1},{0,0,21,10,8,-1,1},{0,0,17,10,8,-1,1},{0,0,21,10,8,-1,1},{0,0,20,10,8,-1,1},{0,0,19,10,8,-1,1},{0,0,21,10,8,-1,1},{0,0,21,10,8,-1,1}}, - {{0,0,20,10,8,-1,1},{0,0,19,10,8,-1,1},{0,0,22,10,8,-1,1},{0,0,18,10,8,-1,1},{0,0,22,10,8,-1,1},{0,0,18,10,8,-1,1},{0,0,22,10,8,-1,1},{0,0,18,10,8,-1,1},{0,0,22,10,8,-1,1},{0,0,18,10,8,-1,1},{0,0,21,10,8,-1,1},{0,0,21,10,8,-1,1},{0,0,21,10,8,-1,1},{0,0,21,10,8,-1,1},{0,0,21,10,8,-1,1},{0,0,6,10,8,-1,1},{0,0,21,10,8,-1,1},{0,0,21,10,8,-1,1},{0,0,21,10,8,-1,1},{0,0,21,10,8,-1,1},{0,0,21,10,8,-1,1},{0,0,21,10,8,-1,1},{0,0,21,10,8,-1,1},{0,0,21,10,8,-1,1},{0,0,21,10,8,-1,1},{0,0,21,10,8,-1,1},{0,0,17,10,8,-1,1},{0,0,17,10,8,-1,1},{0,0,21,10,8,-1,1},{0,0,21,10,8,-1,1},{0,0,21,10,8,-1,1},{0,0,21,10,8,-1,1}}, + {{0,0,20,10,8,-1,1},{0,0,19,10,8,-1,1},{0,1,22,10,8,-1,1},{0,2,18,10,8,-1,1},{0,1,22,10,8,-1,1},{0,2,18,10,8,-1,1},{0,1,22,10,8,-1,1},{0,2,18,10,8,-1,1},{0,1,22,10,8,-1,1},{0,2,18,10,8,-1,1},{0,0,21,10,8,-1,1},{0,0,21,10,8,-1,1},{0,0,21,10,8,-1,1},{0,0,21,10,8,-1,1},{0,0,21,10,8,-1,1},{0,0,6,10,8,-1,1},{0,0,21,10,8,-1,1},{0,0,21,10,8,-1,1},{0,0,21,10,8,-1,1},{0,0,21,10,8,-1,1},{0,0,21,10,8,-1,1},{0,0,21,10,8,-1,1},{0,0,21,10,8,-1,1},{0,0,21,10,8,-1,1},{0,0,21,10,8,-1,1},{0,0,21,10,8,-1,1},{0,0,17,10,8,-1,1},{0,0,17,10,8,-1,1},{0,0,21,10,8,-1,1},{0,0,21,10,8,-1,1},{0,0,21,10,8,-1,1},{0,0,21,10,8,-1,1}}, {{0,0,17,10,8,-1,1},{0,0,21,10,8,-1,1},{0,0,22,10,8,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1}}, {{17,0,26,10,8,-1,0},{17,0,26,10,8,-1,0},{17,0,26,10,8,-1,0},{17,0,26,10,8,-1,0},{17,0,26,10,8,-1,0},{17,0,26,10,8,-1,0},{17,0,26,10,8,-1,0},{17,0,26,10,8,-1,0},{17,0,26,10,8,-1,0},{17,0,26,10,8,-1,0},{17,0,26,10,8,-1,0},{17,0,26,10,8,-1,0},{17,0,26,10,8,-1,0},{17,0,26,10,8,-1,0},{17,0,26,10,8,-1,0},{17,0,26,10,8,-1,0},{17,0,26,10,8,-1,0},{17,0,26,10,8,-1,0},{17,0,26,10,8,-1,0},{17,0,26,10,8,-1,0},{17,0,26,10,8,-1,0},{17,0,26,10,8,-1,0},{17,0,26,10,8,-1,0},{17,0,26,10,8,-1,0},{17,0,26,10,8,-1,0},{17,0,26,10,8,-1,0},{61,0,2,0,12,-1,0},{17,0,26,10,8,-1,0},{17,0,26,10,8,-1,0},{17,0,26,10,8,-1,0},{17,0,26,10,8,-1,0},{17,0,26,10,9,-1,0}}, {{17,0,26,10,8,-1,0},{17,0,26,10,8,-1,0},{17,0,26,10,8,-1,0},{17,0,26,10,8,-1,0},{17,0,26,10,8,-1,0},{17,0,26,10,8,-1,0},{17,0,26,10,8,-1,0},{17,0,26,10,8,-1,0},{17,0,26,10,8,-1,0},{17,0,26,10,8,-1,0},{17,0,26,10,8,-1,0},{17,0,26,10,8,-1,0},{17,0,26,10,8,-1,0},{17,0,26,10,8,-1,0},{17,0,26,10,8,-1,0},{17,0,26,10,8,-1,0},{17,0,26,10,8,-1,0},{17,0,26,10,8,-1,0},{17,0,26,10,8,-1,0},{17,0,26,10,8,-1,0},{17,0,26,10,8,-1,0},{17,0,26,10,8,-1,0},{17,0,26,10,8,-1,0},{17,0,26,10,8,-1,0},{17,0,26,10,8,-1,0},{17,0,26,10,8,-1,0},{17,0,26,10,8,-1,0},{17,0,26,10,8,-1,0},{17,0,26,10,8,-1,0},{17,0,26,10,8,-1,0},{17,0,26,10,8,-1,0},{17,0,26,10,8,-1,0}}, {{17,0,26,10,8,-1,0},{17,0,26,10,8,-1,0},{17,0,26,10,8,-1,0},{17,0,26,10,8,-1,0},{17,0,26,10,8,-1,0},{17,0,26,10,8,-1,0},{17,0,26,10,8,-1,0},{17,0,26,10,8,-1,0},{17,0,26,10,8,-1,0},{17,0,26,10,8,-1,0},{17,0,26,10,8,-1,0},{17,0,26,10,8,-1,0},{17,0,26,10,8,-1,0},{17,0,26,10,8,-1,0},{17,0,26,10,8,-1,0},{17,0,26,10,8,-1,0},{17,0,26,10,8,-1,0},{17,0,26,10,8,-1,0},{17,0,26,10,8,-1,0},{17,0,26,10,9,-1,0},{61,0,2,0,12,-1,0},{61,0,2,0,12,-1,0},{61,0,2,0,12,-1,0},{61,0,2,0,12,-1,0},{61,0,2,0,12,-1,0},{61,0,2,0,12,-1,0},{61,0,2,0,12,-1,0},{61,0,2,0,12,-1,0},{61,0,2,0,12,-1,0},{61,0,2,0,12,-1,0},{61,0,2,0,12,-1,0},{61,0,2,0,12,-1,0}}, {{17,0,26,10,9,-1,0},{17,0,26,10,9,-1,0},{17,0,26,10,9,-1,0},{17,0,26,10,9,-1,0},{17,0,26,10,9,-1,0},{17,0,26,10,9,-1,0},{17,0,26,10,9,-1,0},{17,0,26,10,9,-1,0},{17,0,26,10,9,-1,0},{17,0,26,10,9,-1,0},{17,0,26,10,9,-1,0},{17,0,26,10,9,-1,0},{17,0,26,10,9,-1,0},{17,0,26,10,9,-1,0},{17,0,26,10,9,-1,0},{17,0,26,10,9,-1,0},{17,0,26,10,9,-1,0},{17,0,26,10,9,-1,0},{17,0,26,10,9,-1,0},{17,0,26,10,9,-1,0},{17,0,26,10,9,-1,0},{17,0,26,10,9,-1,0},{17,0,26,10,9,-1,0},{17,0,26,10,9,-1,0},{17,0,26,10,9,-1,0},{17,0,26,10,9,-1,0},{17,0,26,10,9,-1,0},{17,0,26,10,9,-1,0},{17,0,26,10,9,-1,0},{17,0,26,10,9,-1,0},{17,0,26,10,9,-1,0},{17,0,26,10,9,-1,0}}, {{17,0,26,10,9,-1,0},{17,0,26,10,9,-1,0},{17,0,26,10,9,-1,0},{17,0,26,10,9,-1,0},{17,0,26,10,9,-1,0},{17,0,26,10,9,-1,0},{17,0,26,10,9,-1,0},{17,0,26,10,9,-1,0},{17,0,26,10,9,-1,0},{17,0,26,10,9,-1,0},{17,0,26,10,9,-1,0},{17,0,26,10,9,-1,0},{17,0,26,10,9,-1,0},{17,0,26,10,9,-1,0},{17,0,26,10,9,-1,0},{17,0,26,10,9,-1,0},{17,0,26,10,9,-1,0},{17,0,26,10,9,-1,0},{17,0,26,10,9,-1,0},{17,0,26,10,9,-1,0},{17,0,26,10,9,-1,0},{17,0,26,10,9,-1,0},{61,0,2,0,12,-1,0},{61,0,2,0,12,-1,0},{61,0,2,0,12,-1,0},{61,0,2,0,12,-1,0},{61,0,2,0,12,-1,0},{61,0,2,0,12,-1,0},{61,0,2,0,12,-1,0},{61,0,2,0,12,-1,0},{61,0,2,0,12,-1,0},{61,0,2,0,12,-1,0}}, {{61,0,2,0,12,-1,0},{61,0,2,0,12,-1,0},{61,0,2,0,12,-1,0},{61,0,2,0,12,-1,0},{61,0,2,0,12,-1,0},{61,0,2,0,12,-1,0},{61,0,2,0,12,-1,0},{61,0,2,0,12,-1,0},{61,0,2,0,12,-1,0},{61,0,2,0,12,-1,0},{61,0,2,0,12,-1,0},{61,0,2,0,12,-1,0},{61,0,2,0,12,-1,0},{61,0,2,0,12,-1,0},{61,0,2,0,12,-1,0},{61,0,2,0,12,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{61,0,2,0,12,-1,0},{61,0,2,0,12,-1,0},{61,0,2,0,12,-1,0},{61,0,2,0,12,-1,0}}, - {{0,0,29,9,9,-1,0},{0,0,21,10,8,-1,2},{0,0,21,10,8,-1,2},{0,0,21,10,8,-1,0},{0,0,26,10,8,-1,0},{17,0,6,0,0,-1,0},{0,0,7,0,0,-1,0},{17,0,14,0,0,-1,0},{0,0,22,10,8,-1,3},{0,0,18,10,8,-1,3},{0,0,22,10,8,-1,3},{0,0,18,10,8,-1,3},{0,0,22,10,8,-1,3},{0,0,18,10,8,-1,3},{0,0,22,10,8,-1,3},{0,0,18,10,8,-1,3},{0,0,22,10,8,-1,3},{0,0,18,10,8,-1,3},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,22,10,8,-1,3},{0,0,18,10,8,-1,3},{0,0,22,10,8,-1,3},{0,0,18,10,8,-1,3},{0,0,22,10,8,-1,3},{0,0,18,10,8,-1,3},{0,0,22,10,8,-1,3},{0,0,18,10,8,-1,3},{0,0,17,10,8,-1,3},{0,0,22,10,8,-1,3},{0,0,18,10,8,-1,3},{0,0,18,10,8,-1,3}}, + {{0,0,29,9,9,-1,0},{0,0,21,10,8,-1,2},{0,0,21,10,8,-1,2},{0,0,21,10,8,-1,0},{0,0,26,10,8,-1,0},{17,0,6,0,0,-1,0},{0,0,7,0,0,-1,0},{17,0,14,0,0,-1,0},{0,1,22,10,8,-1,3},{0,2,18,10,8,-1,3},{0,1,22,10,8,-1,3},{0,2,18,10,8,-1,3},{0,1,22,10,8,-1,3},{0,2,18,10,8,-1,3},{0,1,22,10,8,-1,3},{0,2,18,10,8,-1,3},{0,1,22,10,8,-1,3},{0,2,18,10,8,-1,3},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{0,1,22,10,8,-1,3},{0,2,18,10,8,-1,3},{0,1,22,10,8,-1,3},{0,2,18,10,8,-1,3},{0,1,22,10,8,-1,3},{0,2,18,10,8,-1,3},{0,1,22,10,8,-1,3},{0,2,18,10,8,-1,3},{0,0,17,10,8,-1,3},{0,0,22,10,8,-1,3},{0,0,18,10,8,-1,3},{0,0,18,10,8,-1,3}}, {{0,0,26,10,8,-1,0},{17,0,14,0,3,-1,0},{17,0,14,0,3,-1,0},{17,0,14,0,3,-1,0},{17,0,14,0,3,-1,0},{17,0,14,0,3,-1,0},{17,0,14,0,3,-1,0},{17,0,14,0,3,-1,0},{17,0,14,0,3,-1,0},{17,0,14,0,3,-1,0},{1,0,12,17,3,-1,0},{1,0,12,17,3,-1,0},{1,0,12,17,3,-1,0},{1,0,12,17,3,-1,0},{18,0,10,0,4,-1,0},{18,0,10,0,4,-1,0},{0,0,17,10,8,-1,3},{0,0,6,0,3,-1,0},{0,0,6,0,3,-1,0},{0,0,6,0,3,-1,0},{0,0,6,0,3,-1,0},{0,0,6,0,3,-1,0},{0,0,26,10,9,-1,0},{0,0,26,10,8,-1,0},{17,0,14,0,9,-1,0},{17,0,14,0,9,-1,0},{17,0,14,0,9,-1,0},{17,0,6,0,3,-1,0},{0,0,7,0,3,-1,0},{0,0,21,10,8,-1,0},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0}}, {{61,0,2,0,12,-1,0},{20,0,7,0,0,-1,2},{20,0,7,0,0,-1,0},{20,0,7,0,0,-1,2},{20,0,7,0,0,-1,0},{20,0,7,0,0,-1,2},{20,0,7,0,0,-1,0},{20,0,7,0,0,-1,2},{20,0,7,0,0,-1,0},{20,0,7,0,0,-1,2},{20,0,7,0,0,-1,0},{20,0,7,0,0,-1,0},{20,0,7,0,0,-1,0},{20,0,7,0,0,-1,0},{20,0,7,0,0,-1,0},{20,0,7,0,0,-1,0},{20,0,7,0,0,-1,0},{20,0,7,0,0,-1,0},{20,0,7,0,0,-1,0},{20,0,7,0,0,-1,0},{20,0,7,0,0,-1,0},{20,0,7,0,0,-1,0},{20,0,7,0,0,-1,0},{20,0,7,0,0,-1,0},{20,0,7,0,0,-1,0},{20,0,7,0,0,-1,0},{20,0,7,0,0,-1,0},{20,0,7,0,0,-1,0},{20,0,7,0,0,-1,0},{20,0,7,0,0,-1,0},{20,0,7,0,0,-1,0},{20,0,7,0,0,-1,0}}, {{20,0,7,0,0,-1,0},{20,0,7,0,0,-1,0},{20,0,7,0,0,-1,0},{20,0,7,0,0,-1,2},{20,0,7,0,0,-1,0},{20,0,7,0,0,-1,0},{20,0,7,0,0,-1,0},{20,0,7,0,0,-1,0},{20,0,7,0,0,-1,0},{20,0,7,0,0,-1,0},{20,0,7,0,0,-1,0},{20,0,7,0,0,-1,0},{20,0,7,0,0,-1,0},{20,0,7,0,0,-1,0},{20,0,7,0,0,-1,0},{20,0,7,0,0,-1,0},{20,0,7,0,0,-1,0},{20,0,7,0,0,-1,0},{20,0,7,0,0,-1,0},{20,0,7,0,0,-1,0},{20,0,7,0,0,-1,0},{20,0,7,0,0,-1,0},{20,0,7,0,0,-1,0},{20,0,7,0,0,-1,0},{20,0,7,0,0,-1,0},{20,0,7,0,0,-1,0},{20,0,7,0,0,-1,0},{20,0,7,0,0,-1,0},{20,0,7,0,0,-1,0},{20,0,7,0,0,-1,0},{20,0,7,0,0,-1,0},{20,0,7,0,0,-1,0}}, {{20,0,7,0,0,-1,0},{20,0,7,0,0,-1,0},{20,0,7,0,0,-1,0},{20,0,7,0,0,-1,2},{20,0,7,0,0,-1,0},{20,0,7,0,0,-1,2},{20,0,7,0,0,-1,0},{20,0,7,0,0,-1,2},{20,0,7,0,0,-1,0},{20,0,7,0,0,-1,0},{20,0,7,0,0,-1,0},{20,0,7,0,0,-1,0},{20,0,7,0,0,-1,0},{20,0,7,0,0,-1,0},{20,0,7,0,0,-1,2},{20,0,7,0,0,-1,0},{20,0,7,0,0,-1,0},{20,0,7,0,0,-1,0},{20,0,7,0,0,-1,0},{20,0,7,0,0,-1,0},{20,0,7,0,0,-1,0},{20,0,7,0,0,-1,2},{20,0,7,0,0,-1,2},{61,0,2,0,12,-1,0},{61,0,2,0,12,-1,0},{1,0,12,17,0,-1,0},{1,0,12,17,0,-1,0},{0,0,24,10,9,-1,2},{0,0,24,10,9,-1,2},{20,0,6,0,0,-1,0},{20,0,6,0,0,-1,0},{20,0,7,0,9,-1,0}}, {{0,0,17,10,1,-1,3},{22,0,7,0,0,-1,2},{22,0,7,0,0,-1,0},{22,0,7,0,0,-1,2},{22,0,7,0,0,-1,0},{22,0,7,0,0,-1,2},{22,0,7,0,0,-1,0},{22,0,7,0,0,-1,2},{22,0,7,0,0,-1,0},{22,0,7,0,0,-1,2},{22,0,7,0,0,-1,0},{22,0,7,0,0,-1,0},{22,0,7,0,0,-1,0},{22,0,7,0,0,-1,0},{22,0,7,0,0,-1,0},{22,0,7,0,0,-1,0},{22,0,7,0,0,-1,0},{22,0,7,0,0,-1,0},{22,0,7,0,0,-1,0},{22,0,7,0,0,-1,0},{22,0,7,0,0,-1,0},{22,0,7,0,0,-1,0},{22,0,7,0,0,-1,0},{22,0,7,0,0,-1,0},{22,0,7,0,0,-1,0},{22,0,7,0,0,-1,0},{22,0,7,0,0,-1,0},{22,0,7,0,0,-1,0},{22,0,7,0,0,-1,0},{22,0,7,0,0,-1,0},{22,0,7,0,0,-1,0},{22,0,7,0,0,-1,0}}, {{22,0,7,0,0,-1,0},{22,0,7,0,0,-1,0},{22,0,7,0,0,-1,0},{22,0,7,0,0,-1,2},{22,0,7,0,0,-1,0},{22,0,7,0,0,-1,0},{22,0,7,0,0,-1,0},{22,0,7,0,0,-1,0},{22,0,7,0,0,-1,0},{22,0,7,0,0,-1,0},{22,0,7,0,0,-1,0},{22,0,7,0,0,-1,0},{22,0,7,0,0,-1,0},{22,0,7,0,0,-1,0},{22,0,7,0,0,-1,0},{22,0,7,0,0,-1,0},{22,0,7,0,0,-1,0},{22,0,7,0,0,-1,0},{22,0,7,0,0,-1,0},{22,0,7,0,0,-1,0},{22,0,7,0,0,-1,0},{22,0,7,0,0,-1,0},{22,0,7,0,0,-1,0},{22,0,7,0,0,-1,0},{22,0,7,0,0,-1,0},{22,0,7,0,0,-1,0},{22,0,7,0,0,-1,0},{22,0,7,0,0,-1,0},{22,0,7,0,0,-1,0},{22,0,7,0,0,-1,0},{22,0,7,0,0,-1,0},{22,0,7,0,0,-1,0}}, {{22,0,7,0,0,-1,0},{22,0,7,0,0,-1,0},{22,0,7,0,0,-1,0},{22,0,7,0,0,-1,2},{22,0,7,0,0,-1,0},{22,0,7,0,0,-1,2},{22,0,7,0,0,-1,0},{22,0,7,0,0,-1,2},{22,0,7,0,0,-1,0},{22,0,7,0,0,-1,0},{22,0,7,0,0,-1,0},{22,0,7,0,0,-1,0},{22,0,7,0,0,-1,0},{22,0,7,0,0,-1,0},{22,0,7,0,0,-1,2},{22,0,7,0,0,-1,0},{22,0,7,0,0,-1,0},{22,0,7,0,0,-1,0},{22,0,7,0,0,-1,0},{22,0,7,0,0,-1,0},{22,0,7,0,0,-1,0},{22,0,7,0,0,-1,2},{22,0,7,0,0,-1,2},{22,0,7,0,0,-1,0},{22,0,7,0,0,-1,0},{22,0,7,0,0,-1,0},{22,0,7,0,0,-1,0},{0,0,21,10,1,-1,0},{0,0,6,0,0,-1,3},{22,0,6,0,0,-1,0},{22,0,6,0,0,-1,0},{22,0,7,0,9,-1,0}}, {{61,0,2,0,12,-1,0},{61,0,2,0,12,-1,0},{61,0,2,0,12,-1,0},{61,0,2,0,12,-1,0},{61,0,2,0,12,-1,0},{5,0,7,0,0,-1,0},{5,0,7,0,0,-1,0},{5,0,7,0,0,-1,0},{5,0,7,0,0,-1,0},{5,0,7,0,0,-1,0},{5,0,7,0,0,-1,0},{5,0,7,0,0,-1,0},{5,0,7,0,0,-1,0},{5,0,7,0,0,-1,0},{5,0,7,0,0,-1,0},{5,0,7,0,0,-1,0},{5,0,7,0,0,-1,0},{5,0,7,0,0,-1,0},{5,0,7,0,0,-1,0},{5,0,7,0,0,-1,0},{5,0,7,0,0,-1,0},{5,0,7,0,0,-1,0},{5,0,7,0,0,-1,0},{5,0,7,0,0,-1,0},{5,0,7,0,0,-1,0},{5,0,7,0,0,-1,0},{5,0,7,0,0,-1,0},{5,0,7,0,0,-1,0},{5,0,7,0,0,-1,0},{5,0,7,0,0,-1,0},{5,0,7,0,0,-1,0},{5,0,7,0,0,-1,0}}, @@ -801,23 +804,23 @@ static const nsCharProps2 sCharProp2Valu {{2,0,24,13,8,-1,1},{2,0,24,13,8,-1,1},{61,0,2,13,12,-1,1},{61,0,2,13,12,-1,1},{61,0,2,13,12,-1,1},{61,0,2,13,12,-1,1},{61,0,2,13,12,-1,1},{61,0,2,13,12,-1,1},{61,0,2,13,12,-1,1},{61,0,2,13,12,-1,1},{61,0,2,13,12,-1,1},{61,0,2,13,12,-1,1},{61,0,2,13,12,-1,1},{61,0,2,13,12,-1,1},{61,0,2,13,12,-1,1},{61,0,2,13,12,-1,1},{61,0,2,13,12,-1,1},{61,0,2,13,12,-1,1},{61,0,2,13,12,-1,1},{2,0,7,13,9,-1,1},{2,0,7,13,9,-1,1},{2,0,7,13,9,-1,1},{2,0,7,13,9,-1,1},{2,0,7,13,9,-1,1},{2,0,7,13,9,-1,1},{2,0,7,13,9,-1,1},{2,0,7,13,9,-1,1},{2,0,7,13,9,-1,1},{2,0,7,13,9,-1,1},{2,0,7,13,9,-1,1},{2,0,7,13,9,-1,1},{2,0,7,13,9,-1,1}}, {{2,0,7,13,9,-1,1},{2,0,7,13,9,-1,1},{2,0,7,13,9,-1,1},{2,0,7,13,9,-1,1},{2,0,7,13,9,-1,1},{2,0,7,13,9,-1,1},{2,0,7,13,9,-1,1},{2,0,7,13,9,-1,1},{2,0,7,13,9,-1,1},{2,0,7,13,9,-1,1},{2,0,7,13,9,-1,1},{2,0,7,13,9,-1,1},{2,0,7,13,9,-1,1},{2,0,7,13,9,-1,1},{2,0,7,13,9,-1,1},{2,0,7,13,9,-1,1},{2,0,7,13,9,-1,1},{2,0,7,13,9,-1,1},{2,0,7,13,9,-1,1},{2,0,7,13,9,-1,1},{2,0,7,13,9,-1,1},{2,0,7,13,9,-1,1},{2,0,7,13,9,-1,1},{2,0,7,13,9,-1,1},{2,0,7,13,9,-1,1},{2,0,7,13,9,-1,1},{2,0,7,13,9,-1,1},{2,0,7,13,9,-1,1},{2,0,7,13,9,-1,1},{2,0,7,13,9,-1,1},{0,0,18,10,8,-1,1},{0,0,22,10,8,-1,1}}, {{61,0,2,13,12,-1,1},{61,0,2,13,12,-1,1},{61,0,2,13,12,-1,1},{61,0,2,13,12,-1,1},{61,0,2,13,12,-1,1},{61,0,2,13,12,-1,1},{61,0,2,13,12,-1,1},{61,0,2,13,12,-1,1},{61,0,2,13,12,-1,1},{61,0,2,13,12,-1,1},{61,0,2,13,12,-1,1},{61,0,2,13,12,-1,1},{61,0,2,13,12,-1,1},{61,0,2,13,12,-1,1},{61,0,2,13,12,-1,1},{61,0,2,13,12,-1,1},{2,0,7,13,9,-1,1},{2,0,7,13,9,-1,1},{2,0,7,13,9,-1,1},{2,0,7,13,9,-1,1},{2,0,7,13,9,-1,1},{2,0,7,13,9,-1,1},{2,0,7,13,9,-1,1},{2,0,7,13,9,-1,1},{2,0,7,13,9,-1,1},{2,0,7,13,9,-1,1},{2,0,7,13,9,-1,1},{2,0,7,13,9,-1,1},{2,0,7,13,9,-1,1},{2,0,7,13,9,-1,1},{2,0,7,13,9,-1,1},{2,0,7,13,9,-1,1}}, {{2,0,7,13,9,-1,1},{2,0,7,13,9,-1,1},{2,0,7,13,9,-1,1},{2,0,7,13,9,-1,1},{2,0,7,13,9,-1,1},{2,0,7,13,9,-1,1},{2,0,7,13,9,-1,1},{2,0,7,13,9,-1,1},{2,0,7,13,9,-1,1},{2,0,7,13,9,-1,1},{2,0,7,13,9,-1,1},{2,0,7,13,9,-1,1},{2,0,7,13,9,-1,1},{2,0,7,13,9,-1,1},{2,0,7,13,9,-1,1},{2,0,7,13,9,-1,1},{61,0,2,13,12,-1,1},{61,0,2,13,12,-1,1},{2,0,7,13,9,-1,1},{2,0,7,13,9,-1,1},{2,0,7,13,9,-1,1},{2,0,7,13,9,-1,1},{2,0,7,13,9,-1,1},{2,0,7,13,9,-1,1},{2,0,7,13,9,-1,1},{2,0,7,13,9,-1,1},{2,0,7,13,9,-1,1},{2,0,7,13,9,-1,1},{2,0,7,13,9,-1,1},{2,0,7,13,9,-1,1},{2,0,7,13,9,-1,1},{2,0,7,13,9,-1,1}}, {{2,0,7,13,9,-1,1},{2,0,7,13,9,-1,1},{2,0,7,13,9,-1,1},{2,0,7,13,9,-1,1},{2,0,7,13,9,-1,1},{2,0,7,13,9,-1,1},{2,0,7,13,9,-1,1},{2,0,7,13,9,-1,1},{61,0,2,13,12,-1,1},{61,0,2,13,12,-1,1},{61,0,2,13,12,-1,1},{61,0,2,13,12,-1,1},{61,0,2,13,12,-1,1},{61,0,2,13,12,-1,1},{61,0,2,13,12,-1,1},{61,0,2,13,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1}}, {{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{2,0,7,13,9,-1,1},{2,0,7,13,9,-1,1},{2,0,7,13,9,-1,1},{2,0,7,13,9,-1,1},{2,0,7,13,9,-1,1},{2,0,7,13,9,-1,1},{2,0,7,13,9,-1,1},{2,0,7,13,9,-1,1},{2,0,7,13,9,-1,1},{2,0,7,13,9,-1,1},{2,0,7,13,9,-1,1},{2,0,7,13,9,-1,1},{2,0,23,13,9,-1,1},{2,0,26,10,8,-1,1},{61,0,2,13,12,-1,1},{61,0,2,13,12,-1,1}}, {{1,0,12,17,10,-1,1},{1,0,12,17,10,-1,1},{1,0,12,17,10,-1,1},{1,0,12,17,10,-1,1},{1,0,12,17,10,-1,1},{1,0,12,17,10,-1,1},{1,0,12,17,10,-1,1},{1,0,12,17,10,-1,1},{1,0,12,17,10,-1,1},{1,0,12,17,10,-1,1},{1,0,12,17,10,-1,1},{1,0,12,17,10,-1,1},{1,0,12,17,10,-1,1},{1,0,12,17,10,-1,1},{1,0,12,17,10,-1,1},{1,0,12,17,10,-1,1},{0,0,21,10,9,-1,0},{0,0,21,10,9,-1,0},{0,0,21,10,9,-1,0},{0,0,21,10,9,-1,0},{0,0,21,10,9,-1,0},{0,0,21,10,9,-1,0},{0,0,21,10,9,-1,0},{0,0,22,10,9,-1,0},{0,0,18,10,9,-1,0},{0,0,21,10,9,-1,0},{61,0,2,0,12,-1,0},{61,0,2,0,12,-1,0},{61,0,2,0,12,-1,0},{61,0,2,0,12,-1,0},{61,0,2,0,12,-1,0},{61,0,2,0,12,-1,0}}, {{1,0,12,17,3,-1,1},{1,0,12,17,3,-1,1},{1,0,12,17,3,-1,1},{1,0,12,17,3,-1,1},{1,0,12,17,3,-1,1},{1,0,12,17,3,-1,1},{1,0,12,17,3,-1,1},{1,0,12,17,3,-1,1},{1,0,12,17,3,-1,1},{1,0,12,17,3,-1,1},{1,0,12,17,3,-1,1},{1,0,12,17,3,-1,1},{1,0,12,17,3,-1,1},{1,0,12,17,3,-1,1},{8,0,12,17,3,-1,1},{8,0,12,17,3,-1,1},{0,0,21,10,9,-1,0},{0,0,17,10,9,-1,0},{0,0,17,10,9,-1,0},{0,0,16,10,9,-1,0},{0,0,16,10,9,-1,0},{0,0,22,10,9,-1,0},{0,0,18,10,9,-1,0},{0,0,22,10,9,-1,0},{0,0,18,10,9,-1,0},{0,0,22,10,9,-1,0},{0,0,18,10,9,-1,0},{0,0,22,10,9,-1,0},{0,0,18,10,9,-1,0},{0,0,22,10,9,-1,0},{0,0,18,10,9,-1,0},{0,0,22,10,9,-1,0}}, - {{0,0,18,10,9,-1,0},{0,0,22,10,9,-1,0},{0,0,18,10,9,-1,0},{0,0,22,10,9,-1,0},{0,0,18,10,9,-1,0},{0,0,21,10,8,-1,0},{0,0,21,10,8,-1,0},{0,0,22,10,9,-1,0},{0,0,18,10,9,-1,0},{0,0,21,10,9,-1,1},{0,0,21,10,9,-1,1},{0,0,21,10,9,-1,1},{0,0,21,10,9,-1,1},{0,0,16,10,9,-1,1},{0,0,16,10,9,-1,1},{0,0,16,10,9,-1,1},{0,0,21,6,9,-1,2},{0,0,21,10,9,-1,2},{0,0,21,6,9,-1,2},{61,0,2,0,12,-1,0},{0,0,21,10,9,-1,0},{0,0,21,6,9,-1,0},{0,0,21,10,9,-1,0},{0,0,21,10,9,-1,0},{0,0,17,10,9,-1,1},{0,0,22,10,9,-1,3},{0,0,18,10,9,-1,3},{0,0,22,10,9,-1,3},{0,0,18,10,9,-1,3},{0,0,22,10,9,-1,3},{0,0,18,10,9,-1,3},{0,0,21,4,9,-1,0}}, + {{0,0,18,10,9,-1,0},{0,0,22,10,9,-1,0},{0,0,18,10,9,-1,0},{0,0,22,10,9,-1,0},{0,0,18,10,9,-1,0},{0,0,21,10,8,-1,0},{0,0,21,10,8,-1,0},{0,0,22,10,9,-1,0},{0,0,18,10,9,-1,0},{0,0,21,10,9,-1,1},{0,0,21,10,9,-1,1},{0,0,21,10,9,-1,1},{0,0,21,10,9,-1,1},{0,0,16,10,9,-1,1},{0,0,16,10,9,-1,1},{0,0,16,10,9,-1,1},{0,0,21,6,9,-1,2},{0,0,21,10,9,-1,2},{0,0,21,6,9,-1,2},{61,0,2,0,12,-1,0},{0,0,21,10,9,-1,0},{0,0,21,6,9,-1,0},{0,0,21,10,9,-1,0},{0,0,21,10,9,-1,0},{0,0,17,10,9,-1,1},{0,1,22,10,9,-1,3},{0,2,18,10,9,-1,3},{0,1,22,10,9,-1,3},{0,2,18,10,9,-1,3},{0,1,22,10,9,-1,3},{0,2,18,10,9,-1,3},{0,0,21,4,9,-1,0}}, {{0,0,21,10,9,-1,0},{0,0,21,10,9,-1,0},{0,0,25,3,9,-1,0},{0,0,17,3,9,-1,1},{0,0,25,10,9,-1,1},{0,0,25,10,9,-1,1},{0,0,25,10,9,-1,1},{61,0,2,0,12,-1,0},{0,0,21,10,9,-1,0},{0,0,23,4,9,-1,0},{0,0,21,4,9,-1,0},{0,0,21,10,9,-1,0},{61,0,2,0,12,-1,0},{61,0,2,0,12,-1,0},{61,0,2,0,12,-1,0},{61,0,2,0,12,-1,0},{2,0,7,13,9,-1,1},{2,0,7,13,9,-1,1},{2,0,7,13,9,-1,1},{2,0,7,13,3,-1,1},{2,0,7,13,9,-1,1},{61,0,2,13,12,-1,1},{2,0,7,13,9,-1,1},{2,0,7,13,9,-1,1},{2,0,7,13,9,-1,1},{2,0,7,13,9,-1,1},{2,0,7,13,9,-1,1},{2,0,7,13,9,-1,1},{2,0,7,13,9,-1,1},{2,0,7,13,9,-1,1},{2,0,7,13,9,-1,1},{2,0,7,13,9,-1,1}}, {{2,0,7,13,9,-1,1},{2,0,7,13,9,-1,1},{2,0,7,13,9,-1,1},{2,0,7,13,9,-1,1},{2,0,7,13,9,-1,1},{2,0,7,13,9,-1,1},{2,0,7,13,9,-1,1},{2,0,7,13,9,-1,1},{2,0,7,13,9,-1,1},{2,0,7,13,9,-1,1},{2,0,7,13,9,-1,1},{2,0,7,13,9,-1,1},{2,0,7,13,9,-1,1},{2,0,7,13,9,-1,1},{2,0,7,13,9,-1,1},{2,0,7,13,9,-1,1},{2,0,7,13,9,-1,1},{2,0,7,13,9,-1,1},{2,0,7,13,9,-1,1},{2,0,7,13,9,-1,1},{2,0,7,13,9,-1,1},{2,0,7,13,9,-1,1},{2,0,7,13,9,-1,1},{2,0,7,13,9,-1,1},{2,0,7,13,9,-1,1},{2,0,7,13,9,-1,1},{2,0,7,13,9,-1,1},{2,0,7,13,9,-1,1},{2,0,7,13,9,-1,1},{61,0,2,13,12,-1,1},{61,0,2,13,12,-1,1},{0,0,1,18,10,-1,1}}, - {{61,0,2,0,12,-1,1},{0,0,21,10,9,-1,2},{0,0,21,10,9,-1,0},{0,0,21,4,9,-1,0},{0,0,23,4,9,-1,0},{0,0,21,4,9,-1,0},{0,0,21,10,9,-1,0},{0,0,21,10,9,-1,0},{0,0,22,10,9,-1,3},{0,0,18,10,9,-1,3},{0,0,21,10,9,-1,0},{0,0,25,3,9,-1,0},{0,0,21,6,9,-1,2},{0,0,17,3,9,-1,1},{0,0,21,6,9,-1,2},{0,0,21,6,9,-1,0},{0,0,13,2,9,0,0},{0,0,13,2,9,1,0},{0,0,13,2,9,2,0},{0,0,13,2,9,3,0},{0,0,13,2,9,4,0},{0,0,13,2,9,5,0},{0,0,13,2,9,6,0},{0,0,13,2,9,7,0},{0,0,13,2,9,8,0},{0,0,13,2,9,9,0},{0,0,21,6,9,-1,3},{0,0,21,10,9,-1,3},{0,0,25,10,9,-1,1},{0,0,25,10,9,-1,1},{0,0,25,10,9,-1,1},{0,0,21,10,9,-1,2}}, - {{0,0,21,10,9,-1,0},{25,0,9,0,9,-1,0},{25,0,9,0,9,-1,0},{25,0,9,0,9,-1,0},{25,0,9,0,9,-1,0},{25,0,9,0,9,-1,0},{25,0,9,0,9,-1,0},{25,0,9,0,9,-1,0},{25,0,9,0,9,-1,0},{25,0,9,0,9,-1,0},{25,0,9,0,9,-1,0},{25,0,9,0,9,-1,0},{25,0,9,0,9,-1,0},{25,0,9,0,9,-1,0},{25,0,9,0,9,-1,0},{25,0,9,0,9,-1,0},{25,0,9,0,9,-1,0},{25,0,9,0,9,-1,0},{25,0,9,0,9,-1,0},{25,0,9,0,9,-1,0},{25,0,9,0,9,-1,0},{25,0,9,0,9,-1,0},{25,0,9,0,9,-1,0},{25,0,9,0,9,-1,0},{25,0,9,0,9,-1,0},{25,0,9,0,9,-1,0},{25,0,9,0,9,-1,0},{0,0,22,10,9,-1,3},{0,0,21,10,9,-1,0},{0,0,18,10,9,-1,3},{0,0,24,10,9,-1,0},{0,0,16,10,9,-1,3}}, - {{0,0,24,10,9,-1,0},{25,0,5,0,9,-1,0},{25,0,5,0,9,-1,0},{25,0,5,0,9,-1,0},{25,0,5,0,9,-1,0},{25,0,5,0,9,-1,0},{25,0,5,0,9,-1,0},{25,0,5,0,9,-1,0},{25,0,5,0,9,-1,0},{25,0,5,0,9,-1,0},{25,0,5,0,9,-1,0},{25,0,5,0,9,-1,0},{25,0,5,0,9,-1,0},{25,0,5,0,9,-1,0},{25,0,5,0,9,-1,0},{25,0,5,0,9,-1,0},{25,0,5,0,9,-1,0},{25,0,5,0,9,-1,0},{25,0,5,0,9,-1,0},{25,0,5,0,9,-1,0},{25,0,5,0,9,-1,0},{25,0,5,0,9,-1,0},{25,0,5,0,9,-1,0},{25,0,5,0,9,-1,0},{25,0,5,0,9,-1,0},{25,0,5,0,9,-1,0},{25,0,5,0,9,-1,0},{0,0,22,10,9,-1,3},{0,0,25,10,9,-1,3},{0,0,18,10,9,-1,3},{0,0,25,10,9,-1,3},{0,0,22,10,9,-1,3}}, - {{0,0,18,10,9,-1,3},{0,0,21,10,9,-1,1},{0,0,22,10,9,-1,1},{0,0,18,10,9,-1,1},{0,0,21,10,9,-1,1},{0,0,21,10,9,-1,1},{22,0,7,0,9,-1,1},{22,0,7,0,9,-1,1},{22,0,7,0,9,-1,1},{22,0,7,0,9,-1,1},{22,0,7,0,9,-1,1},{22,0,7,0,9,-1,1},{22,0,7,0,9,-1,1},{22,0,7,0,9,-1,1},{22,0,7,0,9,-1,1},{22,0,7,0,9,-1,1},{0,0,6,0,9,-1,1},{22,0,7,0,9,-1,1},{22,0,7,0,9,-1,1},{22,0,7,0,9,-1,1},{22,0,7,0,9,-1,1},{22,0,7,0,9,-1,1},{22,0,7,0,9,-1,1},{22,0,7,0,9,-1,1},{22,0,7,0,9,-1,1},{22,0,7,0,9,-1,1},{22,0,7,0,9,-1,1},{22,0,7,0,9,-1,1},{22,0,7,0,9,-1,1},{22,0,7,0,9,-1,1},{22,0,7,0,9,-1,1},{22,0,7,0,9,-1,1}}, + {{61,0,2,0,12,-1,1},{0,0,21,10,9,-1,2},{0,0,21,10,9,-1,0},{0,0,21,4,9,-1,0},{0,0,23,4,9,-1,0},{0,0,21,4,9,-1,0},{0,0,21,10,9,-1,0},{0,0,21,10,9,-1,0},{0,1,22,10,9,-1,3},{0,2,18,10,9,-1,3},{0,0,21,10,9,-1,0},{0,0,25,3,9,-1,0},{0,0,21,6,9,-1,2},{0,0,17,3,9,-1,1},{0,0,21,6,9,-1,2},{0,0,21,6,9,-1,0},{0,0,13,2,9,0,0},{0,0,13,2,9,1,0},{0,0,13,2,9,2,0},{0,0,13,2,9,3,0},{0,0,13,2,9,4,0},{0,0,13,2,9,5,0},{0,0,13,2,9,6,0},{0,0,13,2,9,7,0},{0,0,13,2,9,8,0},{0,0,13,2,9,9,0},{0,0,21,6,9,-1,3},{0,0,21,10,9,-1,3},{0,0,25,10,9,-1,1},{0,0,25,10,9,-1,1},{0,0,25,10,9,-1,1},{0,0,21,10,9,-1,2}}, + {{0,0,21,10,9,-1,0},{25,0,9,0,9,-1,0},{25,0,9,0,9,-1,0},{25,0,9,0,9,-1,0},{25,0,9,0,9,-1,0},{25,0,9,0,9,-1,0},{25,0,9,0,9,-1,0},{25,0,9,0,9,-1,0},{25,0,9,0,9,-1,0},{25,0,9,0,9,-1,0},{25,0,9,0,9,-1,0},{25,0,9,0,9,-1,0},{25,0,9,0,9,-1,0},{25,0,9,0,9,-1,0},{25,0,9,0,9,-1,0},{25,0,9,0,9,-1,0},{25,0,9,0,9,-1,0},{25,0,9,0,9,-1,0},{25,0,9,0,9,-1,0},{25,0,9,0,9,-1,0},{25,0,9,0,9,-1,0},{25,0,9,0,9,-1,0},{25,0,9,0,9,-1,0},{25,0,9,0,9,-1,0},{25,0,9,0,9,-1,0},{25,0,9,0,9,-1,0},{25,0,9,0,9,-1,0},{0,1,22,10,9,-1,3},{0,0,21,10,9,-1,0},{0,2,18,10,9,-1,3},{0,0,24,10,9,-1,0},{0,0,16,10,9,-1,3}}, + {{0,0,24,10,9,-1,0},{25,0,5,0,9,-1,0},{25,0,5,0,9,-1,0},{25,0,5,0,9,-1,0},{25,0,5,0,9,-1,0},{25,0,5,0,9,-1,0},{25,0,5,0,9,-1,0},{25,0,5,0,9,-1,0},{25,0,5,0,9,-1,0},{25,0,5,0,9,-1,0},{25,0,5,0,9,-1,0},{25,0,5,0,9,-1,0},{25,0,5,0,9,-1,0},{25,0,5,0,9,-1,0},{25,0,5,0,9,-1,0},{25,0,5,0,9,-1,0},{25,0,5,0,9,-1,0},{25,0,5,0,9,-1,0},{25,0,5,0,9,-1,0},{25,0,5,0,9,-1,0},{25,0,5,0,9,-1,0},{25,0,5,0,9,-1,0},{25,0,5,0,9,-1,0},{25,0,5,0,9,-1,0},{25,0,5,0,9,-1,0},{25,0,5,0,9,-1,0},{25,0,5,0,9,-1,0},{0,1,22,10,9,-1,3},{0,0,25,10,9,-1,3},{0,2,18,10,9,-1,3},{0,0,25,10,9,-1,3},{0,1,22,10,9,-1,3}}, + {{0,2,18,10,9,-1,3},{0,0,21,10,9,-1,1},{0,1,22,10,9,-1,1},{0,2,18,10,9,-1,1},{0,0,21,10,9,-1,1},{0,0,21,10,9,-1,1},{22,0,7,0,9,-1,1},{22,0,7,0,9,-1,1},{22,0,7,0,9,-1,1},{22,0,7,0,9,-1,1},{22,0,7,0,9,-1,1},{22,0,7,0,9,-1,1},{22,0,7,0,9,-1,1},{22,0,7,0,9,-1,1},{22,0,7,0,9,-1,1},{22,0,7,0,9,-1,1},{0,0,6,0,9,-1,1},{22,0,7,0,9,-1,1},{22,0,7,0,9,-1,1},{22,0,7,0,9,-1,1},{22,0,7,0,9,-1,1},{22,0,7,0,9,-1,1},{22,0,7,0,9,-1,1},{22,0,7,0,9,-1,1},{22,0,7,0,9,-1,1},{22,0,7,0,9,-1,1},{22,0,7,0,9,-1,1},{22,0,7,0,9,-1,1},{22,0,7,0,9,-1,1},{22,0,7,0,9,-1,1},{22,0,7,0,9,-1,1},{22,0,7,0,9,-1,1}}, {{22,0,7,0,9,-1,1},{22,0,7,0,9,-1,1},{22,0,7,0,9,-1,1},{22,0,7,0,9,-1,1},{22,0,7,0,9,-1,1},{22,0,7,0,9,-1,1},{22,0,7,0,9,-1,1},{22,0,7,0,9,-1,1},{22,0,7,0,9,-1,1},{22,0,7,0,9,-1,1},{22,0,7,0,9,-1,1},{22,0,7,0,9,-1,1},{22,0,7,0,9,-1,1},{22,0,7,0,9,-1,1},{22,0,7,0,9,-1,1},{22,0,7,0,9,-1,1},{22,0,7,0,9,-1,1},{22,0,7,0,9,-1,1},{22,0,7,0,9,-1,1},{22,0,7,0,9,-1,1},{22,0,7,0,9,-1,1},{22,0,7,0,9,-1,1},{22,0,7,0,9,-1,1},{22,0,7,0,9,-1,1},{22,0,7,0,9,-1,1},{22,0,7,0,9,-1,1},{22,0,7,0,9,-1,1},{22,0,7,0,9,-1,1},{22,0,7,0,9,-1,1},{22,0,7,0,9,-1,1},{0,0,6,0,9,-1,1},{0,0,6,0,9,-1,1}}, {{18,0,7,0,10,-1,1},{18,0,7,0,9,-1,1},{18,0,7,0,9,-1,1},{18,0,7,0,9,-1,1},{18,0,7,0,9,-1,1},{18,0,7,0,9,-1,1},{18,0,7,0,9,-1,1},{18,0,7,0,9,-1,1},{18,0,7,0,9,-1,1},{18,0,7,0,9,-1,1},{18,0,7,0,9,-1,1},{18,0,7,0,9,-1,1},{18,0,7,0,9,-1,1},{18,0,7,0,9,-1,1},{18,0,7,0,9,-1,1},{18,0,7,0,9,-1,1},{18,0,7,0,9,-1,1},{18,0,7,0,9,-1,1},{18,0,7,0,9,-1,1},{18,0,7,0,9,-1,1},{18,0,7,0,9,-1,1},{18,0,7,0,9,-1,1},{18,0,7,0,9,-1,1},{18,0,7,0,9,-1,1},{18,0,7,0,9,-1,1},{18,0,7,0,9,-1,1},{18,0,7,0,9,-1,1},{18,0,7,0,9,-1,1},{18,0,7,0,9,-1,1},{18,0,7,0,9,-1,1},{18,0,7,0,9,-1,1},{61,0,2,0,12,-1,1}}, {{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{18,0,7,0,9,-1,1},{18,0,7,0,9,-1,1},{18,0,7,0,9,-1,1},{18,0,7,0,9,-1,1},{18,0,7,0,9,-1,1},{18,0,7,0,9,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{18,0,7,0,9,-1,1},{18,0,7,0,9,-1,1},{18,0,7,0,9,-1,1},{18,0,7,0,9,-1,1},{18,0,7,0,9,-1,1},{18,0,7,0,9,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{18,0,7,0,9,-1,1},{18,0,7,0,9,-1,1},{18,0,7,0,9,-1,1},{18,0,7,0,9,-1,1},{18,0,7,0,9,-1,1},{18,0,7,0,9,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{18,0,7,0,9,-1,1},{18,0,7,0,9,-1,1},{18,0,7,0,9,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1}}, {{0,0,23,4,9,-1,0},{0,0,23,4,9,-1,0},{0,0,25,10,9,-1,0},{0,0,24,10,9,-1,3},{0,0,26,10,9,-1,0},{0,0,23,4,9,-1,0},{0,0,23,4,9,-1,0},{61,0,2,0,12,-1,0},{0,0,26,10,9,-1,1},{0,0,25,10,9,-1,1},{0,0,25,10,9,-1,1},{0,0,25,10,9,-1,1},{0,0,25,10,9,-1,1},{0,0,26,10,9,-1,1},{0,0,26,10,9,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,0},{61,0,2,0,12,-1,0},{61,0,2,0,12,-1,0},{61,0,2,0,12,-1,0},{61,0,2,0,12,-1,0},{61,0,2,0,12,-1,0},{61,0,2,0,12,-1,0},{61,0,2,0,12,-1,0},{61,0,2,0,12,-1,0},{0,0,1,10,8,-1,1},{0,0,1,10,8,-1,1},{0,0,1,10,8,-1,1},{0,0,26,10,8,-1,0},{0,0,26,10,8,-1,0},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1}}, {{51,0,7,0,7,-1,1},{51,0,7,0,7,-1,1},{51,0,7,0,7,-1,1},{51,0,7,0,7,-1,1},{51,0,7,0,7,-1,1},{51,0,7,0,7,-1,1},{51,0,7,0,7,-1,1},{51,0,7,0,7,-1,1},{51,0,7,0,7,-1,1},{51,0,7,0,7,-1,1},{51,0,7,0,7,-1,1},{51,0,7,0,7,-1,1},{61,0,2,0,12,-1,1},{51,0,7,0,7,-1,1},{51,0,7,0,7,-1,1},{51,0,7,0,7,-1,1},{51,0,7,0,7,-1,1},{51,0,7,0,7,-1,1},{51,0,7,0,7,-1,1},{51,0,7,0,7,-1,1},{51,0,7,0,7,-1,1},{51,0,7,0,7,-1,1},{51,0,7,0,7,-1,1},{51,0,7,0,7,-1,1},{51,0,7,0,7,-1,1},{51,0,7,0,7,-1,1},{51,0,7,0,7,-1,1},{51,0,7,0,7,-1,1},{51,0,7,0,7,-1,1},{51,0,7,0,7,-1,1},{51,0,7,0,7,-1,1},{51,0,7,0,7,-1,1}}, {{51,0,7,0,7,-1,1},{51,0,7,0,7,-1,1},{51,0,7,0,7,-1,1},{51,0,7,0,7,-1,1},{51,0,7,0,7,-1,1},{51,0,7,0,7,-1,1},{51,0,7,0,7,-1,1},{61,0,2,0,12,-1,1},{51,0,7,0,7,-1,1},{51,0,7,0,7,-1,1},{51,0,7,0,7,-1,1},{51,0,7,0,7,-1,1},{51,0,7,0,7,-1,1},{51,0,7,0,7,-1,1},{51,0,7,0,7,-1,1},{51,0,7,0,7,-1,1},{51,0,7,0,7,-1,1},{51,0,7,0,7,-1,1},{51,0,7,0,7,-1,1},{51,0,7,0,7,-1,1},{51,0,7,0,7,-1,1},{51,0,7,0,7,-1,1},{51,0,7,0,7,-1,1},{51,0,7,0,7,-1,1},{51,0,7,0,7,-1,1},{51,0,7,0,7,-1,1},{51,0,7,0,7,-1,1},{61,0,2,0,12,-1,1},{51,0,7,0,7,-1,1},{51,0,7,0,7,-1,1},{61,0,2,0,12,-1,1},{51,0,7,0,7,-1,1}}, {{51,0,7,0,7,-1,1},{51,0,7,0,7,-1,1},{51,0,7,0,7,-1,1},{51,0,7,0,7,-1,1},{51,0,7,0,7,-1,1},{51,0,7,0,7,-1,1},{51,0,7,0,7,-1,1},{51,0,7,0,7,-1,1},{51,0,7,0,7,-1,1},{51,0,7,0,7,-1,1},{51,0,7,0,7,-1,1},{51,0,7,0,7,-1,1},{51,0,7,0,7,-1,1},{51,0,7,0,7,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1},{51,0,7,0,7,-1,1},{51,0,7,0,7,-1,1},{51,0,7,0,7,-1,1},{51,0,7,0,7,-1,1},{51,0,7,0,7,-1,1},{51,0,7,0,7,-1,1},{51,0,7,0,7,-1,1},{51,0,7,0,7,-1,1},{51,0,7,0,7,-1,1},{51,0,7,0,7,-1,1},{51,0,7,0,7,-1,1},{51,0,7,0,7,-1,1},{51,0,7,0,7,-1,1},{51,0,7,0,7,-1,1},{61,0,2,0,12,-1,1},{61,0,2,0,12,-1,1}}, {{51,0,7,0,7,-1,1},{51,0,7,0,7,-1,1},{51,0,7,0,7,-1,1},{51,0,7,0,7,-1,1},{51,0,7,0,7,-1,1},{51,0,7,0,7,-1,1},{51,0,7,0,7,-1,1},{51,0,7,0,7,-1,1},{51,0,7,0,7,-1,1},{51,0,7,0,7,-1,1},{51,0,7,0,7,-1,1},{51,0,7,0,7,-1,1},{51,0,7,0,7,-1,1},{51,0,7,0,7,-1,1},{51,0,7,0,7,-1,1},{51,0,7,0,7,-1,1},{51,0,7,0,7,-1,1},{51,0,7,0,7,-1,1},{51,0,7,0,7,-1,1},{51,0,7,0,7,-1,1},{51,0,7,0,7,-1,1},{51,0,7,0,7,-1,1},{51,0,7,0,7,-1,1},{51,0,7,0,7,-1,1},{51,0,7,0,7,-1,1},{51,0,7,0,7,-1,1},{51,0,7,0,7,-1,1},{51,0,7,0,7,-1,1},{51,0,7,0,7,-1,1},{51,0,7,0,7,-1,1},{51,0,7,0,7,-1,1},{51,0,7,0,7,-1,1}},
--- a/intl/unicharutil/util/nsUnicodeScriptCodes.h +++ b/intl/unicharutil/util/nsUnicodeScriptCodes.h @@ -6,17 +6,17 @@ /* * Derived from the Unicode Character Database by genUnicodePropertyData.pl * * For Unicode terms of use, see http://www.unicode.org/terms_of_use.html */ /* - * Created on Thu Sep 3 14:42:28 2015 from UCD data files with version info: + * Created on Tue Nov 17 07:34:16 2015 from UCD data files with version info: * # Date: 2015-06-16, 20:24:00 GMT [KW] # # Unicode Character Database # Copyright (c) 1991-2015 Unicode, Inc. # For terms of use, see http://www.unicode.org/terms_of_use.html # @@ -33,16 +33,19 @@ Standard. # Scripts-8.0.0.txt # Date: 2015-03-11, 22:29:42 GMT [MD] # BidiMirroring-8.0.0.txt # Date: 2015-01-20, 18:30:00 GMT [KW, LI] +# BidiBrackets-8.0.0.txt +# Date: 2015-01-20, 19:00:00 GMT [AG, LI, KW] + # HangulSyllableType-8.0.0.txt # Date: 2014-12-16, 23:07:45 GMT [MD] # File: xidmodifications.txt # Version: 8.0.0 # Generated: 2015-05-17, 03:09:04 GMT # @@ -67,17 +70,17 @@ struct nsCharProps1 { unsigned char mHangulType:3; unsigned char mCombiningClass:8; }; struct nsCharProps2 { unsigned char mScriptCode:8; - unsigned char mUnused:3; + unsigned char mPairedBracketType:3; // only 2 bits actually needed unsigned char mCategory:5; unsigned char mBidiCategory:5; unsigned char mXidmod:4; signed char mNumericValue:5; unsigned char mVertOrient:2; };
--- a/js/src/builtin/ModuleObject.h +++ b/js/src/builtin/ModuleObject.h @@ -172,16 +172,17 @@ class ModuleNamespaceObject : public Pro bool get(JSContext* cx, HandleObject proxy, HandleValue receiver, HandleId id, MutableHandleValue vp) const override; bool set(JSContext* cx, HandleObject proxy, HandleId id, HandleValue v, HandleValue receiver, ObjectOpResult& result) const override; static const char family; }; + public: static const ProxyHandler proxyHandler; }; typedef Rooted<ModuleNamespaceObject*> RootedModuleNamespaceObject; typedef Handle<ModuleNamespaceObject*> HandleModuleNamespaceObject; struct FunctionDeclaration { @@ -311,9 +312,16 @@ class MOZ_STACK_CLASS ModuleBuilder }; JSObject* InitModuleClass(JSContext* cx, HandleObject obj); JSObject* InitImportEntryClass(JSContext* cx, HandleObject obj); JSObject* InitExportEntryClass(JSContext* cx, HandleObject obj); } // namespace js +template<> +inline bool +JSObject::is<js::ModuleNamespaceObject>() const +{ + return js::IsDerivedProxyObject(this, &js::ModuleNamespaceObject::proxyHandler); +} + #endif /* builtin_ModuleObject_h */
new file mode 100644 --- /dev/null +++ b/js/src/jit-test/lib/dummyModuleResolveHook.js @@ -0,0 +1,14 @@ +/* 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/. */ + +// A dummy implementation of the module resolve hook used by module tests. This +// implements the bare minimum necessary to allow modules to refer to each +// other. + +let moduleRepo = {}; +setModuleResolveHook(function(module, specifier) { + if (specifier in moduleRepo) + return moduleRepo[specifier]; + throw "Module '" + specifier + "' not found"; +});
--- a/js/src/jit-test/tests/modules/ambiguous-star-export.js +++ b/js/src/jit-test/tests/modules/ambiguous-star-export.js @@ -1,38 +1,31 @@ // Test ambigious export * statements. "use strict"; load(libdir + "asserts.js"); +load(libdir + "dummyModuleResolveHook.js"); function checkModuleEval(source, result) { let m = parseModule(source); m.declarationInstantiation(); assertEq(m.evaluation(), result); } function checkModuleSyntaxError(source) { let m = parseModule(source); assertThrowsInstanceOf(() => m.declarationInstantiation(), SyntaxError); } -let moduleRepo = new Map(); -setModuleResolveHook(function(module, specifier) { - if (specifier in moduleRepo) - return moduleRepo[specifier]; - throw "Module " + specifier + " not found"; -}); - let a = moduleRepo['a'] = parseModule("export var a = 1; export var b = 2;"); let b = moduleRepo['b'] = parseModule("export var b = 3; export var c = 4;"); let c = moduleRepo['c'] = parseModule("export * from 'a'; export * from 'b';"); -let ms = [a, b, c]; -ms.map((m) => m.declarationInstantiation()); -ms.map((m) => m.evaluation(), moduleRepo.values()); +c.declarationInstantiation(); +c.evaluation(); // Check importing/exporting non-ambiguous name works. checkModuleEval("import { a } from 'c'; a;", 1); checkModuleEval("export { a } from 'c';", undefined); // Check importing/exporting ambiguous name is a syntax error. checkModuleSyntaxError("import { b } from 'c';"); checkModuleSyntaxError("export { b } from 'c';");
--- a/js/src/jit-test/tests/modules/bug1210391.js +++ b/js/src/jit-test/tests/modules/bug1210391.js @@ -1,11 +1,8 @@ -let moduleRepo = new Map(); -setModuleResolveHook(function(module, specifier) { - return moduleRepo[specifier]; -}); +load(libdir + "dummyModuleResolveHook.js"); let a = moduleRepo['a'] = parseModule("export var a = 1; export var b = 2;"); let b = moduleRepo['b'] = parseModule("export var b = 3; export var c = 4;"); let c = moduleRepo['c'] = parseModule("export * from 'a'; export * from 'b';"); let d = moduleRepo['d'] = parseModule("import { a } from 'c'; a;"); d.declarationInstantiation(); d.evaluation();
--- a/js/src/jit-test/tests/modules/debugger-frames.js +++ b/js/src/jit-test/tests/modules/debugger-frames.js @@ -52,21 +52,21 @@ dbg.onDebuggerStatement = function (fram // followed by the global. assertEq(env.parent.type, 'declarative'); assertEq(env.parent.parent.type, 'object'); assertEq(env.parent.parent.parent, null); }; f = g2.eval( ` - let moduleRepo = new Map(); + let moduleRepo = {}; setModuleResolveHook(function(module, specifier) { if (specifier in moduleRepo) return moduleRepo[specifier]; - throw "Module " + specifier + " not found"; + throw "Module '" + specifier + "' not found"; }); // Set up a module to import from. a = moduleRepo['a'] = parseModule( \` export var a = 1; export let b = 2; export const c = 3;
--- a/js/src/jit-test/tests/modules/import-namespace.js +++ b/js/src/jit-test/tests/modules/import-namespace.js @@ -1,21 +1,15 @@ // Test importing module namespaces "use strict"; load(libdir + "asserts.js"); load(libdir + "iteration.js"); - -let moduleRepo = new Map(); -setModuleResolveHook(function(module, specifier) { - if (specifier in moduleRepo) - return moduleRepo[specifier]; - throw "Module " + specifier + " not found"; -}); +load(libdir + "dummyModuleResolveHook.js"); function parseAndEvaluate(source) { let m = parseModule(source); m.declarationInstantiation(); return m.evaluation(); } function testHasNames(names, expected) {
--- a/js/src/jit-test/tests/modules/many-exports.js +++ b/js/src/jit-test/tests/modules/many-exports.js @@ -1,19 +1,14 @@ // Test many exports. +load(libdir + "dummyModuleResolveHook.js"); + const count = 1024; -let moduleRepo = {}; -setModuleResolveHook(function(module, specifier) { - if (specifier in moduleRepo) - return moduleRepo[specifier]; - throw "Module " + specifier + " not found"; -}); - let s = ""; for (let i = 0; i < count; i++) s += "export let e" + i + " = " + (i * i) + ";\n"; let a = moduleRepo['a'] = parseModule(s); let b = moduleRepo['b'] = parseModule("import * as ns from 'a'"); b.declarationInstantiation();
--- a/js/src/jit-test/tests/modules/many-imports.js +++ b/js/src/jit-test/tests/modules/many-imports.js @@ -1,19 +1,14 @@ // Test importing an import many times. +load(libdir + "dummyModuleResolveHook.js"); + const count = 1024; -let moduleRepo = {}; -setModuleResolveHook(function(module, specifier) { - if (specifier in moduleRepo) - return moduleRepo[specifier]; - throw "Module " + specifier + " not found"; -}); - let a = moduleRepo['a'] = parseModule("export let a = 1;"); let s = ""; for (let i = 0; i < count; i++) { s += "import { a as i" + i + " } from 'a';\n"; s += "assertEq(i" + i + ", 1);\n"; } let b = moduleRepo['b'] = parseModule(s);
--- a/js/src/jit-test/tests/modules/many-namespace-imports.js +++ b/js/src/jit-test/tests/modules/many-namespace-imports.js @@ -1,19 +1,14 @@ // Test importing a namespace many times. +load(libdir + "dummyModuleResolveHook.js"); + const count = 1024; -let moduleRepo = {}; -setModuleResolveHook(function(module, specifier) { - if (specifier in moduleRepo) - return moduleRepo[specifier]; - throw "Module " + specifier + " not found"; -}); - let a = moduleRepo['a'] = parseModule("export let a = 1;"); let s = ""; for (let i = 0; i < count; i++) { s += "import * as ns" + i + " from 'a';\n"; s += "assertEq(ns" + i + ".a, 1);\n"; } let b = moduleRepo['b'] = parseModule(s);
--- a/js/src/jit-test/tests/modules/module-declaration-instantiation.js +++ b/js/src/jit-test/tests/modules/module-declaration-instantiation.js @@ -1,30 +1,25 @@ // Exercise ModuleDeclarationInstantiation() operation. +load(libdir + "dummyModuleResolveHook.js"); + function testModuleEnvironment(module, expected) { var actual = getModuleEnvironmentNames(module).sort(); assertEq(actual.length, expected.length); for (var i = 0; i < actual.length; i++) { assertEq(actual[i], expected[i]); } } // Check the environment of an empty module. let m = parseModule(""); m.declarationInstantiation(); testModuleEnvironment(m, []); -let moduleRepo = new Map(); -setModuleResolveHook(function(module, specifier) { - if (specifier in moduleRepo) - return moduleRepo[specifier]; - throw "Module " + specifier + " not found"; -}); - let a = moduleRepo['a'] = parseModule("var x = 1; export { x };"); let b = moduleRepo['b'] = parseModule("import { x as y } from 'a';"); a.declarationInstantiation(); b.declarationInstantiation(); testModuleEnvironment(a, ['x']); testModuleEnvironment(b, ['y']);
--- a/js/src/jit-test/tests/modules/module-evaluation.js +++ b/js/src/jit-test/tests/modules/module-evaluation.js @@ -1,18 +1,12 @@ // Exercise ModuleEvaluation() concrete method. load(libdir + "asserts.js"); - -let moduleRepo = new Map(); -setModuleResolveHook(function(module, specifier) { - if (specifier in moduleRepo) - return moduleRepo[specifier]; - throw "Module " + specifier + " not found"; -}); +load(libdir + "dummyModuleResolveHook.js"); function parseAndEvaluate(source) { let m = parseModule(source); m.declarationInstantiation(); return m.evaluation(); } // Check the evaluation of an empty module succeeds.
--- a/js/src/jsprototypes.h +++ b/js/src/jsprototypes.h @@ -83,17 +83,17 @@ real(Uint8Array, 23, InitViaClassSpec, TYPED_ARRAY_CLASP(Uint8)) \ real(Int16Array, 24, InitViaClassSpec, TYPED_ARRAY_CLASP(Int16)) \ real(Uint16Array, 25, InitViaClassSpec, TYPED_ARRAY_CLASP(Uint16)) \ real(Int32Array, 26, InitViaClassSpec, TYPED_ARRAY_CLASP(Int32)) \ real(Uint32Array, 27, InitViaClassSpec, TYPED_ARRAY_CLASP(Uint32)) \ real(Float32Array, 28, InitViaClassSpec, TYPED_ARRAY_CLASP(Float32)) \ real(Float64Array, 29, InitViaClassSpec, TYPED_ARRAY_CLASP(Float64)) \ real(Uint8ClampedArray, 30, InitViaClassSpec, TYPED_ARRAY_CLASP(Uint8Clamped)) \ - real(Proxy, 31, InitProxyClass, OCLASP(Proxy)) \ + real(Proxy, 31, InitProxyClass, js::ProxyClassPtr) \ real(WeakMap, 32, InitWeakMapClass, OCLASP(WeakMap)) \ real(Map, 33, InitMapClass, OCLASP(Map)) \ real(Set, 34, InitSetClass, OCLASP(Set)) \ real(DataView, 35, InitDataViewClass, OCLASP(DataView)) \ real(Symbol, 36, InitSymbolClass, OCLASP(Symbol)) \ IF_SAB(real,imaginary)(SharedArrayBuffer, 37, InitSharedArrayBufferClass, &js::SharedArrayBufferObject::protoClass) \ IF_INTL(real,imaginary) (Intl, 38, InitIntlClass, CLASP(Intl)) \ IF_BDATA(real,imaginary)(TypedObject, 39, InitTypedObjectModuleObject, OCLASP(TypedObjectModule)) \
--- a/js/src/proxy/DeadObjectProxy.cpp +++ b/js/src/proxy/DeadObjectProxy.cpp @@ -146,15 +146,13 @@ DeadObjectProxy::regexp_toShared(JSConte { ReportDead(cx); return false; } const char DeadObjectProxy::family = 0; const DeadObjectProxy DeadObjectProxy::singleton; - bool js::IsDeadProxyObject(JSObject* obj) { - return obj->is<ProxyObject>() && - obj->as<ProxyObject>().handler() == &DeadObjectProxy::singleton; + return IsDerivedProxyObject(obj, &DeadObjectProxy::singleton); }
--- a/js/src/proxy/Proxy.cpp +++ b/js/src/proxy/Proxy.cpp @@ -712,20 +712,20 @@ js::proxy_GetElements(JSContext* cx, Han } JSString* js::proxy_FunToString(JSContext* cx, HandleObject proxy, unsigned indent) { return Proxy::fun_toString(cx, proxy, indent); } -const Class js::ProxyObject::class_ = +const Class js::ProxyObject::proxyClass = PROXY_CLASS_DEF("Proxy", JSCLASS_HAS_CACHED_PROTO(JSProto_Proxy)); -const Class* const js::ProxyClassPtr = &js::ProxyObject::class_; +const Class* const js::ProxyClassPtr = &js::ProxyObject::proxyClass; JS_FRIEND_API(JSObject*) js::NewProxyObject(JSContext* cx, const BaseProxyHandler* handler, HandleValue priv, JSObject* proto_, const ProxyOptions& options) { if (options.lazyProto()) { MOZ_ASSERT(!proto_); proto_ = TaggedProto::LazyProto; @@ -733,17 +733,17 @@ js::NewProxyObject(JSContext* cx, const return ProxyObject::New(cx, handler, priv, TaggedProto(proto_), options); } void ProxyObject::renew(JSContext* cx, const BaseProxyHandler* handler, Value priv) { MOZ_ASSERT_IF(IsCrossCompartmentWrapper(this), IsDeadProxyObject(this)); - MOZ_ASSERT(getClass() == &ProxyObject::class_); + MOZ_ASSERT(getClass() == &ProxyObject::proxyClass); MOZ_ASSERT(!IsWindowProxy(this)); MOZ_ASSERT(hasLazyPrototype()); setHandler(handler); setCrossCompartmentPrivate(priv); setExtra(0, UndefinedValue()); setExtra(1, UndefinedValue()); }
--- a/js/src/vm/ProxyObject.h +++ b/js/src/vm/ProxyObject.h @@ -99,27 +99,35 @@ class ProxyObject : public JSObject static unsigned grayLinkExtraSlot(JSObject* obj); void renew(JSContext* cx, const BaseProxyHandler* handler, Value priv); static void trace(JSTracer* trc, JSObject* obj); void nuke(const BaseProxyHandler* handler); - static const Class class_; + // There is no class_ member to force specialization of JSObject::is<T>(). + // The implementation in JSObject is incorrect for proxies since it doesn't + // take account of the handler type. + static const Class proxyClass; }; +bool IsDerivedProxyObject(const JSObject* obj, const js::BaseProxyHandler* handler); + } // namespace js -// Note: the following |JSObject::is<T>| methods are implemented in terms of -// the Is*Proxy() friend API functions to ensure the implementations are tied -// together. The exception is |JSObject::is<js::OuterWindowProxyObject>() -// const|, which uses the standard template definition, because there is no -// IsOuterWindowProxy() function in the friend API. - template<> inline bool JSObject::is<js::ProxyObject>() const { + // Note: this method is implemented in terms of the IsProxy() friend API + // functions to ensure the implementations are tied together. + // Note 2: this specialization isn't used for subclasses of ProxyObject + // which must supply their own implementation. return js::IsProxy(const_cast<JSObject*>(this)); } +inline bool +js::IsDerivedProxyObject(const JSObject* obj, const js::BaseProxyHandler* handler) { + return obj->is<js::ProxyObject>() && obj->as<js::ProxyObject>().handler() == handler; +} + #endif /* vm_ProxyObject_h */
--- a/js/src/vm/ScopeObject.cpp +++ b/js/src/vm/ScopeObject.cpp @@ -2239,16 +2239,23 @@ class DebugScopeProxy : public BaseProxy ObjectOpResult& result) const override { return result.fail(JSMSG_CANT_DELETE); } }; } /* anonymous namespace */ +template<> +bool +JSObject::is<js::DebugScopeObject>() const +{ + return IsDerivedProxyObject(this, &DebugScopeProxy::singleton); +} + const char DebugScopeProxy::family = 0; const DebugScopeProxy DebugScopeProxy::singleton; /* static */ DebugScopeObject* DebugScopeObject::create(JSContext* cx, ScopeObject& scope, HandleObject enclosing) { MOZ_ASSERT(scope.compartment() == cx->compartment()); MOZ_ASSERT(!enclosing->is<ScopeObject>()); @@ -2328,23 +2335,16 @@ DebugScopeObject::isOptimizedOut() const return !s.as<CallObject>().isForEval() && !s.as<CallObject>().callee().needsCallObject() && !maybeSnapshot(); } return false; } -bool -js::IsDebugScopeSlow(ProxyObject* proxy) -{ - MOZ_ASSERT(proxy->hasClass(&ProxyObject::class_)); - return proxy->handler() == &DebugScopeProxy::singleton; -} - /*****************************************************************************/ DebugScopes::DebugScopes(JSContext* cx) : proxiedScopes(cx), missingScopes(cx->runtime()), liveScopes(cx->runtime()) {}
--- a/js/src/vm/ScopeObject.h +++ b/js/src/vm/ScopeObject.h @@ -1260,19 +1260,16 @@ class DebugScopes static void onPopCall(AbstractFramePtr frame, JSContext* cx); static void onPopBlock(JSContext* cx, const ScopeIter& si); static void onPopBlock(JSContext* cx, AbstractFramePtr frame, jsbytecode* pc); static void onPopWith(AbstractFramePtr frame); static void onPopStrictEvalScope(AbstractFramePtr frame); static void onCompartmentUnsetIsDebuggee(JSCompartment* c); }; -extern bool -IsDebugScopeSlow(ProxyObject* proxy); - } /* namespace js */ template<> inline bool JSObject::is<js::NestedScopeObject>() const { return is<js::BlockObject>() || is<js::StaticWithObject>() || @@ -1294,23 +1291,18 @@ JSObject::is<js::ScopeObject>() const return is<js::LexicalScopeBase>() || is<js::DeclEnvObject>() || is<js::NestedScopeObject>() || is<js::RuntimeLexicalErrorObject>() || is<js::NonSyntacticVariablesObject>(); } template<> -inline bool -JSObject::is<js::DebugScopeObject>() const -{ - // Note: don't use is<ProxyObject>() here -- it also matches subclasses! - return hasClass(&js::ProxyObject::class_) && - IsDebugScopeSlow(&const_cast<JSObject*>(this)->as<js::ProxyObject>()); -} +bool +JSObject::is<js::DebugScopeObject>() const; template<> inline bool JSObject::is<js::ClonedBlockObject>() const { return is<js::BlockObject>() && !!getProto(); }
--- a/layout/base/nsBidi.cpp +++ b/layout/base/nsBidi.cpp @@ -36,28 +36,41 @@ enum { RLO = eCharType_RightToLeftOverride, PDF = eCharType_PopDirectionalFormat, NSM = eCharType_DirNonSpacingMark, BN = eCharType_BoundaryNeutral, LRI = eCharType_LeftToRightIsolate, RLI = eCharType_RightToLeftIsolate, FSI = eCharType_FirstStrongIsolate, PDI = eCharType_PopDirectionalIsolate, + ENL, /* EN after W7 */ /* 23 */ + ENR, /* EN not subject to W7 */ /* 24 */ dirPropCount }; +#define IS_STRONG_TYPE(dirProp) ((dirProp) <= R || (dirProp) == AL) + /* to avoid some conditional statements, use tiny constant arrays */ static Flags flagLR[2]={ DIRPROP_FLAG(L), DIRPROP_FLAG(R) }; static Flags flagE[2]={ DIRPROP_FLAG(LRE), DIRPROP_FLAG(RLE) }; static Flags flagO[2]={ DIRPROP_FLAG(LRO), DIRPROP_FLAG(RLO) }; #define DIRPROP_FLAG_LR(level) flagLR[(level)&1] #define DIRPROP_FLAG_E(level) flagE[(level)&1] #define DIRPROP_FLAG_O(level) flagO[(level)&1] +#define NO_OVERRIDE(level) ((level)&~NSBIDI_LEVEL_OVERRIDE) + +static inline uint8_t +DirFromStrong(uint8_t aDirProp) +{ + MOZ_ASSERT(IS_STRONG_TYPE(aDirProp)); + return aDirProp == L ? L : R; +} + /* * General implementation notes: * * Throughout the implementation, there are comments like (W2) that refer to * rules of the Bidi algorithm in its version 5, in this example to the second * rule of the resolution of weak types. * * For handling surrogate pairs, where two UChar's form one "abstract" (or UTF-32) @@ -133,19 +146,16 @@ static Flags flagO[2]={ DIRPROP_FLAG(LRO * the flags variable. * * If there are no White Space types in the paragraph, then * (L1) is not necessary in AdjustWSLevels(). */ nsBidi::nsBidi() { Init(); - - mMayAllocateText=true; - mMayAllocateRuns=true; } nsBidi::~nsBidi() { Free(); } void nsBidi::Init() @@ -169,57 +179,49 @@ void nsBidi::Init() mLevels=nullptr; mRuns=nullptr; mIsolates=nullptr; mDirPropsMemory=nullptr; mLevelsMemory=nullptr; mRunsMemory=nullptr; mIsolatesMemory=nullptr; - - mMayAllocateText=false; - mMayAllocateRuns=false; } /* - * We are allowed to allocate memory if aMemory==nullptr or - * aMayAllocate==true for each array that we need. + * We are allowed to allocate memory if aMemory==nullptr + * for each array that we need. * We also try to grow and shrink memory as needed if we * allocate it. * * Assume aSizeNeeded>0. * If *aMemory!=nullptr, then assume *aSize>0. * * ### this realloc() may unnecessarily copy the old data, * which we know we don't need any more; * is this the best way to do this?? */ -bool nsBidi::GetMemory(void **aMemory, size_t *aSize, bool aMayAllocate, size_t aSizeNeeded) +/*static*/ +bool +nsBidi::GetMemory(void **aMemory, size_t *aSize, size_t aSizeNeeded) { /* check for existing memory */ if(*aMemory==nullptr) { /* we need to allocate memory */ - if(!aMayAllocate) { - return false; + *aMemory=malloc(aSizeNeeded); + if (*aMemory!=nullptr) { + *aSize=aSizeNeeded; + return true; } else { - *aMemory=malloc(aSizeNeeded); - if (*aMemory!=nullptr) { - *aSize=aSizeNeeded; - return true; - } else { - *aSize=0; - return false; - } + *aSize=0; + return false; } } else { /* there is some memory, is it enough or too much? */ - if(aSizeNeeded>*aSize && !aMayAllocate) { - /* not enough memory, and we must not allocate */ - return false; - } else if(aSizeNeeded!=*aSize && aMayAllocate) { + if(aSizeNeeded!=*aSize) { /* we may try to grow or shrink */ void *memory=realloc(*aMemory, aSizeNeeded); if(memory!=nullptr) { *aMemory=memory; *aSize=aSizeNeeded; return true; } else { @@ -243,17 +245,17 @@ void nsBidi::Free() mRunsMemory = nullptr; free(mIsolatesMemory); mIsolatesMemory = nullptr; } /* SetPara ------------------------------------------------------------ */ nsresult nsBidi::SetPara(const char16_t *aText, int32_t aLength, - nsBidiLevel aParaLevel, nsBidiLevel *aEmbeddingLevels) + nsBidiLevel aParaLevel) { nsBidiDirection direction; /* check the argument values */ if(aText==nullptr || ((NSBIDI_MAX_EXPLICIT_LEVEL<aParaLevel) && !IS_DEFAULT_LEVEL(aParaLevel)) || aLength<-1 ) { @@ -297,42 +299,32 @@ nsresult nsBidi::SetPara(const char16_t */ if(GETDIRPROPSMEMORY(aLength)) { mDirProps=mDirPropsMemory; GetDirProps(aText); } else { return NS_ERROR_OUT_OF_MEMORY; } - /* are explicit levels specified? */ - if(aEmbeddingLevels==nullptr) { - /* no: determine explicit levels according to the (Xn) rules */\ - if(GETLEVELSMEMORY(aLength)) { - mLevels=mLevelsMemory; - ResolveExplicitLevels(&direction); - } else { - return NS_ERROR_OUT_OF_MEMORY; - } + /* determine explicit levels according to the (Xn) rules */ + if(GETLEVELSMEMORY(aLength)) { + mLevels=mLevelsMemory; + ResolveExplicitLevels(&direction, aText); } else { - /* set BN for all explicit codes, check that all levels are aParaLevel..NSBIDI_MAX_EXPLICIT_LEVEL */ - mLevels=aEmbeddingLevels; - nsresult rv = CheckExplicitLevels(&direction); - if(NS_FAILED(rv)) { - return rv; - } + return NS_ERROR_OUT_OF_MEMORY; } /* allocate isolate memory */ if (mIsolateCount <= SIMPLE_ISOLATES_SIZE) { mIsolates = mSimpleIsolates; } else { if (mIsolateCount * sizeof(Isolate) <= mIsolatesSize) { mIsolates = mIsolatesMemory; } else { - if (GETINITIALISOLATESMEMORY(mIsolateCount)) { + if (GETISOLATESMEMORY(mIsolateCount)) { mIsolates = mIsolatesMemory; } else { return NS_ERROR_OUT_OF_MEMORY; } } } mIsolateCount = -1; /* current isolates stack entry == none */ @@ -363,17 +355,17 @@ nsresult nsBidi::SetPara(const char16_t * then we can treat the entire paragraph as one run. * Otherwise, we need to perform the following rules on runs of * the text with the same embedding levels. (X10) * "Significant" explicit level codes are ones that actually * affect non-BN characters. * Examples for "insignificant" ones are empty embeddings * LRE-PDF, LRE-RLE-PDF-PDF, etc. */ - if(aEmbeddingLevels==nullptr && !(mFlags&DIRPROP_FLAG_MULTI_RUNS)) { + if(!(mFlags&DIRPROP_FLAG_MULTI_RUNS)) { ResolveImplicitLevels(0, aLength, GET_LR_FROM_LEVEL(mParaLevel), GET_LR_FROM_LEVEL(mParaLevel)); } else { /* sor, eor: start and end types of same-level-run */ nsBidiLevel *levels=mLevels; int32_t start, limit=0; nsBidiLevel level, nextLevel; @@ -580,16 +572,344 @@ void nsBidi::GetDirProps(const char16_t stackLast--; } flags|=DIRPROP_FLAG_LR(mParaLevel); mFlags = flags; } +/* Functions for handling paired brackets ----------------------------------- */ + +/* In the mIsoRuns array, the first entry is used for text outside of any + isolate sequence. Higher entries are used for each more deeply nested + isolate sequence. + mIsoRunLast is the index of the last used entry. + The mOpenings array is used to note the data of opening brackets not yet + matched by a closing bracket, or matched but still susceptible to change + level. + Each isoRun entry contains the index of the first and + one-after-last openings entries for pending opening brackets it + contains. The next mOpenings entry to use is the one-after-last of the + most deeply nested isoRun entry. + mIsoRuns entries also contain their current embedding level and the bidi + class of the last-encountered strong character, since these will be needed + to resolve the level of paired brackets. */ + +nsBidi::BracketData::BracketData(const nsBidi *aBidi) +{ + mIsoRunLast = 0; + mIsoRuns[0].start = 0; + mIsoRuns[0].limit = 0; + mIsoRuns[0].level = aBidi->mParaLevel; + mIsoRuns[0].lastStrong = mIsoRuns[0].lastBase = mIsoRuns[0].contextDir = + GET_LR_FROM_LEVEL(aBidi->mParaLevel); + mIsoRuns[0].contextPos = 0; + mOpenings = mSimpleOpenings; + mOpeningsCount = SIMPLE_OPENINGS_COUNT; + mOpeningsMemory = nullptr; +} + +nsBidi::BracketData::~BracketData() +{ + free(mOpeningsMemory); +} + +/* LRE, LRO, RLE, RLO, PDF */ +void +nsBidi::BracketData::ProcessBoundary(int32_t aLastDirControlCharPos, + nsBidiLevel aContextLevel, + nsBidiLevel aEmbeddingLevel, + const DirProp* aDirProps) +{ + IsoRun& lastIsoRun = mIsoRuns[mIsoRunLast]; + if (DIRPROP_FLAG(aDirProps[aLastDirControlCharPos]) & MASK_ISO) { /* after an isolate */ + return; + } + if (NO_OVERRIDE(aEmbeddingLevel) > NO_OVERRIDE(aContextLevel)) { /* not PDF */ + aContextLevel = aEmbeddingLevel; + } + lastIsoRun.limit = lastIsoRun.start; + lastIsoRun.level = aEmbeddingLevel; + lastIsoRun.lastStrong = lastIsoRun.lastBase = lastIsoRun.contextDir = + GET_LR_FROM_LEVEL(aContextLevel); + lastIsoRun.contextPos = aLastDirControlCharPos; +} + +/* LRI or RLI */ +void +nsBidi::BracketData::ProcessLRI_RLI(nsBidiLevel aLevel) +{ + MOZ_ASSERT(mIsoRunLast <= NSBIDI_MAX_EXPLICIT_LEVEL); + IsoRun& lastIsoRun = mIsoRuns[mIsoRunLast]; + lastIsoRun.lastBase = O_N; + IsoRun& currIsoRun = mIsoRuns[++mIsoRunLast]; + currIsoRun.start = currIsoRun.limit = lastIsoRun.limit; + currIsoRun.level = aLevel; + currIsoRun.lastStrong = currIsoRun.lastBase = currIsoRun.contextDir = + GET_LR_FROM_LEVEL(aLevel); + currIsoRun.contextPos = 0; +} + +/* PDI */ +void +nsBidi::BracketData::ProcessPDI() +{ + mIsoRuns[mIsoRunLast].lastBase = O_N; +} + +/* newly found opening bracket: create an openings entry */ +bool /* return true if success */ +nsBidi::BracketData::AddOpening(char16_t aMatch, int32_t aPosition) +{ + IsoRun& lastIsoRun = mIsoRuns[mIsoRunLast]; + if (lastIsoRun.limit >= mOpeningsCount) { /* no available new entry */ + if (!GETOPENINGSMEMORY(lastIsoRun.limit * 2)) { + return false; + } + if (mOpenings == mSimpleOpenings) { + memcpy(mOpeningsMemory, mSimpleOpenings, + SIMPLE_OPENINGS_COUNT * sizeof(Opening)); + } + mOpenings = mOpeningsMemory; /* may have changed */ + mOpeningsCount = mOpeningsSize / sizeof(Opening); + } + Opening& o = mOpenings[lastIsoRun.limit]; + o.position = aPosition; + o.match = aMatch; + o.contextDir = lastIsoRun.contextDir; + o.contextPos = lastIsoRun.contextPos; + o.flags = 0; + lastIsoRun.limit++; + return true; +} + +/* change N0c1 to N0c2 when a preceding bracket is assigned the embedding level */ +void +nsBidi::BracketData::FixN0c(int32_t aOpeningIndex, int32_t aNewPropPosition, + DirProp aNewProp, DirProp* aDirProps) +{ + /* This function calls itself recursively */ + IsoRun& lastIsoRun = mIsoRuns[mIsoRunLast]; + for (int32_t k = aOpeningIndex + 1; k < lastIsoRun.limit; k++) { + Opening& o = mOpenings[k]; + if (o.match >= 0) { /* not an N0c match */ + continue; + } + if (aNewPropPosition < o.contextPos) { + break; + } + int32_t openingPosition = o.position; + if (aNewPropPosition >= openingPosition) { + continue; + } + if (aNewProp == o.contextDir) { + break; + } + aDirProps[openingPosition] = aNewProp; + int32_t closingPosition = -(o.match); + aDirProps[closingPosition] = aNewProp; + o.match = 0; /* prevent further changes */ + FixN0c(k, openingPosition, aNewProp, aDirProps); + FixN0c(k, closingPosition, aNewProp, aDirProps); + } +} + +/* process closing bracket */ +DirProp /* return L or R if N0b or N0c, ON if N0d */ +nsBidi::BracketData::ProcessClosing(int32_t aOpenIdx, int32_t aPosition, + DirProp* aDirProps) +{ + IsoRun& lastIsoRun = mIsoRuns[mIsoRunLast]; + Opening& o = mOpenings[aOpenIdx]; + DirProp newProp; + DirProp direction = GET_LR_FROM_LEVEL(lastIsoRun.level); + bool stable = true; // assume stable until proved otherwise + + /* The stable flag is set when brackets are paired and their + level is resolved and cannot be changed by what will be + found later in the source string. + An unstable match can occur only when applying N0c, where + the resolved level depends on the preceding context, and + this context may be affected by text occurring later. + Example: RTL paragraph containing: abc[(latin) HEBREW] + When the closing parenthesis is encountered, it appears + that N0c1 must be applied since 'abc' sets an opposite + direction context and both parentheses receive level 2. + However, when the closing square bracket is processed, + N0b applies because of 'HEBREW' being included within the + brackets, thus the square brackets are treated like R and + receive level 1. However, this changes the preceding + context of the opening parenthesis, and it now appears + that N0c2 must be applied to the parentheses rather than + N0c1. */ + + if ((direction == 0 && o.flags & FOUND_L) || + (direction == 1 && o.flags & FOUND_R)) { /* N0b */ + newProp = direction; + } else if (o.flags & (FOUND_L|FOUND_R)) { /* N0c */ + /* it is stable if there is no containing pair or in + conditions too complicated and not worth checking */ + stable = (aOpenIdx == lastIsoRun.start); + if (direction != o.contextDir) { + newProp = o.contextDir; /* N0c1 */ + } else { + newProp = direction; /* N0c2 */ + } + } else { + /* forget this and any brackets nested within this pair */ + lastIsoRun.limit = aOpenIdx; + return O_N; /* N0d */ + } + aDirProps[o.position] = newProp; + aDirProps[aPosition] = newProp; + /* Update nested N0c pairs that may be affected */ + FixN0c(aOpenIdx, o.position, newProp, aDirProps); + if (stable) { + /* forget any brackets nested within this pair */ + lastIsoRun.limit = aOpenIdx; + } else { + int32_t k; + o.match = -aPosition; + /* neutralize any unmatched opening between the current pair */ + for (k = aOpenIdx + 1; k < lastIsoRun.limit; k++) { + Opening& oo = mOpenings[k]; + if (oo.position > aPosition) { + break; + } + if (oo.match > 0) { + oo.match = 0; + } + } + } + return newProp; +} + +static inline bool +IsMatchingCloseBracket(char16_t aCh1, char16_t aCh2) +{ + // U+232A RIGHT-POINTING ANGLE BRACKET and U+3009 RIGHT ANGLE BRACKET + // are canonical equivalents, so we special-case them here. + return (aCh1 == aCh2) || + (aCh1 == 0x232A && aCh2 == 0x3009) || + (aCh2 == 0x232A && aCh1 == 0x3009); +} + +/* Handle strong characters, digits and candidates for closing brackets. */ +/* Returns true if success. (The only failure mode is an OOM when trying + to allocate memory for the Openings array.) */ +bool +nsBidi::BracketData::ProcessChar(int32_t aPosition, char16_t aCh, + DirProp* aDirProps, nsBidiLevel* aLevels) +{ + IsoRun& lastIsoRun = mIsoRuns[mIsoRunLast]; + DirProp newProp; + DirProp dirProp = aDirProps[aPosition]; + nsBidiLevel level = aLevels[aPosition]; + if (dirProp == O_N) { + /* First see if it is a matching closing bracket. Hopefully, this is + more efficient than checking if it is a closing bracket at all */ + for (int32_t idx = lastIsoRun.limit - 1; idx >= lastIsoRun.start; idx--) { + if (!IsMatchingCloseBracket(aCh, mOpenings[idx].match)) { + continue; + } + /* We have a match */ + newProp = ProcessClosing(idx, aPosition, aDirProps); + if (newProp == O_N) { /* N0d */ + aCh = 0; /* prevent handling as an opening */ + break; + } + lastIsoRun.lastBase = O_N; + lastIsoRun.contextDir = newProp; + lastIsoRun.contextPos = aPosition; + if (level & NSBIDI_LEVEL_OVERRIDE) { /* X4, X5 */ + newProp = GET_LR_FROM_LEVEL(level); + lastIsoRun.lastStrong = newProp; + uint16_t flag = DIRPROP_FLAG(newProp); + for (int32_t i = lastIsoRun.start; i < idx; i++) { + mOpenings[i].flags |= flag; + } + /* matching brackets are not overridden by LRO/RLO */ + aLevels[aPosition] &= ~NSBIDI_LEVEL_OVERRIDE; + } + /* matching brackets are not overridden by LRO/RLO */ + aLevels[mOpenings[idx].position] &= ~NSBIDI_LEVEL_OVERRIDE; + return true; + } + /* We get here only if the ON character is not a matching closing + bracket or it is a case of N0d */ + /* Now see if it is an opening bracket */ + char16_t match = GetPairedBracket(aCh); + if (match != aCh && /* has a matching char */ + GetPairedBracketType(aCh) == PAIRED_BRACKET_TYPE_OPEN) { /* opening bracket */ + if (!AddOpening(match, aPosition)) { + return false; + } + } + } + if (level & NSBIDI_LEVEL_OVERRIDE) { /* X4, X5 */ + newProp = GET_LR_FROM_LEVEL(level); + if (dirProp != S && dirProp != WS && dirProp != O_N) { + aDirProps[aPosition] = newProp; + } + lastIsoRun.lastBase = newProp; + lastIsoRun.lastStrong = newProp; + lastIsoRun.contextDir = newProp; + lastIsoRun.contextPos = aPosition; + } else if (IS_STRONG_TYPE(dirProp)) { + newProp = DirFromStrong(dirProp); + lastIsoRun.lastBase = dirProp; + lastIsoRun.lastStrong = dirProp; + lastIsoRun.contextDir = newProp; + lastIsoRun.contextPos = aPosition; + } else if (dirProp == EN) { + lastIsoRun.lastBase = EN; + if (lastIsoRun.lastStrong == L) { + newProp = L; /* W7 */ + aDirProps[aPosition] = ENL; + lastIsoRun.contextDir = L; + lastIsoRun.contextPos = aPosition; + } else { + newProp = R; /* N0 */ + if (lastIsoRun.lastStrong == AL) { + aDirProps[aPosition] = AN; /* W2 */ + } else { + aDirProps[aPosition] = ENR; + } + lastIsoRun.contextDir = R; + lastIsoRun.contextPos = aPosition; + } + } else if (dirProp == AN) { + newProp = R; /* N0 */ + lastIsoRun.lastBase = AN; + lastIsoRun.contextDir = R; + lastIsoRun.contextPos = aPosition; + } else if (dirProp == NSM) { + /* if the last real char was ON, change NSM to ON so that it + will stay ON even if the last real char is a bracket which + may be changed to L or R */ + newProp = lastIsoRun.lastBase; + if (newProp == O_N) { + aDirProps[aPosition] = newProp; + } + } else { + newProp = dirProp; + lastIsoRun.lastBase = dirProp; + } + if (IS_STRONG_TYPE(newProp)) { + uint16_t flag = DIRPROP_FLAG(DirFromStrong(newProp)); + for (int32_t i = lastIsoRun.start; i < lastIsoRun.limit; i++) { + if (aPosition > mOpenings[i].position) { + mOpenings[i].flags |= flag; + } + } + } + return true; +} + /* perform (X1)..(X9) ------------------------------------------------------- */ /* * Resolve the explicit levels as specified by explicit embedding codes. * Recalculate the flags to have them reflect the real properties * after taking the explicit embeddings into account. * * The Bidi algorithm is designed to result in the same behavior whether embedding @@ -630,17 +950,17 @@ void nsBidi::GetDirProps(const char16_t * * In order to have a correct push-pop semantics even in the case of overflows, * overflow counters and a valid isolate counter are used as described in UAX#9 * section 3.3.2 "Explicit Levels and Direction". * * This implementation assumes that NSBIDI_MAX_EXPLICIT_LEVEL is odd. */ -void nsBidi::ResolveExplicitLevels(nsBidiDirection *aDirection) +void nsBidi::ResolveExplicitLevels(nsBidiDirection *aDirection, const char16_t *aText) { DirProp *dirProps=mDirProps; nsBidiLevel *levels=mLevels; int32_t i=0, length=mLength; Flags flags=mFlags; /* collect all directionalities in the text */ DirProp dirProp; nsBidiLevel level=mParaLevel; @@ -650,268 +970,237 @@ void nsBidi::ResolveExplicitLevels(nsBid /* determine if the text is mixed-directional or single-directional */ direction=DirectionFromFlags(flags); /* we may not need to resolve any explicit levels */ if(direction!=NSBIDI_MIXED) { /* not mixed directionality: levels don't matter - trailingWSStart will be 0 */ } else if(!(flags&(MASK_EXPLICIT|MASK_ISO))) { + BracketData bracketData(this); /* no embeddings, set all levels to the paragraph level */ for(i=0; i<length; ++i) { levels[i]=level; + if (dirProps[i] == BN) { + continue; + } + if (!bracketData.ProcessChar(i, aText[i], mDirProps, mLevels)) { + NS_WARNING("BracketData::ProcessChar failed, out of memory?"); + // Ran out of memory for deeply-nested openings; give up and + // return LTR. This could presumably result in incorrect display, + // but in practice it won't happen except in some artificially- + // constructed torture test -- which is just as likely to die + // altogether with an OOM failure. + *aDirection = NSBIDI_LTR; + return; + } } } else { /* continue to perform (Xn) */ /* (X1) level is set for all codes, embeddingLevel keeps track of the push/pop operations */ /* both variables may carry the NSBIDI_LEVEL_OVERRIDE flag to indicate the override status */ nsBidiLevel embeddingLevel = level, newLevel; nsBidiLevel previousLevel = level; /* previous level for regular (not CC) characters */ + int32_t lastDirControlCharPos = 0; /* index of last effective LRx,RLx, PDx */ uint16_t stack[NSBIDI_MAX_EXPLICIT_LEVEL + 2]; /* we never push anything >=NSBIDI_MAX_EXPLICIT_LEVEL but we need one more entry as base */ int32_t stackLast = 0; int32_t overflowIsolateCount = 0; int32_t overflowEmbeddingCount = 0; int32_t validIsolateCount = 0; + BracketData bracketData(this); + stack[0] = level; /* recalculate the flags */ flags=0; /* since we assume that this is a single paragraph, we ignore (X8) */ for(i=0; i<length; ++i) { dirProp=dirProps[i]; switch(dirProp) { case LRE: case RLE: case LRO: case RLO: /* (X2, X3, X4, X5) */ flags |= DIRPROP_FLAG(BN); + levels[i] = previousLevel; if (dirProp == LRE || dirProp == LRO) { newLevel = (embeddingLevel + 2) & ~(NSBIDI_LEVEL_OVERRIDE | 1); /* least greater even level */ } else { newLevel = ((embeddingLevel & ~NSBIDI_LEVEL_OVERRIDE) + 1) | 1; /* least greater odd level */ } if(newLevel <= NSBIDI_MAX_EXPLICIT_LEVEL && overflowIsolateCount == 0 && overflowEmbeddingCount == 0) { + lastDirControlCharPos = i; embeddingLevel = newLevel; if (dirProp == LRO || dirProp == RLO) { embeddingLevel |= NSBIDI_LEVEL_OVERRIDE; } stackLast++; stack[stackLast] = embeddingLevel; - /* we don't need to set UBIDI_LEVEL_OVERRIDE off for LRE and RLE + /* we don't need to set NSBIDI_LEVEL_OVERRIDE off for LRE and RLE since this has already been done for newLevel which is the source for embeddingLevel. */ } else { - dirProps[i] |= IGNORE_CC; if (overflowIsolateCount == 0) { overflowEmbeddingCount++; } } break; case PDF: /* (X7) */ flags |= DIRPROP_FLAG(BN); + levels[i] = previousLevel; /* handle all the overflow cases first */ if (overflowIsolateCount) { - dirProps[i] |= IGNORE_CC; break; } if (overflowEmbeddingCount) { - dirProps[i] |= IGNORE_CC; overflowEmbeddingCount--; break; } if (stackLast > 0 && stack[stackLast] < ISOLATE) { /* not an isolate entry */ + lastDirControlCharPos = i; stackLast--; embeddingLevel = stack[stackLast]; - } else { - dirProps[i] |= IGNORE_CC; } break; case LRI: case RLI: - if (embeddingLevel != previousLevel) { - previousLevel = embeddingLevel; + flags |= DIRPROP_FLAG(O_N) | DIRPROP_FLAG_LR(embeddingLevel); + levels[i] = NO_OVERRIDE(embeddingLevel); + if (NO_OVERRIDE(embeddingLevel) != NO_OVERRIDE(previousLevel)) { + bracketData.ProcessBoundary(lastDirControlCharPos, previousLevel, + embeddingLevel, mDirProps); + flags |= DIRPROP_FLAG_MULTI_RUNS; } + previousLevel = embeddingLevel; /* (X5a, X5b) */ - flags |= DIRPROP_FLAG(O_N) | DIRPROP_FLAG(BN) | DIRPROP_FLAG_LR(embeddingLevel); - level = embeddingLevel; if (dirProp == LRI) { newLevel = (embeddingLevel + 2) & ~(NSBIDI_LEVEL_OVERRIDE | 1); /* least greater even level */ } else { newLevel = ((embeddingLevel & ~NSBIDI_LEVEL_OVERRIDE) + 1) | 1; /* least greater odd level */ } if (newLevel <= NSBIDI_MAX_EXPLICIT_LEVEL && overflowIsolateCount == 0 && overflowEmbeddingCount == 0) { + flags |= DIRPROP_FLAG(dirProp); + lastDirControlCharPos = i; previousLevel = embeddingLevel; validIsolateCount++; if (validIsolateCount > mIsolateCount) { mIsolateCount = validIsolateCount; } embeddingLevel = newLevel; stackLast++; stack[stackLast] = embeddingLevel + ISOLATE; + bracketData.ProcessLRI_RLI(embeddingLevel); } else { - dirProps[i] |= IGNORE_CC; + /* make it so that it is handled by AdjustWSLevels() */ + dirProps[i] = WS; overflowIsolateCount++; } break; case PDI: + if (NO_OVERRIDE(embeddingLevel) != NO_OVERRIDE(previousLevel)) { + bracketData.ProcessBoundary(lastDirControlCharPos, previousLevel, + embeddingLevel, mDirProps); + flags |= DIRPROP_FLAG_MULTI_RUNS; + } /* (X6a) */ if (overflowIsolateCount) { - dirProps[i] |= IGNORE_CC; overflowIsolateCount--; + /* make it so that it is handled by AdjustWSLevels() */ + dirProps[i] = WS; } else if (validIsolateCount) { + flags |= DIRPROP_FLAG(PDI); + lastDirControlCharPos = i; overflowEmbeddingCount = 0; while (stack[stackLast] < ISOLATE) { /* pop embedding entries */ /* until the last isolate entry */ stackLast--; // Since validIsolateCount is true, there must be an isolate entry // on the stack, so the stack is guaranteed to not be empty. // Still, to eliminate a warning from coverity, we use an assertion. MOZ_ASSERT(stackLast > 0); } stackLast--; /* pop also the last isolate entry */ MOZ_ASSERT(stackLast >= 0); // For coverity validIsolateCount--; + bracketData.ProcessPDI(); } else { - dirProps[i] |= IGNORE_CC; + /* make it so that it is handled by AdjustWSLevels() */ + dirProps[i] = WS; } embeddingLevel = stack[stackLast] & ~ISOLATE; - previousLevel = level = embeddingLevel; - flags |= DIRPROP_FLAG(O_N) | DIRPROP_FLAG(BN) | DIRPROP_FLAG_LR(embeddingLevel); + flags |= DIRPROP_FLAG(O_N) | DIRPROP_FLAG_LR(embeddingLevel); + previousLevel = embeddingLevel; + levels[i] = NO_OVERRIDE(embeddingLevel); break; case B: /* * We do not expect to see a paragraph separator (B), */ NS_NOTREACHED("Unexpected paragraph separator"); break; case BN: /* BN, LRE, RLE, and PDF are supposed to be removed (X9) */ /* they will get their levels set correctly in AdjustWSLevels() */ - flags|=DIRPROP_FLAG(BN); + levels[i] = previousLevel; + flags |= DIRPROP_FLAG(BN); break; default: /* all other types get the "real" level */ - level = embeddingLevel; - if(embeddingLevel != previousLevel) { - previousLevel = embeddingLevel; + if (NO_OVERRIDE(embeddingLevel) != NO_OVERRIDE(previousLevel)) { + bracketData.ProcessBoundary(lastDirControlCharPos, previousLevel, + embeddingLevel, mDirProps); + flags |= DIRPROP_FLAG_MULTI_RUNS; + if (embeddingLevel & NSBIDI_LEVEL_OVERRIDE) { + flags |= DIRPROP_FLAG_O(embeddingLevel); + } else { + flags |= DIRPROP_FLAG_E(embeddingLevel); + } } - - if (level & NSBIDI_LEVEL_OVERRIDE) { - flags |= DIRPROP_FLAG_LR(level); - } else { - flags |= DIRPROP_FLAG(dirProp); + previousLevel = embeddingLevel; + levels[i] = embeddingLevel; + if (!bracketData.ProcessChar(i, aText[i], mDirProps, mLevels)) { + NS_WARNING("BracketData::ProcessChar failed, out of memory?"); + *aDirection = NSBIDI_LTR; + return; } + flags |= DIRPROP_FLAG(dirProps[i]); break; } - - /* - * We need to set reasonable levels even on BN codes and - * explicit codes because we will later look at same-level runs (X10). - */ - levels[i]=level; - if (i > 0 && levels[i - 1] != level) { - flags |= DIRPROP_FLAG_MULTI_RUNS; - if (level & NSBIDI_LEVEL_OVERRIDE) { - flags |= DIRPROP_FLAG_O(level); - } else { - flags |= DIRPROP_FLAG_E(level); - } - } - if (DIRPROP_FLAG(dirProp) & MASK_ISO) { - level = embeddingLevel; - } } if(flags&MASK_EMBEDDING) { flags|=DIRPROP_FLAG_LR(mParaLevel); } /* subsequently, ignore the explicit codes and BN (X9) */ /* again, determine if the text is mixed-directional or single-directional */ mFlags=flags; direction=DirectionFromFlags(flags); } *aDirection = direction; } -/* - * Use a pre-specified embedding levels array: - * - * Adjust the directional properties for overrides (->LEVEL_OVERRIDE), - * ignore all explicit codes (X9), - * and check all the preset levels. - * - * Recalculate the flags to have them reflect the real properties - * after taking the explicit embeddings into account. - */ -nsresult nsBidi::CheckExplicitLevels(nsBidiDirection *aDirection) -{ - const DirProp *dirProps=mDirProps; - DirProp dirProp; - nsBidiLevel *levels=mLevels; - int32_t isolateCount = 0; - - int32_t i, length=mLength; - Flags flags=0; /* collect all directionalities in the text */ - nsBidiLevel level, paraLevel=mParaLevel; - mIsolateCount = 0; - - for(i=0; i<length; ++i) { - level=levels[i]; - dirProp = dirProps[i]; - if (dirProp == LRI || dirProp == RLI) { - isolateCount++; - if (isolateCount > mIsolateCount) { - mIsolateCount = isolateCount; - } - } else if (dirProp == PDI) { - isolateCount--; - } - if(level&NSBIDI_LEVEL_OVERRIDE) { - /* keep the override flag in levels[i] but adjust the flags */ - level&=~NSBIDI_LEVEL_OVERRIDE; /* make the range check below simpler */ - flags|=DIRPROP_FLAG_O(level); - } else { - /* set the flags */ - flags|=DIRPROP_FLAG_E(level)|DIRPROP_FLAG(dirProp); - } - if(level<paraLevel || NSBIDI_MAX_EXPLICIT_LEVEL<level) { - /* level out of bounds */ - *aDirection = NSBIDI_LTR; - return NS_ERROR_INVALID_ARG; - } - } - if(flags&MASK_EMBEDDING) { - flags|=DIRPROP_FLAG_LR(mParaLevel); - } - - /* determine if the text is mixed-directional or single-directional */ - mFlags=flags; - *aDirection = DirectionFromFlags(flags); - return NS_OK; -} - /* determine if the text is mixed-directional or single-directional */ nsBidiDirection nsBidi::DirectionFromFlags(Flags aFlags) { /* if the text contains AN and neutrals, then some neutrals may become RTL */ if(!(aFlags&MASK_RTL || (aFlags&DIRPROP_FLAG(AN) && aFlags&MASK_POSSIBLE_N))) { return NSBIDI_LTR; } else if(!(aFlags&MASK_LTR)) { return NSBIDI_RTL; @@ -1191,31 +1480,31 @@ void nsBidi::ResolveImplicitLevels(int32 const DirProp *dirProps = mDirProps; DirProp dirProp; LevState levState; int32_t i, start1, start2; uint16_t oldStateImp, stateImp, actionImp; uint8_t gprop, resProp, cell; /* initialize for property and levels state tables */ - levState.startON = -1; levState.runStart = aStart; levState.runLevel = mLevels[aStart]; levState.pImpTab = impTab[levState.runLevel & 1]; levState.pImpAct = impAct0; /* The isolates[] entries contain enough information to resume the bidi algorithm in the same state as it was when it was interrupted by an isolate sequence. */ - if (dirProps[aStart] == PDI) { + if (dirProps[aStart] == PDI && mIsolateCount >= 0) { start1 = mIsolates[mIsolateCount].start1; stateImp = mIsolates[mIsolateCount].stateImp; levState.state = mIsolates[mIsolateCount].state; mIsolateCount--; } else { + levState.startON = -1; start1 = aStart; if (dirProps[aStart] == NSM) { stateImp = 1 + aSOR; } else { stateImp = 0; } levState.state = 0; ProcessPropertySeq(&levState, aSOR, aStart, aStart); @@ -1228,17 +1517,17 @@ void nsBidi::ResolveImplicitLevels(int32 dirProp = mDirProps[aLimit - 1]; if (dirProp == LRI || dirProp == RLI) { break; /* no forced closing for sequence ending with LRI/RLI */ } } gprop = aEOR; } else { DirProp prop; - prop = PURE_DIRPROP(dirProps[i]); + prop = dirProps[i]; gprop = groupProp[prop]; } oldStateImp = stateImp; cell = impTabProps[oldStateImp][gprop]; stateImp = GET_STATEPROPS(cell); /* isolate the new state */ actionImp = GET_ACTIONPROPS(cell); /* isolate the action */ if ((i == aLimit) && (actionImp == 0)) { /* there is an unprocessed sequence if its property == eor */ @@ -1299,24 +1588,24 @@ void nsBidi::AdjustWSLevels() if(mFlags&MASK_WS) { nsBidiLevel paraLevel=mParaLevel; Flags flag; i=mTrailingWSStart; while(i>0) { /* reset a sequence of WS/BN before eop and B/S to the paragraph paraLevel */ - while (i > 0 && DIRPROP_FLAG(PURE_DIRPROP(dirProps[--i])) & MASK_WS) { + while (i > 0 && DIRPROP_FLAG(dirProps[--i]) & MASK_WS) { levels[i]=paraLevel; } /* reset BN to the next character's paraLevel until B/S, which restarts above loop */ /* here, i+1 is guaranteed to be <length */ while(i>0) { - flag = DIRPROP_FLAG(PURE_DIRPROP(dirProps[--i])); + flag = DIRPROP_FLAG(dirProps[--i]); if(flag&MASK_BN_EXPLICIT) { levels[i]=levels[i+1]; } else if(flag&MASK_B_S) { levels[i]=paraLevel; break; } } } @@ -1329,262 +1618,16 @@ nsresult nsBidi::GetDirection(nsBidiDire return NS_OK; } nsresult nsBidi::GetParaLevel(nsBidiLevel* aParaLevel) { *aParaLevel = mParaLevel; return NS_OK; } -#ifdef FULL_BIDI_ENGINE - -/* -------------------------------------------------------------------------- */ - -nsresult nsBidi::GetLength(int32_t* aLength) -{ - *aLength = mLength; - return NS_OK; -} - -/* - * General remarks about the functions in this section: - * - * These functions deal with the aspects of potentially mixed-directional - * text in a single paragraph or in a line of a single paragraph - * which has already been processed according to - * the Unicode 6.3 Bidi algorithm as defined in - * http://www.unicode.org/unicode/reports/tr9/ , version 28, - * also described in The Unicode Standard, Version 6.3.0 . - * - * This means that there is a nsBidi object with a levels - * and a dirProps array. - * paraLevel and direction are also set. - * Only if the length of the text is zero, then levels==dirProps==nullptr. - * - * The overall directionality of the paragraph - * or line is used to bypass the reordering steps if possible. - * Even purely RTL text does not need reordering there because - * the getLogical/VisualIndex() functions can compute the - * index on the fly in such a case. - * - * The implementation of the access to same-level-runs and of the reordering - * do attempt to provide better performance and less memory usage compared to - * a direct implementation of especially rule (L2) with an array of - * one (32-bit) integer per text character. - * - * Here, the levels array is scanned as soon as necessary, and a vector of - * same-level-runs is created. Reordering then is done on this vector. - * For each run of text positions that were resolved to the same level, - * only 8 bytes are stored: the first text position of the run and the visual - * position behind the run after reordering. - * One sign bit is used to hold the directionality of the run. - * This is inefficient if there are many very short runs. If the average run - * length is <2, then this uses more memory. - * - * In a further attempt to save memory, the levels array is never changed - * after all the resolution rules (Xn, Wn, Nn, In). - * Many functions have to consider the field trailingWSStart: - * if it is less than length, then there is an implicit trailing run - * at the paraLevel, - * which is not reflected in the levels array. - * This allows a line nsBidi object to use the same levels array as - * its paragraph parent object. - * - * When a nsBidi object is created for a line of a paragraph, then the - * paragraph's levels and dirProps arrays are reused by way of setting - * a pointer into them, not by copying. This again saves memory and forbids to - * change the now shared levels for (L1). - */ -nsresult nsBidi::SetLine(const nsBidi* aParaBidi, int32_t aStart, int32_t aLimit) -{ - nsBidi* pParent = (nsBidi*)aParaBidi; - int32_t length; - - /* check the argument values */ - if(pParent==nullptr) { - return NS_ERROR_INVALID_POINTER; - } else if(aStart < 0 || aStart >= aLimit || aLimit > pParent->mLength) { - return NS_ERROR_INVALID_ARG; - } - - /* set members from our aParaBidi parent */ - length = mLength = aLimit - aStart; - mParaLevel=pParent->mParaLevel; - - mRuns=nullptr; - mFlags=0; - - mDirProps=pParent->mDirProps+aStart; - mLevels=pParent->mLevels+aStart; - mRunCount=-1; - - if(pParent->mDirection!=NSBIDI_MIXED) { - /* the parent is already trivial */ - mDirection=pParent->mDirection; - - /* - * The parent's levels are all either - * implicitly or explicitly ==paraLevel; - * do the same here. - */ - if(pParent->mTrailingWSStart<=aStart) { - mTrailingWSStart=0; - } else if(pParent->mTrailingWSStart<aLimit) { - mTrailingWSStart=pParent->mTrailingWSStart-aStart; - } else { - mTrailingWSStart=length; - } - } else { - const nsBidiLevel *levels=mLevels; - int32_t i, trailingWSStart; - nsBidiLevel level; - - SetTrailingWSStart(); - trailingWSStart=mTrailingWSStart; - - /* recalculate pLineBidi->direction */ - if(trailingWSStart==0) { - /* all levels are at paraLevel */ - mDirection=(nsBidiDirection)(mParaLevel&1); - } else { - /* get the level of the first character */ - level=levels[0]&1; - - /* if there is anything of a different level, then the line is mixed */ - if(trailingWSStart<length && (mParaLevel&1)!=level) { - /* the trailing WS is at paraLevel, which differs from levels[0] */ - mDirection=NSBIDI_MIXED; - } else { - /* see if levels[1..trailingWSStart-1] have the same direction as levels[0] and paraLevel */ - i=1; - for(;;) { - if(i==trailingWSStart) { - /* the direction values match those in level */ - mDirection=(nsBidiDirection)level; - break; - } else if((levels[i]&1)!=level) { - mDirection=NSBIDI_MIXED; - break; - } - ++i; - } - } - } - - switch(mDirection) { - case NSBIDI_LTR: - /* make sure paraLevel is even */ - mParaLevel=(mParaLevel+1)&~1; - - /* all levels are implicitly at paraLevel (important for GetLevels()) */ - mTrailingWSStart=0; - break; - case NSBIDI_RTL: - /* make sure paraLevel is odd */ - mParaLevel|=1; - - /* all levels are implicitly at paraLevel (important for GetLevels()) */ - mTrailingWSStart=0; - break; - default: - break; - } - } - return NS_OK; -} - -/* handle trailing WS (L1) -------------------------------------------------- */ - -/* - * SetTrailingWSStart() sets the start index for a trailing - * run of WS in the line. This is necessary because we do not modify - * the paragraph's levels array that we just point into. - * Using trailingWSStart is another form of performing (L1). - * - * To make subsequent operations easier, we also include the run - * before the WS if it is at the paraLevel - we merge the two here. - */ -void nsBidi::SetTrailingWSStart() { - /* mDirection!=NSBIDI_MIXED */ - - const DirProp *dirProps=mDirProps; - nsBidiLevel *levels=mLevels; - int32_t start=mLength; - nsBidiLevel paraLevel=mParaLevel; - - /* go backwards across all WS, BN, explicit codes */ - while(start>0 && DIRPROP_FLAG(dirProps[start-1])&MASK_WS) { - --start; - } - - /* if the WS run can be merged with the previous run then do so here */ - while(start>0 && levels[start-1]==paraLevel) { - --start; - } - - mTrailingWSStart=start; -} - -nsresult nsBidi::GetLevelAt(int32_t aCharIndex, nsBidiLevel* aLevel) -{ - /* return paraLevel if in the trailing WS run, otherwise the real level */ - if(aCharIndex<0 || mLength<=aCharIndex) { - *aLevel = 0; - } else if(mDirection!=NSBIDI_MIXED || aCharIndex>=mTrailingWSStart) { - *aLevel = mParaLevel; - } else { - *aLevel = mLevels[aCharIndex]; - } - return NS_OK; -} - -nsresult nsBidi::GetLevels(nsBidiLevel** aLevels) -{ - int32_t start, length; - - length = mLength; - if(length<=0) { - *aLevels = nullptr; - return NS_ERROR_INVALID_ARG; - } - - start = mTrailingWSStart; - if(start==length) { - /* the current levels array reflects the WS run */ - *aLevels = mLevels; - return NS_OK; - } - - /* - * After the previous if(), we know that the levels array - * has an implicit trailing WS run and therefore does not fully - * reflect itself all the levels. - * This must be a nsBidi object for a line, and - * we need to create a new levels array. - */ - - if(GETLEVELSMEMORY(length)) { - nsBidiLevel *levels=mLevelsMemory; - - if(start>0 && levels!=mLevels) { - memcpy(levels, mLevels, start); - } - memset(levels+start, mParaLevel, length-start); - - /* this new levels array is set for the line and reflects the WS run */ - mTrailingWSStart=length; - *aLevels=mLevels=levels; - return NS_OK; - } else { - /* out of memory */ - *aLevels = nullptr; - return NS_ERROR_OUT_OF_MEMORY; - } -} -#endif // FULL_BIDI_ENGINE nsresult nsBidi::GetCharTypeAt(int32_t aCharIndex, nsCharType* pType) { if(aCharIndex<0 || mLength<=aCharIndex) { return NS_ERROR_INVALID_ARG; } *pType = (nsCharType)mDirProps[aCharIndex]; return NS_OK; @@ -2033,459 +2076,8 @@ bool nsBidi::PrepareReorder(const nsBidi /* initialize the index map */ for(start=aLength; start>0;) { --start; aIndexMap[start]=start; } return true; } - -#ifdef FULL_BIDI_ENGINE -/* API functions for logical<->visual mapping ------------------------------- */ - -nsresult nsBidi::GetVisualIndex(int32_t aLogicalIndex, int32_t* aVisualIndex) { - int32_t visualIndex = NSBIDI_MAP_NOWHERE; - - if(aLogicalIndex<0 || mLength<=aLogicalIndex) { - return NS_ERROR_INVALID_ARG; - } else { - /* we can do the trivial cases without the runs array */ - switch(mDirection) { - case NSBIDI_LTR: - *aVisualIndex = aLogicalIndex; - return NS_OK; - case NSBIDI_RTL: - *aVisualIndex = mLength-aLogicalIndex-1; - return NS_OK; - default: - if(mRunCount<0 && !GetRuns()) { - return NS_ERROR_OUT_OF_MEMORY; - } else { - Run *runs=mRuns; - int32_t i, visualStart=0, offset, length; - - /* linear search for the run, search on the visual runs */ - for (i = 0; i < mRunCount; ++i) { - length=runs[i].visualLimit-visualStart; - offset=aLogicalIndex-GET_INDEX(runs[i].logicalStart); - if(offset>=0 && offset<length) { - if(IS_EVEN_RUN(runs[i].logicalStart)) { - /* LTR */ - visualIndex = visualStart + offset; - } else { - /* RTL */ - visualIndex = visualStart + length - offset - 1; - } - break; - } - visualStart+=length; - } - if (i >= mRunCount) { - *aVisualIndex = NSBIDI_MAP_NOWHERE; - return NS_OK; - } - } - } - } - - *aVisualIndex = visualIndex; - return NS_OK; -} - -nsresult nsBidi::GetLogicalIndex(int32_t aVisualIndex, int32_t *aLogicalIndex) -{ - if(aVisualIndex<0 || mLength<=aVisualIndex) { - return NS_ERROR_INVALID_ARG; - } - - /* we can do the trivial cases without the runs array */ - if (mDirection == NSBIDI_LTR) { - *aLogicalIndex = aVisualIndex; - return NS_OK; - } else if (mDirection == NSBIDI_RTL) { - *aLogicalIndex = mLength - aVisualIndex - 1; - return NS_OK; - } - - if(mRunCount<0 && !GetRuns()) { - return NS_ERROR_OUT_OF_MEMORY; - } - - Run *runs=mRuns; - int32_t i, runCount=mRunCount, start; - - if(runCount<=10) { - /* linear search for the run */ - for(i=0; aVisualIndex>=runs[i].visualLimit; ++i) {} - } else { - /* binary search for the run */ - int32_t start=0, limit=runCount; - - /* the middle if() will guaranteed find the run, we don't need a loop limit */ - for(;;) { - i=(start+limit)/2; - if(aVisualIndex>=runs[i].visualLimit) { - start=i+1; - } else if(i==0 || aVisualIndex>=runs[i-1].visualLimit) { - break; - } else { - limit=i; - } - } - } - - start=runs[i].logicalStart; - if(IS_EVEN_RUN(start)) { - /* LTR */ - /* the offset in runs[i] is aVisualIndex-runs[i-1].visualLimit */ - if(i>0) { - aVisualIndex-=runs[i-1].visualLimit; - } - *aLogicalIndex = GET_INDEX(start)+aVisualIndex; - return NS_OK; - } else { - /* RTL */ - *aLogicalIndex = GET_INDEX(start)+runs[i].visualLimit-aVisualIndex-1; - return NS_OK; - } -} - -nsresult nsBidi::GetLogicalMap(int32_t *aIndexMap) -{ - nsresult rv; - - /* CountRuns() checks for VALID_PARA_OR_LINE */ - rv = CountRuns(nullptr); - if(NS_FAILED(rv)) { - return rv; - } else if(aIndexMap==nullptr) { - return NS_ERROR_INVALID_ARG; - } else { - /* fill a logical-to-visual index map using the runs[] */ - int32_t visualStart, visualLimit, j; - int32_t logicalStart; - Run *runs = mRuns; - if (mLength <= 0) { - return NS_OK; - } - - visualStart = 0; - for (j = 0; j < mRunCount; ++j) { - logicalStart = GET_INDEX(runs[j].logicalStart); - visualLimit = runs[j].visualLimit; - if (IS_EVEN_RUN(runs[j].logicalStart)) { - do { /* LTR */ - aIndexMap[logicalStart++] = visualStart++; - } while (visualStart < visualLimit); - } else { - logicalStart += visualLimit-visualStart; /* logicalLimit */ - do { /* RTL */ - aIndexMap[--logicalStart] = visualStart++; - } while (visualStart < visualLimit); - } - /* visualStart==visualLimit; */ - } - } - return NS_OK; -} - -nsresult nsBidi::GetVisualMap(int32_t *aIndexMap) -{ - int32_t* runCount=nullptr; - nsresult rv; - - if(aIndexMap==nullptr) { - return NS_ERROR_INVALID_ARG; - } - - /* CountRuns() checks all of its and our arguments */ - rv = CountRuns(runCount); - if(NS_FAILED(rv)) { - return rv; - } else { - /* fill a visual-to-logical index map using the runs[] */ - Run *runs=mRuns, *runsLimit=runs+mRunCount; - int32_t logicalStart, visualStart, visualLimit; - - visualStart=0; - for(; runs<runsLimit; ++runs) { - logicalStart=runs->logicalStart; - visualLimit=runs->visualLimit; - if(IS_EVEN_RUN(logicalStart)) { - do { /* LTR */ - *aIndexMap++ = logicalStart++; - } while(++visualStart<visualLimit); - } else { - REMOVE_ODD_BIT(logicalStart); - logicalStart+=visualLimit-visualStart; /* logicalLimit */ - do { /* RTL */ - *aIndexMap++ = --logicalStart; - } while(++visualStart<visualLimit); - } - /* visualStart==visualLimit; */ - } - return NS_OK; - } -} - -/* reorder a line based on a levels array (L2) ------------------------------ */ - -nsresult nsBidi::ReorderLogical(const nsBidiLevel *aLevels, int32_t aLength, int32_t *aIndexMap) -{ - int32_t start, limit, sumOfSosEos; - nsBidiLevel minLevel, maxLevel; - - if(aIndexMap==nullptr || - !PrepareReorder(aLevels, aLength, aIndexMap, &minLevel, &maxLevel)) { - return NS_OK; - } - - /* nothing to do? */ - if(minLevel==maxLevel && (minLevel&1)==0) { - return NS_OK; - } - - /* reorder only down to the lowest odd level */ - minLevel|=1; - - /* loop maxLevel..minLevel */ - do { - start=0; - - /* loop for all sequences of levels to reorder at the current maxLevel */ - for(;;) { - /* look for a sequence of levels that are all at >=maxLevel */ - /* look for the first index of such a sequence */ - while(start<aLength && aLevels[start]<maxLevel) { - ++start; - } - if(start>=aLength) { - break; /* no more such sequences */ - } - - /* look for the limit of such a sequence (the index behind it) */ - for(limit=start; ++limit<aLength && aLevels[limit]>=maxLevel;) {} - - /* - * sos=start of sequence, eos=end of sequence - * - * The closed (inclusive) interval from sos to eos includes all the logical - * and visual indexes within this sequence. They are logically and - * visually contiguous and in the same range. - * - * For each run, the new visual index=sos+eos-old visual index; - * we pre-add sos+eos into sumOfSosEos -> - * new visual index=sumOfSosEos-old visual index; - */ - sumOfSosEos=start+limit-1; - - /* reorder each index in the sequence */ - do { - aIndexMap[start]=sumOfSosEos-aIndexMap[start]; - } while(++start<limit); - - /* start==limit */ - if(limit==aLength) { - break; /* no more such sequences */ - } else { - start=limit+1; - } - } - } while(--maxLevel>=minLevel); - - return NS_OK; -} - -nsresult nsBidi::InvertMap(const int32_t *aSrcMap, int32_t *aDestMap, int32_t aLength) -{ - if(aSrcMap!=nullptr && aDestMap!=nullptr && aLength > 0) { - const int32_t *pi; - int32_t destLength = -1, count = 0; - /* find highest value and count positive indexes in srcMap */ - pi = aSrcMap + aLength; - while (pi > aSrcMap) { - if (*--pi > destLength) { - destLength = *pi; - } - if (*pi >= 0) { - count++; - } - } - destLength++; /* add 1 for origin 0 */ - if (count < destLength) { - /* we must fill unmatched destMap entries with -1 */ - memset(aDestMap, 0xFF, destLength * sizeof(int32_t)); - } - pi = aSrcMap + aLength; - while (aLength > 0) { - if (*--pi >= 0) { - aDestMap[*pi] = --aLength; - } else { - --aLength; - } - } - } - return NS_OK; -} - -int32_t nsBidi::doWriteReverse(const char16_t *src, int32_t srcLength, - char16_t *dest, uint16_t options) { - /* - * RTL run - - * - * RTL runs need to be copied to the destination in reverse order - * of code points, not code units, to keep Unicode characters intact. - * - * The general strategy for this is to read the source text - * in backward order, collect all code units for a code point - * (and optionally following combining characters, see below), - * and copy all these code units in ascending order - * to the destination for this run. - * - * Several options request whether combining characters - * should be kept after their base characters, - * whether Bidi control characters should be removed, and - * whether characters should be replaced by their mirror-image - * equivalent Unicode characters. - */ - int32_t i, j, destSize; - uint32_t c; - - /* optimize for several combinations of options */ - switch(options&(NSBIDI_REMOVE_BIDI_CONTROLS|NSBIDI_DO_MIRRORING|NSBIDI_KEEP_BASE_COMBINING)) { - case 0: - /* - * With none of the "complicated" options set, the destination - * run will have the same length as the source run, - * and there is no mirroring and no keeping combining characters - * with their base characters. - */ - destSize=srcLength; - - /* preserve character integrity */ - do { - /* i is always after the last code unit known to need to be kept in this segment */ - i=srcLength; - - /* collect code units for one base character */ - UTF_BACK_1(src, 0, srcLength); - - /* copy this base character */ - j=srcLength; - do { - *dest++=src[j++]; - } while(j<i); - } while(srcLength>0); - break; - case NSBIDI_KEEP_BASE_COMBINING: - /* - * Here, too, the destination - * run will have the same length as the source run, - * and there is no mirroring. - * We do need to keep combining characters with their base characters. - */ - destSize=srcLength; - - /* preserve character integrity */ - do { - /* i is always after the last code unit known to need to be kept in this segment */ - i=srcLength; - - /* collect code units and modifier letters for one base character */ - do { - UTF_PREV_CHAR(src, 0, srcLength, c); - } while(srcLength>0 && GetBidiCat(c) == eCharType_DirNonSpacingMark); - - /* copy this "user character" */ - j=srcLength; - do { - *dest++=src[j++]; - } while(j<i); - } while(srcLength>0); - break; - default: - /* - * With several "complicated" options set, this is the most - * general and the slowest copying of an RTL run. - * We will do mirroring, remove Bidi controls, and - * keep combining characters with their base characters - * as requested. - */ - if(!(options&NSBIDI_REMOVE_BIDI_CONTROLS)) { - i=srcLength; - } else { - /* we need to find out the destination length of the run, - which will not include the Bidi control characters */ - int32_t length=srcLength; - char16_t ch; - - i=0; - do { - ch=*src++; - if (!IsBidiControl((uint32_t)ch)) { - ++i; - } - } while(--length>0); - src-=srcLength; - } - destSize=i; - - /* preserve character integrity */ - do { - /* i is always after the last code unit known to need to be kept in this segment */ - i=srcLength; - - /* collect code units for one base character */ - UTF_PREV_CHAR(src, 0, srcLength, c); - if(options&NSBIDI_KEEP_BASE_COMBINING) { - /* collect modifier letters for this base character */ - while(srcLength>0 && GetBidiCat(c) == eCharType_DirNonSpacingMark) { - UTF_PREV_CHAR(src, 0, srcLength, c); - } - } - - if(options&NSBIDI_REMOVE_BIDI_CONTROLS && IsBidiControl(c)) { - /* do not copy this Bidi control character */ - continue; - } - - /* copy this "user character" */ - j=srcLength; - if(options&NSBIDI_DO_MIRRORING) { - /* mirror only the base character */ - c = GetMirroredChar(c); - - int32_t k=0; - UTF_APPEND_CHAR_UNSAFE(dest, k, c); - dest+=k; - j+=k; - } - while(j<i) { - *dest++=src[j++]; - } - } while(srcLength>0); - break; - } /* end of switch */ - return destSize; -} - -nsresult nsBidi::WriteReverse(const char16_t *aSrc, int32_t aSrcLength, char16_t *aDest, uint16_t aOptions, int32_t *aDestSize) -{ - if( aSrc==nullptr || aSrcLength<0 || - aDest==nullptr - ) { - return NS_ERROR_INVALID_ARG; - } - - /* do input and output overlap? */ - if( aSrc>=aDest && aSrc<aDest+aSrcLength || - aDest>=aSrc && aDest<aSrc+aSrcLength - ) { - return NS_ERROR_INVALID_ARG; - } - - if(aSrcLength>0) { - *aDestSize = doWriteReverse(aSrc, aSrcLength, aDest, aOptions); - } - return NS_OK; -} -#endif // FULL_BIDI_ENGINE
--- a/layout/base/nsBidi.h +++ b/layout/base/nsBidi.h @@ -44,24 +44,16 @@ */ /** * nsBidiLevel is the type of the level values in this * Bidi implementation. * It holds an embedding level and indicates the visual direction * by its bit 0 (even/odd value).<p> * - * It can also hold non-level values for the - * <code>aParaLevel</code> and <code>aEmbeddingLevels</code> - * arguments of <code>SetPara</code>; there: - * <ul> - * <li>bit 7 of an <code>aEmbeddingLevels[]</code> - * value indicates whether the using application is - * specifying the level of a character to <i>override</i> whatever the - * Bidi implementation would resolve it to.</li> * <li><code>aParaLevel</code> can be set to the * pseudo-level values <code>NSBIDI_DEFAULT_LTR</code> * and <code>NSBIDI_DEFAULT_RTL</code>.</li></ul> * * @see nsBidi::SetPara * * <p>The related constants are not real, valid level values. * <code>NSBIDI_DEFAULT_XXX</code> can be used to specify @@ -122,74 +114,38 @@ enum nsBidiDirection { /** All left-to-right text This is a 0 value. */ NSBIDI_LTR, /** All right-to-left text This is a 1 value. */ NSBIDI_RTL, /** Mixed-directional text. */ NSBIDI_MIXED }; -typedef enum nsBidiDirection nsBidiDirection; - /* miscellaneous definitions ------------------------------------------------ */ -/** option flags for WriteReverse() */ -/** - * option bit for WriteReverse(): - * keep combining characters after their base characters in RTL runs - * - * @see WriteReverse - */ -#define NSBIDI_KEEP_BASE_COMBINING 1 - -/** - * option bit for WriteReverse(): - * replace characters with the "mirrored" property in RTL runs - * by their mirror-image mappings - * - * @see WriteReverse - */ -#define NSBIDI_DO_MIRRORING 2 - -/** - * option bit for WriteReverse(): - * remove Bidi control characters - * - * @see WriteReverse - */ -#define NSBIDI_REMOVE_BIDI_CONTROLS 8 /* helper macros for each allocated array member */ -#define GETDIRPROPSMEMORY(length) \ - GetMemory((void **)&mDirPropsMemory, &mDirPropsSize, \ - mMayAllocateText, (length)) +#define GETDIRPROPSMEMORY(length) nsBidi::GetMemory((void **)&mDirPropsMemory, \ + &mDirPropsSize, \ + (length)) -#define GETLEVELSMEMORY(length) \ - GetMemory((void **)&mLevelsMemory, &mLevelsSize, \ - mMayAllocateText, (length)) - -#define GETRUNSMEMORY(length) \ - GetMemory((void **)&mRunsMemory, &mRunsSize, \ - mMayAllocateRuns, (length)*sizeof(Run)) +#define GETLEVELSMEMORY(length) nsBidi::GetMemory((void **)&mLevelsMemory, \ + &mLevelsSize, \ + (length)) -/* additional macros used by constructor - always allow allocation */ -#define GETINITIALDIRPROPSMEMORY(length) \ - GetMemory((void **)&mDirPropsMemory, &mDirPropsSize, \ - true, (length)) +#define GETRUNSMEMORY(length) nsBidi::GetMemory((void **)&mRunsMemory, \ + &mRunsSize, \ + (length)*sizeof(Run)) -#define GETINITIALLEVELSMEMORY(length) \ - GetMemory((void **)&mLevelsMemory, &mLevelsSize, \ - true, (length)) +#define GETISOLATESMEMORY(length) nsBidi::GetMemory((void **)&mIsolatesMemory, \ + &mIsolatesSize, \ + (length)*sizeof(Isolate)) -#define GETINITIALRUNSMEMORY(length) \ - GetMemory((void **)&mRunsMemory, &mRunsSize, \ - true, (length)*sizeof(Run)) - -#define GETINITIALISOLATESMEMORY(length) \ - GetMemory((void **)&mIsolatesMemory, &mIsolatesSize, \ - true, (length)*sizeof(Isolate)) +#define GETOPENINGSMEMORY(length) nsBidi::GetMemory((void **)&mOpeningsMemory, \ + &mOpeningsSize, \ + (length)*sizeof(Opening)) /* * Sometimes, bit values are more appropriate * to deal with directionality properties. * Abbreviations in these macro names refer to names * used in the Bidi algorithm. */ typedef uint8_t DirProp; @@ -229,33 +185,27 @@ typedef uint8_t DirProp; #define MASK_EMBEDDING (DIRPROP_FLAG(NSM)|MASK_POSSIBLE_N) /* the dirProp's L and R are defined to 0 and 1 values in nsCharType */ #define GET_LR_FROM_LEVEL(level) ((DirProp)((level)&1)) #define IS_DEFAULT_LEVEL(level) (((level)&0xfe)==0xfe) /* - * The following bit is ORed to the property of directional control - * characters which are ignored: unmatched PDF or PDI; LRx, RLx or FSI - * which would exceed the maximum explicit bidi level. - */ -#define IGNORE_CC 0x40 - -#define PURE_DIRPROP(prop) ((prop)&~IGNORE_CC) - -/* * The following bit is used for the directional isolate status. * Stack entries corresponding to isolate sequences are greater than ISOLATE. */ #define ISOLATE 0x0100 /* number of isolate entries allocated initially without malloc */ #define SIMPLE_ISOLATES_SIZE 5 +/* number of isolate run entries for paired brackets allocated initially without malloc */ +#define SIMPLE_OPENINGS_COUNT 8 + /* handle surrogate pairs --------------------------------------------------- */ #define IS_FIRST_SURROGATE(uchar) (((uchar)&0xfc00)==0xd800) #define IS_SECOND_SURROGATE(uchar) (((uchar)&0xfc00)==0xdc00) /* get the UTF-32 value directly from the surrogate pseudo-characters */ #define SURROGATE_OFFSET ((0xd800<<10UL)+0xdc00-0x10000) #define GET_UTF_32(first, second) (((first)<<10UL)+(second)-SURROGATE_OFFSET) @@ -385,16 +335,42 @@ typedef uint8_t DirProp; #define UTF_APPEND_CHAR(s, i, length, c) UTF_APPEND_CHAR_SAFE(s, i, length, c) struct Isolate { int32_t start1; int16_t stateImp; int16_t state; }; +// For bracket matching + +#define FOUND_L DIRPROP_FLAG(L) +#define FOUND_R DIRPROP_FLAG(R) + +struct Opening { + int32_t position; /* position of opening bracket */ + int32_t match; /* matching char or -position of closing bracket */ + int32_t contextPos; /* position of last strong char found before opening */ + uint16_t flags; /* bits for L or R/AL found within the pair */ + DirProp contextDir; /* L or R according to last strong char before opening */ + uint8_t filler; /* to complete a nice multiple of 4 chars */ +}; + +struct IsoRun { + int32_t contextPos; /* position of char determining context */ + uint16_t start; /* index of first opening entry for this run */ + uint16_t limit; /* index after last opening entry for this run */ + nsBidiLevel level; /* level of this run */ + DirProp lastStrong; /* bidi class of last strong char found in this run */ + DirProp lastBase; /* bidi class of last base char found in this run */ + DirProp contextDir; /* L or R to use as context for following openings */ +}; + +class nsBidi; + /* Run structure for reordering --------------------------------------------- */ typedef struct Run { int32_t logicalStart; /* first character of the run; b31 indicates even/odd level */ int32_t visualLimit; /* last visual position of the run +1 */ } Run; /* in a Run, logicalStart will get this bit set if the run level is odd */ @@ -500,38 +476,18 @@ public: * If the function shall determine the paragraph level from the text, * then <code>aParaLevel</code> can be set to * either <code>NSBIDI_DEFAULT_LTR</code> * or <code>NSBIDI_DEFAULT_RTL</code>; * if there is no strongly typed character, then * the desired default is used (0 for LTR or 1 for RTL). * Any other value between 0 and <code>NSBIDI_MAX_EXPLICIT_LEVEL</code> is also valid, * with odd levels indicating RTL. - * - * @param aEmbeddingLevels (in) may be used to preset the embedding and override levels, - * ignoring characters like LRE and PDF in the text. - * A level overrides the directional property of its corresponding - * (same index) character if the level has the - * <code>NSBIDI_LEVEL_OVERRIDE</code> bit set.<p> - * Except for that bit, it must be - * <code>aParaLevel<=aEmbeddingLevels[]<=NSBIDI_MAX_EXPLICIT_LEVEL</code>.<p> - * <strong>Caution: </strong>A copy of this pointer, not of the levels, - * will be stored in the <code>nsBidi</code> object; - * the <code>aEmbeddingLevels</code> array must not be - * deallocated before the <code>nsBidi</code> object is destroyed or reused, - * and the <code>aEmbeddingLevels</code> - * should not be modified to avoid unexpected results on subsequent Bidi operations. - * However, the <code>SetPara</code> and - * <code>SetLine</code> functions may modify some or all of the levels.<p> - * After the <code>nsBidi</code> object is reused or destroyed, the caller - * must take care of the deallocation of the <code>aEmbeddingLevels</code> array.<p> - * <strong>The <code>aEmbeddingLevels</code> array must be - * at least <code>aLength</code> long.</strong> */ - nsresult SetPara(const char16_t *aText, int32_t aLength, nsBidiLevel aParaLevel, nsBidiLevel *aEmbeddingLevels); + nsresult SetPara(const char16_t *aText, int32_t aLength, nsBidiLevel aParaLevel); /** * Get the directionality of the text. * * @param aDirection receives a <code>NSBIDI_XXX</code> value that indicates if the entire text * represented by this object is unidirectional, * and which direction, or if it is mixed-directional. * @@ -543,83 +499,16 @@ public: * Get the paragraph level of the text. * * @param aParaLevel receives a <code>NSBIDI_XXX</code> value indicating the paragraph level * * @see nsBidiLevel */ nsresult GetParaLevel(nsBidiLevel* aParaLevel); -#ifdef FULL_BIDI_ENGINE - /** - * <code>SetLine</code> sets an <code>nsBidi</code> to - * contain the reordering information, especially the resolved levels, - * for all the characters in a line of text. This line of text is - * specified by referring to an <code>nsBidi</code> object representing - * this information for a paragraph of text, and by specifying - * a range of indexes in this paragraph.<p> - * In the new line object, the indexes will range from 0 to <code>aLimit-aStart</code>.<p> - * - * This is used after calling <code>SetPara</code> - * for a paragraph, and after line-breaking on that paragraph. - * It is not necessary if the paragraph is treated as a single line.<p> - * - * After line-breaking, rules (L1) and (L2) for the treatment of - * trailing WS and for reordering are performed on - * an <code>nsBidi</code> object that represents a line.<p> - * - * <strong>Important:</strong> the line <code>nsBidi</code> object shares data with - * <code>aParaBidi</code>. - * You must destroy or reuse this object before <code>aParaBidi</code>. - * In other words, you must destroy or reuse the <code>nsBidi</code> object for a line - * before the object for its parent paragraph. - * - * @param aParaBidi is the parent paragraph object. - * - * @param aStart is the line's first index into the paragraph text. - * - * @param aLimit is just behind the line's last index into the paragraph text - * (its last index +1).<br> - * It must be <code>0<=aStart<=aLimit<=</code>paragraph length. - * - * @see SetPara - */ - nsresult SetLine(const nsBidi* aParaBidi, int32_t aStart, int32_t aLimit); - - /** - * Get the length of the text. - * - * @param aLength receives the length of the text that the nsBidi object was created for. - */ - nsresult GetLength(int32_t* aLength); - - /** - * Get the level for one character. - * - * @param aCharIndex the index of a character. - * - * @param aLevel receives the level for the character at aCharIndex. - * - * @see nsBidiLevel - */ - nsresult GetLevelAt(int32_t aCharIndex, nsBidiLevel* aLevel); - - /** - * Get an array of levels for each character.<p> - * - * Note that this function may allocate memory under some - * circumstances, unlike <code>GetLevelAt</code>. - * - * @param aLevels receives a pointer to the levels array for the text, - * or <code>nullptr</code> if an error occurs. - * - * @see nsBidiLevel - */ - nsresult GetLevels(nsBidiLevel** aLevels); -#endif // FULL_BIDI_ENGINE /** * Get the bidirectional type for one character. * * @param aCharIndex the index of a character. * * @param aType receives the bidirectional type of the character at aCharIndex. */ nsresult GetCharTypeAt(int32_t aCharIndex, nsCharType* aType); @@ -702,102 +591,16 @@ public: * @endcode * * Note that in right-to-left runs, code like this places * modifier letters before base characters and second surrogates * before first ones. */ nsresult GetVisualRun(int32_t aRunIndex, int32_t* aLogicalStart, int32_t* aLength, nsBidiDirection* aDirection); -#ifdef FULL_BIDI_ENGINE - /** - * Get the visual position from a logical text position. - * If such a mapping is used many times on the same - * <code>nsBidi</code> object, then calling - * <code>GetLogicalMap</code> is more efficient.<p> - * - * Note that in right-to-left runs, this mapping places - * modifier letters before base characters and second surrogates - * before first ones. - * - * @param aLogicalIndex is the index of a character in the text. - * - * @param aVisualIndex will receive the visual position of this character. - * - * @see GetLogicalMap - * @see GetLogicalIndex - */ - nsresult GetVisualIndex(int32_t aLogicalIndex, int32_t* aVisualIndex); - - /** - * Get the logical text position from a visual position. - * If such a mapping is used many times on the same - * <code>nsBidi</code> object, then calling - * <code>GetVisualMap</code> is more efficient.<p> - * - * This is the inverse function to <code>GetVisualIndex</code>. - * - * @param aVisualIndex is the visual position of a character. - * - * @param aLogicalIndex will receive the index of this character in the text. - * - * @see GetVisualMap - * @see GetVisualIndex - */ - nsresult GetLogicalIndex(int32_t aVisualIndex, int32_t* aLogicalIndex); - - /** - * Get a logical-to-visual index map (array) for the characters in the nsBidi - * (paragraph or line) object. - *