diff --git a/b2g/app/b2g.js b/b2g/app/b2g.js index 20d75e6ce2cd..ee262519c76f 100644 --- a/b2g/app/b2g.js +++ b/b2g/app/b2g.js @@ -186,7 +186,8 @@ pref("privacy.item.siteSettings", true); pref("privacy.item.syncAccount", true); // base url for the wifi geolocation network provider -pref("geo.wifi.uri", "https://maps.googleapis.com/maps/api/browserlocation/json"); +pref("geo.provider.use_mls", false); +pref("geo.wifi.uri", "https://location.services.mozilla.com/v1/geolocate?key=%MOZILLA_API_KEY%"); // enable geo pref("geo.enabled", true); diff --git a/b2g/config/emulator-ics/sources.xml b/b2g/config/emulator-ics/sources.xml index a538167704a1..fdc91885b4ba 100644 --- a/b2g/config/emulator-ics/sources.xml +++ b/b2g/config/emulator-ics/sources.xml @@ -19,7 +19,7 @@ - + diff --git a/b2g/config/emulator-jb/sources.xml b/b2g/config/emulator-jb/sources.xml index a823a4355641..921ae49afd1f 100644 --- a/b2g/config/emulator-jb/sources.xml +++ b/b2g/config/emulator-jb/sources.xml @@ -17,7 +17,7 @@ - + diff --git a/b2g/config/emulator/sources.xml b/b2g/config/emulator/sources.xml index a538167704a1..fdc91885b4ba 100644 --- a/b2g/config/emulator/sources.xml +++ b/b2g/config/emulator/sources.xml @@ -19,7 +19,7 @@ - + diff --git a/b2g/config/gaia.json b/b2g/config/gaia.json index 540d3fb91652..ece5c7e6230a 100644 --- a/b2g/config/gaia.json +++ b/b2g/config/gaia.json @@ -4,6 +4,6 @@ "branch": "", "revision": "" }, - "revision": "d0ed050535c3a5337c09c0de720de78954a42f31", + "revision": "3d294ffa51afd8a8daafcdaa97cda8e38de81cb8", "repo_path": "/integration/gaia-central" } diff --git a/b2g/config/hamachi/sources.xml b/b2g/config/hamachi/sources.xml index 1e17bc13b5d6..ea35e19c1397 100644 --- a/b2g/config/hamachi/sources.xml +++ b/b2g/config/hamachi/sources.xml @@ -17,7 +17,7 @@ - + @@ -96,7 +96,7 @@ - + diff --git a/b2g/config/helix/sources.xml b/b2g/config/helix/sources.xml index 9dacc2d80458..6c781f868bca 100644 --- a/b2g/config/helix/sources.xml +++ b/b2g/config/helix/sources.xml @@ -15,7 +15,7 @@ - + diff --git a/b2g/config/inari/sources.xml b/b2g/config/inari/sources.xml index 3355fcdff84e..874a55758f0b 100644 --- a/b2g/config/inari/sources.xml +++ b/b2g/config/inari/sources.xml @@ -19,7 +19,7 @@ - + diff --git a/b2g/config/leo/sources.xml b/b2g/config/leo/sources.xml index 18b2d7e5781e..8a2daca9c8a9 100644 --- a/b2g/config/leo/sources.xml +++ b/b2g/config/leo/sources.xml @@ -17,7 +17,7 @@ - + diff --git a/b2g/config/mako/sources.xml b/b2g/config/mako/sources.xml index f5e8228f9793..2c7bf418e310 100644 --- a/b2g/config/mako/sources.xml +++ b/b2g/config/mako/sources.xml @@ -17,7 +17,7 @@ - + diff --git a/b2g/config/wasabi/sources.xml b/b2g/config/wasabi/sources.xml index eb72db1ccba8..bd8374314906 100644 --- a/b2g/config/wasabi/sources.xml +++ b/b2g/config/wasabi/sources.xml @@ -17,7 +17,7 @@ - + diff --git a/b2g/installer/package-manifest.in b/b2g/installer/package-manifest.in index ca15b8fe20b4..4a8ea6286ebb 100644 --- a/b2g/installer/package-manifest.in +++ b/b2g/installer/package-manifest.in @@ -375,6 +375,8 @@ @BINPATH@/components/nsLoginInfo.js @BINPATH@/components/nsLoginManager.js @BINPATH@/components/nsLoginManagerPrompter.js +@BINPATH@/components/NetworkGeolocationProvider.manifest +@BINPATH@/components/NetworkGeolocationProvider.js #ifdef MOZ_WEBRTC @BINPATH@/components/PeerConnection.js @BINPATH@/components/PeerConnection.manifest diff --git a/browser/base/content/tabbrowser.xml b/browser/base/content/tabbrowser.xml index 5d1f17844abb..3582c3df4502 100644 --- a/browser/base/content/tabbrowser.xml +++ b/browser/base/content/tabbrowser.xml @@ -2998,10 +2998,9 @@ gContextMenuContentData = { event: aMessage.objects.event, browser: browser }; let popup = browser.ownerDocument.getElementById("contentAreaContextMenu"); - popup.openPopup(browser, "overlap", - gContextMenuContentData.event.clientX, - gContextMenuContentData.event.clientY, - true, false, null); + let event = gContextMenuContentData.event; + let pos = browser.mapScreenCoordinatesFromContent(event.screenX, event.screenY); + popup.openPopupAtScreen(pos.x, pos.y, true); break; } case "DOMWebNotificationClicked": { @@ -3998,6 +3997,10 @@ PrivateBrowsingUtils.isWindowPrivate(sourceNode.ownerDocument.defaultView)) return dt.effectAllowed = "none"; + if (window.gMultiProcessBrowser != + sourceNode.ownerDocument.defaultView.gMultiProcessBrowser) + return dt.effectAllowed = "none"; + #ifdef XP_MACOSX return dt.effectAllowed = event.altKey ? "copy" : "move"; #else diff --git a/browser/base/content/test/general/browser.ini b/browser/base/content/test/general/browser.ini index 165ae6e35f03..aae3d6c517c8 100644 --- a/browser/base/content/test/general/browser.ini +++ b/browser/base/content/test/general/browser.ini @@ -16,6 +16,7 @@ support-files = browser_clearplugindata.html browser_clearplugindata_noage.html browser_registerProtocolHandler_notification.html + browser_star_hsts.sjs browser_tab_dragdrop2_frame1.xul bug564387.html bug564387_video1.ogv @@ -321,6 +322,7 @@ skip-if = os == "linux" # bug 857427 [browser_save_video.js] [browser_scope.js] [browser_selectTabAtIndex.js] +[browser_star_hsts.js] [browser_subframe_favicons_not_used.js] [browser_tabDrop.js] [browser_tabMatchesInAwesomebar_perwindowpb.js] diff --git a/browser/base/content/test/general/browser_star_hsts.js b/browser/base/content/test/general/browser_star_hsts.js new file mode 100644 index 000000000000..db6704e28c92 --- /dev/null +++ b/browser/base/content/test/general/browser_star_hsts.js @@ -0,0 +1,114 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +let secureURL = "https://example.com/browser/browser/base/content/test/general/browser_star_hsts.sjs"; +let unsecureURL = "http://example.com/browser/browser/base/content/test/general/browser_star_hsts.sjs"; + +add_task(function* test_star_redirect() { + registerCleanupFunction(function() { + // Ensure to remove example.com from the HSTS list. + let sss = Cc["@mozilla.org/ssservice;1"] + .getService(Ci.nsISiteSecurityService); + sss.removeState(Ci.nsISiteSecurityService.HEADER_HSTS, + NetUtil.newURI("http://example.com/"), 0); + PlacesUtils.bookmarks.removeFolderChildren(PlacesUtils.unfiledBookmarksFolderId); + gBrowser.removeCurrentTab(); + }); + + let tab = gBrowser.selectedTab = gBrowser.addTab(); + // This will add the page to the HSTS cache. + yield promiseTabLoadEvent(tab, secureURL, secureURL); + // This should transparently be redirected to the secure page. + yield promiseTabLoadEvent(tab, unsecureURL, secureURL); + + yield promiseStarState(BookmarkingUI.STATUS_UNSTARRED); + + let promiseBookmark = promiseOnItemAdded(gBrowser.currentURI); + BookmarkingUI.star.click(); + // This resolves on the next tick, so the star should have already been + // updated at that point. + yield promiseBookmark; + + is(BookmarkingUI.status, BookmarkingUI.STATUS_STARRED, "The star is starred"); +}); + +/** + * Waits for the star to reflect the expected state. + */ +function promiseStarState(aValue) { + let deferred = Promise.defer(); + let expectedStatus = aValue ? BookmarkingUI.STATUS_STARRED + : BookmarkingUI.STATUS_UNSTARRED; + (function checkState() { + if (BookmarkingUI.status == BookmarkingUI.STATUS_UPDATING || + BookmarkingUI.status != expectedStatus) { + info("Waiting for star button change."); + setTimeout(checkState, 1000); + } else { + deferred.resolve(); + } + })(); + return deferred.promise; +} + +/** + * Starts a load in an existing tab and waits for it to finish (via some event). + * + * @param aTab + * The tab to load into. + * @param aUrl + * The url to load. + * @param [optional] aFinalURL + * The url to wait for, same as aURL if not defined. + * @return {Promise} resolved when the event is handled. + */ +function promiseTabLoadEvent(aTab, aURL, aFinalURL) +{ + if (!aFinalURL) + aFinalURL = aURL; + let deferred = Promise.defer(); + info("Wait for load tab event"); + aTab.linkedBrowser.addEventListener("load", function load(event) { + if (event.originalTarget != aTab.linkedBrowser.contentDocument || + event.target.location.href == "about:blank" || + event.target.location.href != aFinalURL) { + info("skipping spurious load event"); + return; + } + aTab.linkedBrowser.removeEventListener("load", load, true); + info("Tab load event received"); + deferred.resolve(); + }, true, true); + aTab.linkedBrowser.loadURI(aURL); + return deferred.promise; +} + +/** + * Waits for a bookmark to be added for the given uri. + */ +function promiseOnItemAdded(aExpectedURI) { + let defer = Promise.defer(); + let bookmarksObserver = { + onItemAdded: function (aItemId, aFolderId, aIndex, aItemType, aURI) { + info("Added a bookmark to " + aURI.spec); + PlacesUtils.bookmarks.removeObserver(bookmarksObserver); + if (aURI.equals(aExpectedURI)) + defer.resolve(); + else + defer.reject(new Error("Added an unexpected bookmark")); + }, + onBeginUpdateBatch: function () {}, + onEndUpdateBatch: function () {}, + onItemRemoved: function () {}, + onItemChanged: function () {}, + onItemVisited: function () {}, + onItemMoved: function () {}, + QueryInterface: XPCOMUtils.generateQI([ + Ci.nsINavBookmarkObserver, + ]) + }; + info("Waiting for a bookmark to be added"); + PlacesUtils.bookmarks.addObserver(bookmarksObserver, false); + return defer.promise; +} diff --git a/browser/base/content/test/general/browser_star_hsts.sjs b/browser/base/content/test/general/browser_star_hsts.sjs new file mode 100644 index 000000000000..10c7aae12894 --- /dev/null +++ b/browser/base/content/test/general/browser_star_hsts.sjs @@ -0,0 +1,13 @@ +/* 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/. */ + +function handleRequest(request, response) +{ + let page = "

HSTS page

"; + response.setStatusLine(request.httpVersion, "200", "OK"); + response.setHeader("Strict-Transport-Security", "max-age=60"); + response.setHeader("Content-Type", "text/html", false); + response.setHeader("Content-Length", page.length + "", false); + response.write(page); +} diff --git a/config/config.mk b/config/config.mk index dabe7e98de48..d9cbe86e4b08 100644 --- a/config/config.mk +++ b/config/config.mk @@ -841,7 +841,7 @@ OBJ_SUFFIX := $(_OBJ_SUFFIX) # PGO builds with GCC build objects with instrumentation in a first pass, # then objects optimized, without instrumentation, in a second pass. If -# we overwrite the ojects from the first pass with those from the second, +# we overwrite the objects from the first pass with those from the second, # we end up not getting instrumentation data for better optimization on # incremental builds. As a consequence, we use a different object suffix # for the first pass. diff --git a/configure.in b/configure.in index 62c4c6d6dbe7..7bdc6c4a332a 100644 --- a/configure.in +++ b/configure.in @@ -60,7 +60,7 @@ dnl ======================================================== GLIB_VERSION=1.2.0 PERL_VERSION=5.006 CAIRO_VERSION=1.10 -PANGO_VERSION=1.14.0 +PANGO_VERSION=1.22.0 GTK2_VERSION=2.10.0 GTK3_VERSION=3.0.0 WINDRES_VERSION=2.14.90 @@ -251,10 +251,13 @@ if test -n "$gonkdir" ; then 19) GONK_INCLUDES="-I$gonkdir/frameworks/native/include -I$gonkdir/frameworks/av/include -I$gonkdir/frameworks/av/include/media -I$gonkdir/frameworks/av/include/camera -I$gonkdir/frameworks/native/include/media/openmax -I$gonkdir/frameworks/av/media/libstagefright/include" MOZ_B2G_CAMERA=1 - MOZ_OMX_DECODER=1 MOZ_B2G_BT=1 MOZ_B2G_BT_BLUEDROID=1 MOZ_NFC=1 + MOZ_RTSP=1 + MOZ_OMX_DECODER=1 + MOZ_OMX_ENCODER=1 + AC_DEFINE(MOZ_OMX_ENCODER) ;; *) @@ -4050,6 +4053,16 @@ fi AC_DEFINE_UNQUOTED(MOZ_UPDATE_CHANNEL, $MOZ_UPDATE_CHANNEL) AC_SUBST(MOZ_UPDATE_CHANNEL) +# Allow to specify a Mozilla API key file that contains the secret key to be +# used for various Mozilla API requests. +MOZ_ARG_WITH_STRING(mozilla-api-keyfile, +[ --with-mozilla-api-keyfile=file Use the secret key contained in the given keyfile for Mozilla API requests], + MOZ_MOZILLA_API_KEY=`cat $withval`) +if test -z "$MOZ_MOZILLA_API_KEY"; then + MOZ_MOZILLA_API_KEY=no-mozilla-api-key +fi +AC_SUBST(MOZ_MOZILLA_API_KEY) + # Allow to specify a Google API key file that contains the secret key to be # used for various Google API requests. MOZ_ARG_WITH_STRING(google-api-keyfile, diff --git a/content/base/src/nsDocument.cpp b/content/base/src/nsDocument.cpp index ed58b331f671..5ca6309e7543 100644 --- a/content/base/src/nsDocument.cpp +++ b/content/base/src/nsDocument.cpp @@ -963,7 +963,7 @@ TransferZoomLevels(nsIDocument* aFromDoc, return; toCtxt->SetFullZoom(fromCtxt->GetFullZoom()); - toCtxt->SetMinFontSize(fromCtxt->MinFontSize(nullptr)); + toCtxt->SetBaseMinFontSize(fromCtxt->BaseMinFontSize()); toCtxt->SetTextZoom(fromCtxt->TextZoom()); } diff --git a/content/canvas/src/WebGLContextGL.cpp b/content/canvas/src/WebGLContextGL.cpp index b9c7ca9c32e6..354cec2389ba 100644 --- a/content/canvas/src/WebGLContextGL.cpp +++ b/content/canvas/src/WebGLContextGL.cpp @@ -508,8 +508,16 @@ WebGLContext::CopyTexImage2D(GLenum target, return; } - if (mBoundFramebuffer && !mBoundFramebuffer->CheckAndInitializeAttachments()) - return ErrorInvalidFramebufferOperation("copyTexImage2D: incomplete framebuffer"); + if (mBoundFramebuffer) { + if (!mBoundFramebuffer->CheckAndInitializeAttachments()) + return ErrorInvalidFramebufferOperation("copyTexImage2D: incomplete framebuffer"); + + GLenum readPlaneBits = LOCAL_GL_COLOR_BUFFER_BIT; + if (!mBoundFramebuffer->HasCompletePlanes(readPlaneBits)) { + return ErrorInvalidOperation("copyTexImage2D: Read source attachment doesn't have the" + " correct color/depth/stencil type."); + } + } bool texFormatRequiresAlpha = internalformat == LOCAL_GL_RGBA || internalformat == LOCAL_GL_ALPHA || @@ -613,10 +621,17 @@ WebGLContext::CopyTexSubImage2D(GLenum target, return ErrorInvalidOperation("copyTexSubImage2D: a base internal format of DEPTH_COMPONENT or DEPTH_STENCIL isn't supported"); } - if (mBoundFramebuffer) + if (mBoundFramebuffer) { if (!mBoundFramebuffer->CheckAndInitializeAttachments()) return ErrorInvalidFramebufferOperation("copyTexSubImage2D: incomplete framebuffer"); + GLenum readPlaneBits = LOCAL_GL_COLOR_BUFFER_BIT; + if (!mBoundFramebuffer->HasCompletePlanes(readPlaneBits)) { + return ErrorInvalidOperation("copyTexSubImage2D: Read source attachment doesn't have the" + " correct color/depth/stencil type."); + } + } + bool texFormatRequiresAlpha = (internalFormat == LOCAL_GL_RGBA || internalFormat == LOCAL_GL_ALPHA || internalFormat == LOCAL_GL_LUMINANCE_ALPHA); @@ -2307,6 +2322,12 @@ WebGLContext::ReadPixels(GLint x, GLint y, GLsizei width, // prevent readback of arbitrary video memory through uninitialized renderbuffers! if (!mBoundFramebuffer->CheckAndInitializeAttachments()) return ErrorInvalidFramebufferOperation("readPixels: incomplete framebuffer"); + + GLenum readPlaneBits = LOCAL_GL_COLOR_BUFFER_BIT; + if (!mBoundFramebuffer->HasCompletePlanes(readPlaneBits)) { + return ErrorInvalidOperation("readPixels: Read source attachment doesn't have the" + " correct color/depth/stencil type."); + } } // Now that the errors are out of the way, on to actually reading diff --git a/content/canvas/src/WebGLFramebuffer.cpp b/content/canvas/src/WebGLFramebuffer.cpp index 645561cabdeb..92f0ef7ec200 100644 --- a/content/canvas/src/WebGLFramebuffer.cpp +++ b/content/canvas/src/WebGLFramebuffer.cpp @@ -630,6 +630,31 @@ WebGLFramebuffer::CheckFramebufferStatus() const return mContext->gl->fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER); } +bool +WebGLFramebuffer::HasCompletePlanes(GLbitfield mask) +{ + if (CheckFramebufferStatus() != LOCAL_GL_FRAMEBUFFER_COMPLETE) + return false; + + MOZ_ASSERT(mContext->mBoundFramebuffer == this); + bool hasPlanes = true; + if (mask & LOCAL_GL_COLOR_BUFFER_BIT) { + hasPlanes &= ColorAttachmentCount() && + ColorAttachment(0).IsDefined(); + } + + if (mask & LOCAL_GL_DEPTH_BUFFER_BIT) { + hasPlanes &= DepthAttachment().IsDefined() || + DepthStencilAttachment().IsDefined(); + } + + if (mask & LOCAL_GL_STENCIL_BUFFER_BIT) { + hasPlanes &= StencilAttachment().IsDefined() || + DepthStencilAttachment().IsDefined(); + } + + return hasPlanes; +} bool WebGLFramebuffer::CheckAndInitializeAttachments() diff --git a/content/canvas/src/WebGLFramebuffer.h b/content/canvas/src/WebGLFramebuffer.h index 282f36ae5a04..8634534882d0 100644 --- a/content/canvas/src/WebGLFramebuffer.h +++ b/content/canvas/src/WebGLFramebuffer.h @@ -166,6 +166,9 @@ public: NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLFramebuffer) NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(WebGLFramebuffer) + // mask mirrors glClear. + bool HasCompletePlanes(GLbitfield mask); + bool CheckAndInitializeAttachments(); bool CheckColorAttachmentNumber(GLenum attachment, const char* functionName) const; diff --git a/content/canvas/test/webgl/non-conf-tests/mochitest.ini b/content/canvas/test/webgl/non-conf-tests/mochitest.ini index 91b8c2986def..1c31862f2c4c 100644 --- a/content/canvas/test/webgl/non-conf-tests/mochitest.ini +++ b/content/canvas/test/webgl/non-conf-tests/mochitest.ini @@ -3,6 +3,7 @@ support-files = driver-info.js webgl-util.js +[test_depth_readpixels.html] [test_highp_fs.html] [test_no_arr_points.html] [test_privileged_exts.html] diff --git a/content/canvas/test/webgl/non-conf-tests/test_depth_readpixels.html b/content/canvas/test/webgl/non-conf-tests/test_depth_readpixels.html new file mode 100644 index 000000000000..e82ef42901c3 --- /dev/null +++ b/content/canvas/test/webgl/non-conf-tests/test_depth_readpixels.html @@ -0,0 +1,61 @@ + + + +WebGL test: Check for error on ReadPixels from a depth-only FB. + + + + + + + + + + + diff --git a/content/html/content/src/HTMLBRElement.cpp b/content/html/content/src/HTMLBRElement.cpp index cd24478b595d..562ce318d814 100644 --- a/content/html/content/src/HTMLBRElement.cpp +++ b/content/html/content/src/HTMLBRElement.cpp @@ -37,8 +37,8 @@ NS_IMPL_STRING_ATTR(HTMLBRElement, Clear, clear) static const nsAttrValue::EnumTable kClearTable[] = { { "left", NS_STYLE_CLEAR_LEFT }, { "right", NS_STYLE_CLEAR_RIGHT }, - { "all", NS_STYLE_CLEAR_LEFT_AND_RIGHT }, - { "both", NS_STYLE_CLEAR_LEFT_AND_RIGHT }, + { "all", NS_STYLE_CLEAR_BOTH }, + { "both", NS_STYLE_CLEAR_BOTH }, { 0 } }; diff --git a/content/html/content/src/HTMLInputElement.cpp b/content/html/content/src/HTMLInputElement.cpp index 72d17e45da2e..38f663c3a25b 100644 --- a/content/html/content/src/HTMLInputElement.cpp +++ b/content/html/content/src/HTMLInputElement.cpp @@ -20,6 +20,7 @@ #include "nsIControllers.h" #include "nsIStringBundle.h" #include "nsFocusManager.h" +#include "nsColorControlFrame.h" #include "nsNumberControlFrame.h" #include "nsPIDOMWindow.h" #include "nsRepeatService.h" @@ -2805,12 +2806,12 @@ HTMLInputElement::SetValueInternal(const nsAString& aValue, OnValueChanged(!mParserCreating); } - // Call parent's SetAttr for color input so its control frame is notified - // and updated if (mType == NS_FORM_INPUT_COLOR) { - return nsGenericHTMLFormElement::SetAttr(kNameSpaceID_None, - nsGkAtoms::value, aValue, - true); + // Update color frame, to reflect color changes + nsColorControlFrame* colorControlFrame = do_QueryFrame(GetPrimaryFrame()); + if (colorControlFrame) { + colorControlFrame->UpdateColor(); + } } return NS_OK; diff --git a/content/html/content/test/forms/mochitest.ini b/content/html/content/test/forms/mochitest.ini index 7c438cb44132..e0b7291a7c9c 100644 --- a/content/html/content/test/forms/mochitest.ini +++ b/content/html/content/test/forms/mochitest.ini @@ -20,6 +20,7 @@ support-files = [test_input_color_picker_initial.html] [test_input_color_picker_popup.html] [test_input_color_picker_update.html] +[test_input_defaultValue.html] [test_input_email.html] [test_input_event.html] [test_input_file_picker.html] diff --git a/content/html/content/test/forms/test_input_defaultValue.html b/content/html/content/test/forms/test_input_defaultValue.html new file mode 100644 index 000000000000..53d2dd43a9c1 --- /dev/null +++ b/content/html/content/test/forms/test_input_defaultValue.html @@ -0,0 +1,81 @@ + + + + + Test for Bug 977029 + + + +
+ Bug 977029 +

+ Goal of this test is to check that modifying defaultValue and value attribute + of input types is working as expected. +

+
+ + + + + + + + + + +
+
+ + + + diff --git a/content/media/MediaDecoderStateMachine.cpp b/content/media/MediaDecoderStateMachine.cpp index c5ae7d08c663..f2e3449484fc 100644 --- a/content/media/MediaDecoderStateMachine.cpp +++ b/content/media/MediaDecoderStateMachine.cpp @@ -2449,6 +2449,15 @@ void MediaDecoderStateMachine::StartBuffering() { AssertCurrentThreadInMonitor(); + if (mState != DECODER_STATE_DECODING) { + // We only move into BUFFERING state if we're actually decoding. + // If we're currently doing something else, we don't need to buffer, + // and more importantly, we shouldn't overwrite mState to interrupt + // the current operation, as that could leave us in an inconsistent + // state! + return; + } + if (IsPlaying()) { StopPlayback(); } diff --git a/content/media/MediaResource.cpp b/content/media/MediaResource.cpp index eb83fb0a7ce3..79517bc2ceef 100644 --- a/content/media/MediaResource.cpp +++ b/content/media/MediaResource.cpp @@ -1643,6 +1643,9 @@ public: void BaseMediaResource::DispatchBytesConsumed(int64_t aNumBytes, int64_t aOffset) { + if (aNumBytes <= 0) { + return; + } RefPtr event(new DispatchBytesConsumedEvent(mDecoder, aNumBytes, aOffset)); NS_DispatchToMainThread(event, NS_DISPATCH_NORMAL); } diff --git a/content/media/directshow/DirectShowReader.cpp b/content/media/directshow/DirectShowReader.cpp index e9760ecb5585..bafd3f83026f 100644 --- a/content/media/directshow/DirectShowReader.cpp +++ b/content/media/directshow/DirectShowReader.cpp @@ -84,6 +84,11 @@ ParseMP3Headers(MP3FrameParser *aParser, MediaResource *aResource) MAX_READ_SIZE, &bytesRead); NS_ENSURE_SUCCESS(rv, rv); + if (!bytesRead) { + // End of stream. + return NS_ERROR_FAILURE; + } + aParser->Parse(buffer, bytesRead, offset); offset += bytesRead; } diff --git a/docshell/base/moz.build b/docshell/base/moz.build index f5a398b51912..2fe80c744f23 100644 --- a/docshell/base/moz.build +++ b/docshell/base/moz.build @@ -37,6 +37,7 @@ XPIDL_MODULE = 'docshell' EXPORTS += [ 'nsDocShellLoadTypes.h', 'nsILinkHandler.h', + 'nsIScrollObserver.h', 'nsIWebShellServices.h', 'SerializedLoadContext.h', ] diff --git a/docshell/base/nsDocShell.cpp b/docshell/base/nsDocShell.cpp index 732f61ae7d56..91e2e37a73a7 100644 --- a/docshell/base/nsDocShell.cpp +++ b/docshell/base/nsDocShell.cpp @@ -67,6 +67,7 @@ #include "nsITimedChannel.h" #include "nsIPrivacyTransitionObserver.h" #include "nsIReflowObserver.h" +#include "nsIScrollObserver.h" #include "nsIDocShellTreeItem.h" #include "nsIChannel.h" #include "IHistory.h" @@ -2857,6 +2858,39 @@ nsDocShell::GetCurrentDocChannel() return nullptr; } +NS_IMETHODIMP +nsDocShell::AddWeakScrollObserver(nsIScrollObserver* aObserver) +{ + nsWeakPtr weakObs = do_GetWeakReference(aObserver); + if (!weakObs) { + return NS_ERROR_FAILURE; + } + return mScrollObservers.AppendElement(weakObs) ? NS_OK : NS_ERROR_FAILURE; +} + +NS_IMETHODIMP +nsDocShell::RemoveWeakScrollObserver(nsIScrollObserver* aObserver) +{ + nsWeakPtr obs = do_GetWeakReference(aObserver); + return mScrollObservers.RemoveElement(obs) ? NS_OK : NS_ERROR_FAILURE; +} + +NS_IMETHODIMP +nsDocShell::NotifyScrollObservers() +{ + nsTObserverArray::ForwardIterator iter(mScrollObservers); + while (iter.HasMore()) { + nsWeakPtr ref = iter.GetNext(); + nsCOMPtr obs = do_QueryReferent(ref); + if (obs) { + obs->ScrollPositionChanged(); + } else { + mScrollObservers.RemoveElement(ref); + } + } + return NS_OK; +} + //***************************************************************************** // nsDocShell::nsIDocShellTreeItem //***************************************************************************** @@ -9280,19 +9314,6 @@ nsDocShell::InternalLoad(nsIURI * aURI, sameExceptHashes && !newHash.IsEmpty()); if (doShortCircuitedLoad) { - // Cancel an outstanding new-document load if this is a history - // load. - // - // We can't cancel the oustanding load unconditionally, because if a - // page does - // - load a.html - // - start loading b.html - // - load a.html#h - // we break the web if we cancel the load of b.html. - if (aSHEntry && mDocumentRequest) { - mDocumentRequest->Cancel(NS_BINDING_ABORTED); - } - // Save the position of the scrollers. nscoord cx = 0, cy = 0; GetCurScrollPos(ScrollOrientation_X, &cx); @@ -9324,6 +9345,8 @@ nsDocShell::InternalLoad(nsIURI * aURI, mURIResultedInDocument = true; + nsCOMPtr oldLSHE = mLSHE; + /* we need to assign mLSHE to aSHEntry right here, so that on History loads, * SetCurrentURI() called from OnNewURI() will send proper * onLocationChange() notifications to the browser to update @@ -9401,10 +9424,10 @@ nsDocShell::InternalLoad(nsIURI * aURI, SetCurScrollPosEx(bx, by); } - /* Clear out mLSHE so that further anchor visits get - * recorded in SH and SH won't misbehave. + /* Restore the original LSHE if we were loading something + * while short-circuited load was initiated. */ - SetHistoryEntry(&mLSHE, nullptr); + SetHistoryEntry(&mLSHE, oldLSHE); /* Set the title for the SH entry for this target url. so that * SH menus in go/back/forward buttons won't be empty for this. */ diff --git a/docshell/base/nsDocShell.h b/docshell/base/nsDocShell.h index 83ac34f86588..c19177742107 100644 --- a/docshell/base/nsDocShell.h +++ b/docshell/base/nsDocShell.h @@ -900,6 +900,7 @@ private: nsCOMPtr mParentCharsetPrincipal; nsTObserverArray mPrivacyObservers; nsTObserverArray mReflowObservers; + nsTObserverArray mScrollObservers; nsCString mOriginalUriString; // Separate function to do the actual name (i.e. not _top, _self etc.) diff --git a/docshell/base/nsIDocShell.idl b/docshell/base/nsIDocShell.idl index 1a9cf2bccf9c..ed323c903d65 100644 --- a/docshell/base/nsIDocShell.idl +++ b/docshell/base/nsIDocShell.idl @@ -41,10 +41,11 @@ interface nsIWebBrowserPrint; interface nsIVariant; interface nsIPrivacyTransitionObserver; interface nsIReflowObserver; +interface nsIScrollObserver; typedef unsigned long nsLoadFlags; -[scriptable, builtinclass, uuid(d0eaef67-4234-47de-b05a-9c7b324eb4f4)] +[scriptable, builtinclass, uuid(e46d924d-c20f-4add-8cf5-1e1c817b2181)] interface nsIDocShell : nsIDocShellTreeItem { /** @@ -667,6 +668,24 @@ interface nsIDocShell : nsIDocShellTreeItem in DOMHighResTimeStamp start, in DOMHighResTimeStamp end); + /** + * Add an observer to the list of parties to be notified when scroll position + * of some elements is changed. + */ + [noscript] void addWeakScrollObserver(in nsIScrollObserver obs); + + /** + * Add an observer to the list of parties to be notified when scroll position + * of some elements is changed. + */ + [noscript] void removeWeakScrollObserver(in nsIScrollObserver obs); + + /** + * Notify all attached observers that the scroll position of some element + * has changed. + */ + [noscript] void notifyScrollObservers(); + /** * Returns true if this docshell corresponds to an + + diff --git a/docshell/test/navigation/mochitest.ini b/docshell/test/navigation/mochitest.ini index 29089c210c66..900c2072d216 100644 --- a/docshell/test/navigation/mochitest.ini +++ b/docshell/test/navigation/mochitest.ini @@ -8,6 +8,7 @@ support-files = file_bug508537_1.html file_bug534178.html file_document_write_1.html + file_fragment_handling_during_load.html file_static_and_dynamic_1.html frame0.html frame1.html diff --git a/docshell/test/navigation/test_sessionhistory.html b/docshell/test/navigation/test_sessionhistory.html index a9ee9ec82d38..c33df365e192 100644 --- a/docshell/test/navigation/test_sessionhistory.html +++ b/docshell/test/navigation/test_sessionhistory.html @@ -26,7 +26,8 @@ var testFiles = "file_bug508537_1.html", // Dynamic frames and forward-back "file_document_write_1.html", // Session history + document.write "file_static_and_dynamic_1.html",// Static and dynamic frames and forward-back - "file_bug534178.html" // Session history transaction clean-up. + "file_bug534178.html", // Session history transaction clean-up. + "file_fragment_handling_during_load.html" ]; var testCount = 0; // Used by the test files. diff --git a/dom/apps/src/AppsServiceChild.jsm b/dom/apps/src/AppsServiceChild.jsm index 0ae273c931a9..fb27f060d752 100644 --- a/dom/apps/src/AppsServiceChild.jsm +++ b/dom/apps/src/AppsServiceChild.jsm @@ -8,10 +8,10 @@ const Cu = Components.utils; const Cc = Components.classes; const Ci = Components.interfaces; -// This module exposes a subset of the functionalities of the parent DOM -// Registry to content processes, to be used from the AppsService component. +// This module exposes a subset of the functionnalities of the parent DOM +// Registry to content processes, to be be used from the AppsService component. -this.EXPORTED_SYMBOLS = ["DOMApplicationRegistry", "WrappedManifestCache"]; +this.EXPORTED_SYMBOLS = ["DOMApplicationRegistry"]; Cu.import("resource://gre/modules/AppsUtils.jsm"); Cu.import("resource://gre/modules/Services.jsm"); @@ -20,265 +20,54 @@ function debug(s) { //dump("-*- AppsServiceChild.jsm: " + s + "\n"); } -const APPS_IPC_MSG_NAMES = [ - "Webapps:AddApp", - "Webapps:RemoveApp", - "Webapps:CheckForUpdate:Return:KO", - "Webapps:FireEvent", - "Webapps:UpdateState" -]; - -// A simple cache for the wrapped manifests. -this.WrappedManifestCache = { - _cache: { }, - - // Gets an entry from the cache, and populates the cache if needed. - get: function mcache_get(aManifestURL, aManifest, aWindow, aInnerWindowID) { - if (!(aManifestURL in this._cache)) { - this._cache[aManifestURL] = { }; - } - - let winObjs = this._cache[aManifestURL]; - if (!(aInnerWindowID in winObjs)) { - winObjs[aInnerWindowID] = Cu.cloneInto(aManifest, aWindow); - } - - return winObjs[aInnerWindowID]; - }, - - // Invalidates an entry in the cache. - evict: function mcache_evict(aManifestURL, aInnerWindowID) { - debug("Evicting manifest " + aManifestURL + " window ID " + - aInnerWindowID); - if (aManifestURL in this._cache) { - let winObjs = this._cache[aManifestURL]; - if (aInnerWindowID in winObjs) { - delete winObjs[aInnerWindowID]; - } - - if (Object.keys(winObjs).length == 0) { - delete this._cache[aManifestURL]; - } - } - }, - - observe: function(aSubject, aTopic, aData) { - // Clear the cache on memory pressure. - this._cache = { }; - Cu.forceGC(); - }, - - init: function() { - Services.obs.addObserver(this, "memory-pressure", false); - } -}; - -this.WrappedManifestCache.init(); - - -// DOMApplicationRegistry keeps a cache containing a list of apps in the device. -// This information is updated with the data received from the main process and -// it is queried by the DOM objects to set their state. -// This module handle all the messages broadcasted from the parent process, -// including DOM events, which are dispatched to the corresponding DOM objects. - this.DOMApplicationRegistry = { - // DOMApps will hold a list of arrays of weak references to - // mozIDOMApplication objects indexed by manifest URL. - DOMApps: {}, - init: function init() { + debug("init"); this.cpmm = Cc["@mozilla.org/childprocessmessagemanager;1"] .getService(Ci.nsISyncMessageSender); - APPS_IPC_MSG_NAMES.forEach((function(aMsgName) { + ["Webapps:AddApp", "Webapps:RemoveApp"].forEach((function(aMsgName) { this.cpmm.addMessageListener(aMsgName, this); }).bind(this)); - this.cpmm.sendAsyncMessage("Webapps:RegisterForMessages", { - messages: APPS_IPC_MSG_NAMES - }); - // We need to prime the cache with the list of apps. - // XXX should we do this async and block callers if it's not yet there? - let list = this.cpmm.sendSyncMessage("Webapps:GetList", { })[0]; - this.webapps = list.webapps; + // XXX shoud we do this async and block callers if it's not yet there? + this.webapps = this.cpmm.sendSyncMessage("Webapps:GetList", { })[0]; // We need a fast mapping from localId -> app, so we add an index. - // And add the manifest to the app object. this.localIdIndex = { }; for (let id in this.webapps) { let app = this.webapps[id]; this.localIdIndex[app.localId] = app; - app.manifest = list.manifests[id]; } Services.obs.addObserver(this, "xpcom-shutdown", false); }, observe: function(aSubject, aTopic, aData) { - // cpmm.addMessageListener causes the DOMApplicationRegistry object to - // live forever if we don't clean up properly. + // cpmm.addMessageListener causes the DOMApplicationRegistry object to live + // forever if we don't clean up properly. this.webapps = null; - this.DOMApps = null; - - APPS_IPC_MSG_NAMES.forEach((aMsgName) => { + ["Webapps:AddApp", "Webapps:RemoveApp"].forEach((function(aMsgName) { this.cpmm.removeMessageListener(aMsgName, this); - }); - - this.cpmm.sendAsyncMessage("Webapps:UnregisterForMessages", - APPS_IPC_MSG_NAMES) + }).bind(this)); }, receiveMessage: function receiveMessage(aMessage) { debug("Received " + aMessage.name + " message."); - let msg = aMessage.data; + let msg = aMessage.json; switch (aMessage.name) { case "Webapps:AddApp": this.webapps[msg.id] = msg.app; this.localIdIndex[msg.app.localId] = msg.app; break; case "Webapps:RemoveApp": - delete this.DOMApps[this.webapps[msg.id].manifestURL]; delete this.localIdIndex[this.webapps[msg.id].localId]; delete this.webapps[msg.id]; break; - case "Webapps:FireEvent": - this._fireEvent(aMessage); - break; - case "Webapps:UpdateState": - this._updateState(msg); - break; - case "Webapps:CheckForUpdate:Return:KO": - let DOMApps = this.DOMApps[msg.manifestURL]; - if (!DOMApps || !msg.requestID) { - return; - } - DOMApps.forEach((DOMApp) => { - let domApp = DOMApp.get(); - if (msg.requestID) { - domApp._fireRequestResult(aMessage, true /* aIsError */); - } - }); - break; } }, - /** - * mozIDOMApplication management - */ - - // Every time a DOM app is created, we save a weak reference to it that will - // be used to dispatch events and fire request results. - addDOMApp: function(aApp, aManifestURL, aId) { - let weakRef = Cu.getWeakReference(aApp); - - if (!this.DOMApps[aManifestURL]) { - this.DOMApps[aManifestURL] = []; - } - - let apps = this.DOMApps[aManifestURL]; - - // Get rid of dead weak references. - for (let i = 0; i < apps.length; i++) { - if (!apps[i].get()) { - apps.splice(i); - } - } - - apps.push(weakRef); - - // Each DOM app contains a proxy object used to build their state. We - // return the handler for this proxy object with traps to get and set - // app properties kept in the DOMApplicationRegistry app cache. - return { - get: function(target, prop) { - if (!DOMApplicationRegistry.webapps[aId]) { - return; - } - return DOMApplicationRegistry.webapps[aId][prop]; - }, - set: function(target, prop, val) { - if (!DOMApplicationRegistry.webapps[aId]) { - return; - } - DOMApplicationRegistry.webapps[aId][prop] = val; - return; - }, - }; - }, - - _fireEvent: function(aMessage) { - let msg = aMessage.data; - debug("_fireEvent " + JSON.stringify(msg)); - if (!this.DOMApps || !msg.manifestURL || !msg.eventType) { - return; - } - - let DOMApps = this.DOMApps[msg.manifestURL]; - if (!DOMApps) { - return; - } - - // The parent might ask childs to trigger more than one event in one - // shot, so in order to avoid needless IPC we allow an array for the - // 'eventType' IPC message field. - if (!Array.isArray(msg.eventType)) { - msg.eventType = [msg.eventType]; - } - - DOMApps.forEach((DOMApp) => { - let domApp = DOMApp.get(); - msg.eventType.forEach((aEventType) => { - if ('on' + aEventType in domApp) { - domApp._fireEvent(aEventType); - } - }); - - if (msg.requestID) { - aMessage.data.result = msg.manifestURL; - domApp._fireRequestResult(aMessage); - } - }); - }, - - _updateState: function(aMessage) { - if (!this.DOMApps || !aMessage.id) { - return; - } - - let app = this.webapps[aMessage.id]; - if (!app) { - return; - } - - if (aMessage.app) { - for (let prop in aMessage.app) { - app[prop] = aMessage.app[prop]; - } - } - - if (aMessage.error) { - app.downloadError = aMessage.error; - } - - if (aMessage.manifest) { - app.manifest = aMessage.manifest; - // Evict the wrapped manifest cache for all the affected DOM objects. - let DOMApps = this.DOMApps[app.manifestURL]; - if (!DOMApps) { - return; - } - DOMApps.forEach((DOMApp) => { - let domApp = DOMApp.get(); - WrappedManifestCache.evict(app.manifestURL, domApp.innerWindowID); - }); - } - }, - - /** - * nsIAppsService API - */ getAppByManifestURL: function getAppByManifestURL(aManifestURL) { debug("getAppByManifestURL " + aManifestURL); return AppsUtils.getAppByManifestURL(this.webapps, aManifestURL); diff --git a/dom/apps/src/Webapps.js b/dom/apps/src/Webapps.js index e2283451e72f..7dd80030d8cd 100644 --- a/dom/apps/src/Webapps.js +++ b/dom/apps/src/Webapps.js @@ -12,7 +12,6 @@ Cu.import("resource://gre/modules/Services.jsm"); Cu.import("resource://gre/modules/DOMRequestHelper.jsm"); Cu.import("resource://gre/modules/AppsUtils.jsm"); Cu.import("resource://gre/modules/BrowserElementPromptService.jsm"); -Cu.import("resource://gre/modules/AppsServiceChild.jsm"); XPCOMUtils.defineLazyServiceGetter(this, "cpmm", "@mozilla.org/childprocessmessagemanager;1", @@ -265,9 +264,50 @@ WebappsRegistry.prototype = { * mozIDOMApplication object */ +// A simple cache for the wrapped manifests. +let manifestCache = { + _cache: { }, + + // Gets an entry from the cache, and populates the cache if needed. + get: function mcache_get(aManifestURL, aManifest, aWindow, aInnerWindowID) { + if (!(aManifestURL in this._cache)) { + this._cache[aManifestURL] = { }; + } + + let winObjs = this._cache[aManifestURL]; + if (!(aInnerWindowID in winObjs)) { + winObjs[aInnerWindowID] = Cu.cloneInto(aManifest, aWindow); + } + + return winObjs[aInnerWindowID]; + }, + + // Invalidates an entry in the cache. + evict: function mcache_evict(aManifestURL, aInnerWindowID) { + if (aManifestURL in this._cache) { + let winObjs = this._cache[aManifestURL]; + if (aInnerWindowID in winObjs) { + delete winObjs[aInnerWindowID]; + } + + if (Object.keys(winObjs).length == 0) { + delete this._cache[aManifestURL]; + } + } + }, + + observe: function(aSubject, aTopic, aData) { + // Clear the cache on memory pressure. + this._cache = { }; + }, + + init: function() { + Services.obs.addObserver(this, "memory-pressure", false); + } +}; + function createApplicationObject(aWindow, aApp) { - let app = Cc["@mozilla.org/webapps/application;1"] - .createInstance(Ci.mozIDOMApplication); + let app = Cc["@mozilla.org/webapps/application;1"].createInstance(Ci.mozIDOMApplication); app.wrappedJSObject.init(aWindow, aApp); return app; } @@ -280,12 +320,27 @@ WebappsApplication.prototype = { __proto__: DOMRequestIpcHelper.prototype, init: function(aWindow, aApp) { - let proxyHandler = DOMApplicationRegistry.addDOMApp(this, - aApp.manifestURL, - aApp.id); - this._proxy = new Proxy(this, proxyHandler); - this._window = aWindow; + let principal = this._window.document.nodePrincipal; + this._appStatus = principal.appStatus; + this.origin = aApp.origin; + this._manifest = aApp.manifest; + this._updateManifest = aApp.updateManifest; + this.manifestURL = aApp.manifestURL; + this.receipts = aApp.receipts; + this.installOrigin = aApp.installOrigin; + this.installTime = aApp.installTime; + this.installState = aApp.installState || "installed"; + this.removable = aApp.removable; + this.lastUpdateCheck = aApp.lastUpdateCheck ? aApp.lastUpdateCheck + : Date.now(); + this.updateTime = aApp.updateTime ? aApp.updateTime + : aApp.installTime; + this.progress = NaN; + this.downloadAvailable = aApp.downloadAvailable; + this.downloading = aApp.downloading; + this.readyToApplyDownload = aApp.readyToApplyDownload; + this.downloadSize = aApp.downloadSize || 0; this._onprogress = null; this._ondownloadsuccess = null; @@ -293,83 +348,40 @@ WebappsApplication.prototype = { this._ondownloadavailable = null; this._ondownloadapplied = null; - this.initDOMRequestHelper(aWindow); - }, + this._downloadError = null; - get _appStatus() { - return this._proxy.appStatus; - }, + this.initDOMRequestHelper(aWindow, [ + { name: "Webapps:CheckForUpdate:Return:KO", weakRef: true }, + { name: "Webapps:Connect:Return:OK", weakRef: true }, + { name: "Webapps:Connect:Return:KO", weakRef: true }, + { name: "Webapps:FireEvent", weakRef: true }, + { name: "Webapps:GetConnections:Return:OK", weakRef: true }, + { name: "Webapps:UpdateState", weakRef: true } + ]); - get downloadAvailable() { - return this._proxy.downloadAvailable; - }, - - get downloading() { - return this._proxy.downloading; - }, - - get downloadSize() { - return this._proxy.downloadSize; - }, - - get installOrigin() { - return this._proxy.installOrigin; - }, - - get installState() { - return this._proxy.installState; - }, - - get installTime() { - return this._proxy.installTime; - }, - - get lastUpdateCheck() { - return this._proxy.lastUpdateCheck; - }, - - get manifestURL() { - return this._proxy.manifestURL; - }, - - get origin() { - return this._proxy.origin; - }, - - get progress() { - return this._proxy.progress; - }, - - get readyToApplyDownload() { - return this._proxy.readyToApplyDownload; - }, - - get receipts() { - return this._proxy.receipts; - }, - - set receipts(aReceipts) { - this._proxy.receipts = aReceipts; - }, - - get removable() { - return this._proxy.removable; - }, - - get updateTime() { - return this._proxy.updateTime; + cpmm.sendAsyncMessage("Webapps:RegisterForMessages", { + messages: ["Webapps:FireEvent", + "Webapps:UpdateState"], + app: { + id: this.id, + manifestURL: this.manifestURL, + installState: this.installState, + downloading: this.downloading + } + }); }, get manifest() { - return WrappedManifestCache.get(this.manifestURL, - this._proxy.manifest, - this._window, - this.innerWindowID); + return manifestCache.get(this.manifestURL, + this._manifest, + this._window, + this.innerWindowID); }, get updateManifest() { - return this._proxy.updateManifest ? - Cu.cloneInto(this._proxy.updateManifest, this._window) : null; + return this.updateManifest = + this._updateManifest ? Cu.cloneInto(this._updateManifest, this._window) + : null; }, set onprogress(aCallback) { @@ -413,7 +425,7 @@ WebappsApplication.prototype = { }, get downloadError() { - return new this._window.DOMError(this._proxy.downloadError || ''); + return new this._window.DOMError(this._downloadError || ''); }, download: function() { @@ -455,11 +467,12 @@ WebappsApplication.prototype = { BrowserElementPromptService.getBrowserElementChildForWindow(this._window); if (browserChild) { this.addMessageListeners("Webapps:ClearBrowserData:Return"); - browserChild.messageManager.sendAsyncMessage("Webapps:ClearBrowserData", { - manifestURL: this.manifestURL, - oid: this._id, - requestID: this.getRequestId(request) - }); + browserChild.messageManager.sendAsyncMessage( + "Webapps:ClearBrowserData", + { manifestURL: this.manifestURL, + oid: this._id, + requestID: this.getRequestId(request) } + ); } else { Services.DOMRequest.fireErrorAsync(request, "NO_CLEARABLE_BROWSER"); } @@ -467,34 +480,29 @@ WebappsApplication.prototype = { }, connect: function(aKeyword, aRules) { - this.addMessageListeners(["Webapps:Connect:Return:OK", - "Webapps:Connect:Return:KO"]); return this.createPromise(function (aResolve, aReject) { - cpmm.sendAsyncMessage("Webapps:Connect", { - keyword: aKeyword, - rules: aRules, - manifestURL: this.manifestURL, - outerWindowID: this._id, - appStatus: this._appStatus, - requestID: this.getPromiseResolverId({ - resolve: aResolve, - reject: aReject - }) - }); + cpmm.sendAsyncMessage("Webapps:Connect", + { keyword: aKeyword, + rules: aRules, + manifestURL: this.manifestURL, + outerWindowID: this._id, + appStatus: this._appStatus, + requestID: this.getPromiseResolverId({ + resolve: aResolve, + reject: aReject + })}); }.bind(this)); }, getConnections: function() { - this.addMessageListeners("Webapps:getConnections:Return:OK"); return this.createPromise(function (aResolve, aReject) { - cpmm.sendAsyncMessage("Webapps:GetConnections", { - manifestURL: this.manifestURL, - outerWindowID: this._id, - requestID: this.getPromiseResolverId({ - resolve: aResolve, - reject: aReject - }) - }); + cpmm.sendAsyncMessage("Webapps:GetConnections", + { manifestURL: this.manifestURL, + outerWindowID: this._id, + requestID: this.getPromiseResolverId({ + resolve: aResolve, + reject: aReject + })}); }.bind(this)); }, @@ -543,7 +551,12 @@ WebappsApplication.prototype = { uninit: function() { this._onprogress = null; - WrappedManifestCache.evict(this.manifestURL, this.innerWindowID); + cpmm.sendAsyncMessage("Webapps:UnregisterForMessages", [ + "Webapps:FireEvent", + "Webapps:UpdateState" + ]); + + manifestCache.evict(this.manifestURL, this.innerWindowID); }, _fireEvent: function(aName) { @@ -560,15 +573,21 @@ WebappsApplication.prototype = { } }, - _fireRequestResult: function(aMessage, aIsError) { - let req; - let msg = aMessage.data; - req = this.takeRequest(msg.requestID); - if (!req) { - return; + _updateState: function(aMsg) { + if (aMsg.app) { + for (let prop in aMsg.app) { + this[prop] = aMsg.app[prop]; + } + } + + if (aMsg.error) { + this._downloadError = aMsg.error; + } + + if (aMsg.manifest) { + this._manifest = aMsg.manifest; + manifestCache.evict(this.manifestURL, this.innerWindowID); } - aIsError ? Services.DOMRequest.fireError(req, msg.error) - : Services.DOMRequest.fireSuccess(req, msg.result); }, receiveMessage: function(aMessage) { @@ -582,7 +601,10 @@ WebappsApplication.prototype = { req = this.takeRequest(msg.requestID); } - if (msg.oid != this._id || !req) { + // ondownload* callbacks should be triggered on all app instances + if ((msg.oid != this._id || !req) && + aMessage.name !== "Webapps:FireEvent" && + aMessage.name !== "Webapps:UpdateState") { return; } @@ -597,13 +619,45 @@ WebappsApplication.prototype = { "Webapps:Launch:Return:KO"]); Services.DOMRequest.fireSuccess(req, null); break; + case "Webapps:CheckForUpdate:Return:KO": + Services.DOMRequest.fireError(req, msg.error); + break; + case "Webapps:FireEvent": + if (msg.manifestURL != this.manifestURL) { + return; + } + + // The parent might ask childs to trigger more than one event in one + // shot, so in order to avoid needless IPC we allow an array for the + // 'eventType' IPC message field. + if (!Array.isArray(msg.eventType)) { + msg.eventType = [msg.eventType]; + } + + msg.eventType.forEach((aEventType) => { + if ("_on" + aEventType in this) { + this._fireEvent(aEventType); + } else { + dump("Unsupported event type " + aEventType + "\n"); + } + }); + + if (req) { + Services.DOMRequest.fireSuccess(req, this.manifestURL); + } + break; + case "Webapps:UpdateState": + if (msg.manifestURL != this.manifestURL) { + return; + } + + this._updateState(msg); + break; case "Webapps:ClearBrowserData:Return": this.removeMessageListeners(aMessage.name); Services.DOMRequest.fireSuccess(req, null); break; case "Webapps:Connect:Return:OK": - this.removeMessageListeners(["Webapps:Connect:Return:OK", - "Webapps:Connect:Return:KO"]); let messagePorts = []; msg.messagePortIDs.forEach((aPortID) => { let port = new this._window.MozInterAppMessagePort(aPortID); @@ -612,12 +666,9 @@ WebappsApplication.prototype = { req.resolve(messagePorts); break; case "Webapps:Connect:Return:KO": - this.removeMessageListeners(["Webapps:Connect:Return:OK", - "Webapps:Connect:Return:KO"]); req.reject("No connections registered"); break; case "Webapps:GetConnections:Return:OK": - this.removeMessageListeners(aMessage.name); let connections = []; msg.connections.forEach((aConnection) => { let connection = @@ -799,8 +850,12 @@ WebappsApplicationMgmt.prototype = { break; case "Webapps:Uninstall:Broadcast:Return:OK": if (this._onuninstall) { + let detail = { + manifestURL: msg.manifestURL, + origin: msg.origin + }; let event = new this._window.MozApplicationEvent("applicationuninstall", - { application : createApplicationObject(this._window, msg) }); + { application : createApplicationObject(this._window, detail) }); this._onuninstall.handleEvent(event); } break; @@ -829,5 +884,7 @@ WebappsApplicationMgmt.prototype = { classDescription: "Webapps Application Mgmt"}) } +manifestCache.init(); + this.NSGetFactory = XPCOMUtils.generateNSGetFactory([WebappsRegistry, WebappsApplication]); diff --git a/dom/apps/src/Webapps.jsm b/dom/apps/src/Webapps.jsm index c42385a490a8..d7aac84d7aca 100755 --- a/dom/apps/src/Webapps.jsm +++ b/dom/apps/src/Webapps.jsm @@ -1142,7 +1142,8 @@ this.DOMApplicationRegistry = { this.removeMessageListener(["Webapps:Internal:AllMessages"], mm); break; case "Webapps:GetList": - return { webapps: this.webapps, manifests: this._manifestCache }; + this.addMessageListener(["Webapps:AddApp", "Webapps:RemoveApp"], null, mm); + return this.webapps; case "Webapps:Download": this.startDownload(msg.manifestURL); break; @@ -1287,7 +1288,7 @@ this.DOMApplicationRegistry = { downloading: false }, error: error, - id: app.id + manifestURL: app.manifestURL, }) this.broadcastMessage("Webapps:FireEvent", { eventType: "downloaderror", @@ -1316,7 +1317,7 @@ this.DOMApplicationRegistry = { if (!app.downloadAvailable) { this.broadcastMessage("Webapps:UpdateState", { error: "NO_DOWNLOAD_AVAILABLE", - id: app.id + manifestURL: app.manifestURL }); this.broadcastMessage("Webapps:FireEvent", { eventType: "downloaderror", @@ -1361,7 +1362,7 @@ this.DOMApplicationRegistry = { this.broadcastMessage("Webapps:UpdateState", { app: app, manifest: jsonManifest, - id: app.id + manifestURL: aManifestURL }); this.broadcastMessage("Webapps:FireEvent", { eventType: "downloadsuccess", @@ -1404,7 +1405,7 @@ this.DOMApplicationRegistry = { DOMApplicationRegistry._saveApps().then(() => { DOMApplicationRegistry.broadcastMessage("Webapps:UpdateState", { app: app, - id: app.id + manifestURL: aManifestURL }); DOMApplicationRegistry.broadcastMessage("Webapps:FireEvent", { eventType: "downloadsuccess", @@ -1498,7 +1499,7 @@ this.DOMApplicationRegistry = { this.broadcastMessage("Webapps:UpdateState", { app: app, manifest: aData, - id: app.id + manifestURL: app.manifestURL }); this.broadcastMessage("Webapps:FireEvent", { eventType: "downloadapplied", @@ -1538,7 +1539,7 @@ this.DOMApplicationRegistry = { installState: aApp.installState, progress: 0 }, - id: aApp.id + manifestURL: aApp.manifestURL }); let cacheUpdate = updateSvc.scheduleAppUpdate( appcacheURI, docURI, aApp.localId, false, aProfileDir); @@ -1588,7 +1589,6 @@ this.DOMApplicationRegistry = { debug("checkForUpdate for " + aData.manifestURL); function sendError(aError) { - debug("checkForUpdate error " + aError); aData.error = aError; aMm.sendAsyncMessage("Webapps:CheckForUpdate:Return:KO", aData); } @@ -1618,7 +1618,8 @@ this.DOMApplicationRegistry = { // then we can't have an update. if (app.origin.startsWith("app://") && app.manifestURL.startsWith("app://")) { - sendError("NOT_UPDATABLE"); + aData.error = "NOT_UPDATABLE"; + aMm.sendAsyncMessage("Webapps:CheckForUpdate:Return:KO", aData); return; } @@ -1635,7 +1636,8 @@ this.DOMApplicationRegistry = { if (onlyCheckAppCache) { // Bail out for packaged apps. if (app.origin.startsWith("app://")) { - sendError("NOT_UPDATABLE"); + aData.error = "NOT_UPDATABLE"; + aMm.sendAsyncMessage("Webapps:CheckForUpdate:Return:KO", aData); return; } @@ -1643,7 +1645,8 @@ this.DOMApplicationRegistry = { this._readManifests([{ id: id }]).then((aResult) => { let manifest = aResult[0].manifest; if (!manifest.appcache_path) { - sendError("NOT_UPDATABLE"); + aData.error = "NOT_UPDATABLE"; + aMm.sendAsyncMessage("Webapps:CheckForUpdate:Return:KO", aData); return; } @@ -1659,7 +1662,7 @@ this.DOMApplicationRegistry = { this._saveApps().then(() => { this.broadcastMessage("Webapps:UpdateState", { app: app, - id: app.id + manifestURL: app.manifestURL }); this.broadcastMessage("Webapps:FireEvent", { eventType: "downloadavailable", @@ -1668,7 +1671,8 @@ this.DOMApplicationRegistry = { }); }); } else { - sendError("NOT_UPDATABLE"); + aData.error = "NOT_UPDATABLE"; + aMm.sendAsyncMessage("Webapps:CheckForUpdate:Return:KO", aData); } } }; @@ -1728,7 +1732,7 @@ this.DOMApplicationRegistry = { : "downloadapplied"; aMm.sendAsyncMessage("Webapps:UpdateState", { app: app, - id: app.id + manifestURL: app.manifestURL }); aMm.sendAsyncMessage("Webapps:FireEvent", { eventType: eventType, @@ -1755,7 +1759,7 @@ this.DOMApplicationRegistry = { : "downloadapplied"; aMm.sendAsyncMessage("Webapps:UpdateState", { app: app, - id: app.id + manifestURL: app.manifestURL }); aMm.sendAsyncMessage("Webapps:FireEvent", { eventType: eventType, @@ -1863,7 +1867,7 @@ this.DOMApplicationRegistry = { this._saveApps().then(() => { this.broadcastMessage("Webapps:UpdateState", { app: aApp, - id: aApp.id + manifestURL: aApp.manifestURL }); this.broadcastMessage("Webapps:FireEvent", { eventType: "downloadavailable", @@ -1927,7 +1931,7 @@ this.DOMApplicationRegistry = { reg.broadcastMessage("Webapps:UpdateState", { app: aApp, manifest: aApp.manifest, - id: aApp.id + manifestURL: aApp.manifestURL }); reg.broadcastMessage("Webapps:FireEvent", { eventType: "downloadapplied", @@ -1949,7 +1953,7 @@ this.DOMApplicationRegistry = { reg.broadcastMessage("Webapps:UpdateState", { app: aApp, manifest: aApp.manifest, - id: aApp.id + manifestURL: aApp.manifestURL }); reg.broadcastMessage("Webapps:FireEvent", { eventType: eventType, @@ -2214,8 +2218,8 @@ this.DOMApplicationRegistry = { queuedDownload: {}, queuedPackageDownload: {}, - onInstallSuccessAck: function onInstallSuccessAck(aManifestURL, - aDontNeedNetwork) { +onInstallSuccessAck: function onInstallSuccessAck(aManifestURL, + aDontNeedNetwork) { // If we are offline, register to run when we'll be online. if ((Services.io.offline) && !aDontNeedNetwork) { let onlineWrapper = { @@ -2345,6 +2349,7 @@ this.DOMApplicationRegistry = { let jsonManifest = aData.isPackage ? app.updateManifest : app.manifest; this._writeManifestFile(id, aData.isPackage, jsonManifest); + debug("app.origin: " + app.origin); let manifest = new ManifestHelper(jsonManifest, app.origin); let appObject = this._cloneApp(aData, app, manifest, id, localId); @@ -2388,8 +2393,6 @@ this.DOMApplicationRegistry = { // corresponging DOMRequest.onsuccess event as soon as the app is properly // saved in the registry. this._saveApps().then(() => { - aData.isPackage ? appObject.updateManifest = jsonManifest : - appObject.manifest = jsonManifest; this.broadcastMessage("Webapps:AddApp", { id: id, app: appObject }); if (aData.isPackage && aData.autoInstall) { // Skip directly to onInstallSuccessAck, since there isn't @@ -2506,7 +2509,7 @@ this.DOMApplicationRegistry = { this.broadcastMessage("Webapps:UpdateState", { app: app, manifest: aManifest, - id: app.id + manifestURL: aNewApp.manifestURL }); this.broadcastMessage("Webapps:FireEvent", { eventType: ["downloadsuccess", "downloadapplied"], @@ -2616,11 +2619,14 @@ this.DOMApplicationRegistry = { oldApp, aNewApp); - AppDownloadManager.add(aNewApp.manifestURL, { - channel: requestChannel, - appId: id, - previousState: aIsUpdate ? "installed" : "pending" - }); + AppDownloadManager.add( + aNewApp.manifestURL, + { + channel: requestChannel, + appId: id, + previousState: aIsUpdate ? "installed" : "pending" + } + ); // We set the 'downloading' flag to true right before starting the fetch. oldApp.downloading = true; @@ -2643,7 +2649,7 @@ this.DOMApplicationRegistry = { debug("package's etag or hash unchanged; sending 'applied' event"); // The package's Etag or hash has not changed. // We send a "applied" event right away. - this._sendAppliedEvent(oldApp); + this._sendAppliedEvent(aNewApp, oldApp, id); return; } @@ -2783,7 +2789,7 @@ this.DOMApplicationRegistry = { app: { progress: aProgress }, - id: aNewApp.id + manifestURL: aNewApp.manifestURL }); this.broadcastMessage("Webapps:FireEvent", { eventType: "progress", @@ -2911,21 +2917,21 @@ this.DOMApplicationRegistry = { * @param aOldApp {Object} the currently stored app data * @param aId {String} the unique id of the app */ - _sendAppliedEvent: function(aApp) { - aApp.downloading = false; - aApp.downloadAvailable = false; - aApp.downloadSize = 0; - aApp.installState = "installed"; - aApp.readyToApplyDownload = false; - if (aApp.staged && aApp.staged.manifestHash) { + _sendAppliedEvent: function(aNewApp, aOldApp, aId) { + aOldApp.downloading = false; + aOldApp.downloadAvailable = false; + aOldApp.downloadSize = 0; + aOldApp.installState = "installed"; + aOldApp.readyToApplyDownload = false; + if (aOldApp.staged && aOldApp.staged.manifestHash) { // If we're here then the manifest has changed but the package // hasn't. Let's clear this, so we don't keep offering // a bogus update to the user - aApp.manifestHash = aApp.staged.manifestHash; - aApp.etag = aApp.staged.etag || aApp.etag; - aApp.staged = {}; + aOldApp.manifestHash = aOldApp.staged.manifestHash; + aOldApp.etag = aOldApp.staged.etag || aOldApp.etag; + aOldApp.staged = {}; // Move the staged update manifest to a non staged one. - let dirPath = this._getAppDir(aApp.id).path; + let dirPath = this._getAppDir(aId).path; // We don't really mind much if this fails. OS.File.move(OS.Path.join(dirPath, "staged-update.webapp"), @@ -2935,15 +2941,15 @@ this.DOMApplicationRegistry = { // Save the updated registry, and cleanup the tmp directory. this._saveApps().then(() => { this.broadcastMessage("Webapps:UpdateState", { - app: aApp, - id: aApp.id + app: aOldApp, + manifestURL: aNewApp.manifestURL }); this.broadcastMessage("Webapps:FireEvent", { - manifestURL: aApp.manifestURL, + manifestURL: aNewApp.manifestURL, eventType: ["downloadsuccess", "downloadapplied"] }); }); - let file = FileUtils.getFile("TmpD", ["webapps", aApp.id], false); + let file = FileUtils.getFile("TmpD", ["webapps", aId], false); if (file && file.exists()) { file.remove(true); } @@ -3322,7 +3328,7 @@ this.DOMApplicationRegistry = { this.broadcastMessage("Webapps:UpdateState", { app: aOldApp, error: aError, - id: aNewApp.id + manifestURL: aNewApp.manifestURL }); this.broadcastMessage("Webapps:FireEvent", { eventType: "downloaderror", @@ -3872,7 +3878,7 @@ AppcacheObserver.prototype = { let app = this.app; DOMApplicationRegistry.broadcastMessage("Webapps:UpdateState", { app: app, - id: app.id + manifestURL: app.manifestURL }); DOMApplicationRegistry.broadcastMessage("Webapps:FireEvent", { eventType: "progress", @@ -3904,7 +3910,7 @@ AppcacheObserver.prototype = { app.downloadAvailable = false; DOMApplicationRegistry.broadcastMessage("Webapps:UpdateState", { app: app, - id: app.id + manifestURL: app.manifestURL }); DOMApplicationRegistry.broadcastMessage("Webapps:FireEvent", { eventType: ["downloadsuccess", "downloadapplied"], @@ -3917,7 +3923,7 @@ AppcacheObserver.prototype = { app.downloading = false; DOMApplicationRegistry.broadcastMessage("Webapps:UpdateState", { app: app, - id: app.id + manifestURL: app.manifestURL }); DOMApplicationRegistry.broadcastMessage("Webapps:FireEvent", { error: aError, diff --git a/dom/apps/tests/test_packaged_app_common.js b/dom/apps/tests/test_packaged_app_common.js index 97b90331fef4..f8440156f167 100644 --- a/dom/apps/tests/test_packaged_app_common.js +++ b/dom/apps/tests/test_packaged_app_common.js @@ -99,7 +99,6 @@ var PackagedTestHelper = (function PackagedTestHelper() { var aApp = evt.application; aApp.ondownloaderror = function(evt) { var error = aApp.downloadError.name; - ok(true, "Got downloaderror " + error); if (error == aExpectedError) { ok(true, "Got expected " + aExpectedError); var expected = { diff --git a/dom/apps/tests/test_packaged_app_update.html b/dom/apps/tests/test_packaged_app_update.html index 8fb92f85751a..0d7f6850b296 100644 --- a/dom/apps/tests/test_packaged_app_update.html +++ b/dom/apps/tests/test_packaged_app_update.html @@ -79,15 +79,16 @@ function updateApp(aExpectedReady, aPreviousVersion, aNextVersion) { checkLastAppState.bind(PackagedTestHelper, miniManifestURL, false, false, aNextVersion, PackagedTestHelper.next); - var ondownloadsuccesshandler = - checkLastAppState.bind(undefined, miniManifestURL, - aExpectedReady, false, aPreviousVersion, - function() { - navigator.mozApps.mgmt.applyDownload(lApp); - }); + var ondownloadsuccesshandler = + checkLastAppState.bind(undefined, miniManifestURL, + aExpectedReady, false, aPreviousVersion, + function() { + navigator.mozApps.mgmt.applyDownload(lApp); + }); + + checkForUpdate(true, ondownloadsuccesshandler, ondownloadappliedhandler, null, + true); - checkForUpdate(true, ondownloadsuccesshandler, ondownloadappliedhandler, null, - true); } @@ -174,7 +175,7 @@ var steps = [ "&appName=arandomname" + "&appToFail1"; PackagedTestHelper.checkAppDownloadError(miniManifestURL, - "MANIFEST_MISMATCH", 1, false, true, + "MANIFEST_MISMATCH", 2, false, true, "arandomname", function () { checkForUpdate(false, null, null, null, false, diff --git a/dom/apps/tests/test_receipt_operations.html b/dom/apps/tests/test_receipt_operations.html index 2a965a02a8c2..fdc460476df0 100644 --- a/dom/apps/tests/test_receipt_operations.html +++ b/dom/apps/tests/test_receipt_operations.html @@ -247,4 +247,4 @@ addLoadEvent(go); - + \ No newline at end of file diff --git a/dom/base/Console.cpp b/dom/base/Console.cpp index 119749c11226..77678d04e070 100644 --- a/dom/base/Console.cpp +++ b/dom/base/Console.cpp @@ -132,7 +132,7 @@ JSStructuredCloneCallbacks gConsoleCallbacks = { ConsoleStructuredCloneCallbacksError }; -class ConsoleCallData +class ConsoleCallData MOZ_FINAL : public LinkedListElement { public: ConsoleCallData() @@ -141,6 +141,12 @@ public: , mTimeStamp(JS_Now()) , mMonotonicTimer(0) { + MOZ_COUNT_CTOR(ConsoleCallData); + } + + ~ConsoleCallData() + { + MOZ_COUNT_DTOR(ConsoleCallData); } void @@ -259,7 +265,7 @@ private: class ConsoleCallDataRunnable MOZ_FINAL : public ConsoleRunnable { public: - ConsoleCallDataRunnable(const ConsoleCallData& aCallData) + ConsoleCallDataRunnable(ConsoleCallData* aCallData) : mCallData(aCallData) { } @@ -269,16 +275,16 @@ private: PreDispatch(JSContext* aCx) MOZ_OVERRIDE { ClearException ce(aCx); - JSAutoCompartment ac(aCx, mCallData.mGlobal); + JSAutoCompartment ac(aCx, mCallData->mGlobal); JS::Rooted arguments(aCx, - JS_NewArrayObject(aCx, mCallData.mArguments.Length())); + JS_NewArrayObject(aCx, mCallData->mArguments.Length())); if (!arguments) { return false; } - for (uint32_t i = 0; i < mCallData.mArguments.Length(); ++i) { - if (!JS_DefineElement(aCx, arguments, i, mCallData.mArguments[i], + for (uint32_t i = 0; i < mCallData->mArguments.Length(); ++i) { + if (!JS_DefineElement(aCx, arguments, i, mCallData->mArguments[i], nullptr, nullptr, JSPROP_ENUMERATE)) { return false; } @@ -290,8 +296,8 @@ private: return false; } - mCallData.mArguments.Clear(); - mCallData.mGlobal = nullptr; + mCallData->mArguments.Clear(); + mCallData->mGlobal = nullptr; return true; } @@ -341,17 +347,17 @@ private: return; } - mCallData.mArguments.AppendElement(value); + mCallData->mArguments.AppendElement(value); } - MOZ_ASSERT(mCallData.mArguments.Length() == length); + MOZ_ASSERT(mCallData->mArguments.Length() == length); - mCallData.mGlobal = JS::CurrentGlobalOrNull(cx); - console->AppendCallData(mCallData); + mCallData->mGlobal = JS::CurrentGlobalOrNull(cx); + console->AppendCallData(mCallData.forget()); } private: - ConsoleCallData mCallData; + nsAutoPtr mCallData; JSAutoStructuredCloneBuffer mArguments; nsTArray mStrings; @@ -480,7 +486,7 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(Console) NS_IMPL_CYCLE_COLLECTION_UNLINK(mStorage) NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER - tmp->mQueuedCalls.Clear(); + tmp->ClearConsoleData(); NS_IMPL_CYCLE_COLLECTION_UNLINK_END @@ -494,11 +500,16 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(Console) NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER - for (uint32_t i = 0; i < tmp->mQueuedCalls.Length(); ++i) { - NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mQueuedCalls[i].mGlobal); + for (ConsoleCallData* data = tmp->mQueuedCalls.getFirst(); data != nullptr; + data = data->getNext()) { + if (data->mGlobal) { + aCallbacks.Trace(&data->mGlobal, "data->mGlobal", aClosure); + } - for (uint32_t j = 0; j < tmp->mQueuedCalls[i].mArguments.Length(); ++j) { - NS_IMPL_CYCLE_COLLECTION_TRACE_JSVAL_MEMBER_CALLBACK(mQueuedCalls[i].mArguments[j]); + for (uint32_t i = 0; i < data->mArguments.Length(); ++i) { + if (JSVAL_IS_TRACEABLE(data->mArguments[i])) { + aCallbacks.Trace(&data->mArguments[i], "data->mArguments[i]", aClosure); + } } } @@ -568,7 +579,7 @@ Console::Observe(nsISupports* aSubject, const char* aTopic, obs->RemoveObserver(this, "inner-window-destroyed"); } - mQueuedCalls.Clear(); + ClearConsoleData(); mTimerRegistry.Clear(); if (mTimer) { @@ -735,8 +746,8 @@ Console::Method(JSContext* aCx, MethodName aMethodName, // goes wrong. class RAII { public: - RAII(nsTArray& aArray) - : mArray(aArray) + RAII(LinkedList& aList) + : mList(aList) , mUnfinished(true) { } @@ -744,7 +755,9 @@ Console::Method(JSContext* aCx, MethodName aMethodName, ~RAII() { if (mUnfinished) { - mArray.RemoveElementAt(mArray.Length() - 1); + ConsoleCallData* data = mList.popLast(); + MOZ_ASSERT(data); + delete data; } } @@ -755,12 +768,14 @@ Console::Method(JSContext* aCx, MethodName aMethodName, } private: - nsTArray& mArray; + LinkedList& mList; bool mUnfinished; }; - ConsoleCallData& callData = *mQueuedCalls.AppendElement(); - callData.Initialize(aCx, aMethodName, aMethodString, aData); + ConsoleCallData* callData = new ConsoleCallData(); + mQueuedCalls.insertBack(callData); + + callData->Initialize(aCx, aMethodName, aMethodString, aData); RAII raii(mQueuedCalls); if (mWindow) { @@ -773,7 +788,7 @@ Console::Method(JSContext* aCx, MethodName aMethodName, nsCOMPtr loadContext = do_QueryInterface(webNav); MOZ_ASSERT(loadContext); - loadContext->GetUsePrivateBrowsing(&callData.mPrivate); + loadContext->GetUsePrivateBrowsing(&callData->mPrivate); } uint32_t maxDepth = aMethodName == MethodTrace ? @@ -797,7 +812,7 @@ Console::Method(JSContext* aCx, MethodName aMethodName, if (language == nsIProgrammingLanguage::JAVASCRIPT || language == nsIProgrammingLanguage::JAVASCRIPT2) { - ConsoleStackEntry& data = *callData.mStack.AppendElement(); + ConsoleStackEntry& data = *callData->mStack.AppendElement(); nsCString string; rv = stack->GetFilename(string); @@ -850,20 +865,24 @@ Console::Method(JSContext* aCx, MethodName aMethodName, return; } - callData.mMonotonicTimer = performance->Now(); + callData->mMonotonicTimer = performance->Now(); } + // The operation is completed. RAII class has to be disabled. + raii.Finished(); + if (!NS_IsMainThread()) { - // Here we are in a worker thread. + // Here we are in a worker thread. The ConsoleCallData has to been removed + // from the list and it will be deleted by the ConsoleCallDataRunnable or + // by the Main-Thread Console object. + mQueuedCalls.popLast(); + nsRefPtr runnable = new ConsoleCallDataRunnable(callData); runnable->Dispatch(); return; } - // The operation is completed. RAII class has to be disabled. - raii.Finished(); - if (!mTimer) { mTimer = do_CreateInstance("@mozilla.org/timer;1"); mTimer->InitWithCallback(this, CALL_DELAY, @@ -872,9 +891,9 @@ Console::Method(JSContext* aCx, MethodName aMethodName, } void -Console::AppendCallData(const ConsoleCallData& aCallData) +Console::AppendCallData(ConsoleCallData* aCallData) { - mQueuedCalls.AppendElement(aCallData); + mQueuedCalls.insertBack(aCallData); if (!mTimer) { mTimer = do_CreateInstance("@mozilla.org/timer;1"); @@ -887,17 +906,19 @@ Console::AppendCallData(const ConsoleCallData& aCallData) NS_IMETHODIMP Console::Notify(nsITimer *timer) { - MOZ_ASSERT(!mQueuedCalls.IsEmpty()); + MOZ_ASSERT(!mQueuedCalls.isEmpty()); - uint32_t i = 0; - for (; i < MESSAGES_IN_INTERVAL && i < mQueuedCalls.Length(); - ++i) { - ProcessCallData(mQueuedCalls[i]); + for (uint32_t i = 0; i < MESSAGES_IN_INTERVAL; ++i) { + ConsoleCallData* data = mQueuedCalls.popFirst(); + if (!data) { + break; + } + + ProcessCallData(data); + delete data; } - mQueuedCalls.RemoveElementsAt(0, i); - - if (mQueuedCalls.IsEmpty()) { + if (mQueuedCalls.isEmpty()) { mTimer->Cancel(); mTimer = nullptr; } @@ -906,18 +927,20 @@ Console::Notify(nsITimer *timer) } void -Console::ProcessCallData(ConsoleCallData& aData) +Console::ProcessCallData(ConsoleCallData* aData) { + MOZ_ASSERT(aData); + ConsoleStackEntry frame; - if (!aData.mStack.IsEmpty()) { - frame = aData.mStack[0]; + if (!aData->mStack.IsEmpty()) { + frame = aData->mStack[0]; } AutoSafeJSContext cx; ClearException ce(cx); RootedDictionary event(cx); - JSAutoCompartment ac(cx, aData.mGlobal); + JSAutoCompartment ac(cx, aData->mGlobal); event.mID.Construct(); event.mInnerID.Construct(); @@ -930,14 +953,14 @@ Console::ProcessCallData(ConsoleCallData& aData) event.mInnerID.Value().SetAsString() = frame.mFilename; } - event.mLevel = aData.mMethodString; + event.mLevel = aData->mMethodString; event.mFilename = frame.mFilename; event.mLineNumber = frame.mLineNumber; event.mFunctionName = frame.mFunctionName; - event.mTimeStamp = aData.mTimeStamp; - event.mPrivate = aData.mPrivate; + event.mTimeStamp = aData->mTimeStamp; + event.mPrivate = aData->mPrivate; - switch (aData.mMethodName) { + switch (aData->mMethodName) { case MethodLog: case MethodInfo: case MethodWarn: @@ -946,35 +969,35 @@ Console::ProcessCallData(ConsoleCallData& aData) case MethodDebug: case MethodAssert: event.mArguments.Construct(); - ProcessArguments(cx, aData.mArguments, event.mArguments.Value()); + ProcessArguments(cx, aData->mArguments, event.mArguments.Value()); break; default: event.mArguments.Construct(); - ArgumentsToValueList(aData.mArguments, event.mArguments.Value()); + ArgumentsToValueList(aData->mArguments, event.mArguments.Value()); } - if (aData.mMethodName == MethodTrace) { + if (aData->mMethodName == MethodTrace) { event.mStacktrace.Construct(); - event.mStacktrace.Value().SwapElements(aData.mStack); + event.mStacktrace.Value().SwapElements(aData->mStack); } - else if (aData.mMethodName == MethodGroup || - aData.mMethodName == MethodGroupCollapsed || - aData.mMethodName == MethodGroupEnd) { - ComposeGroupName(cx, aData.mArguments, event.mGroupName); + else if (aData->mMethodName == MethodGroup || + aData->mMethodName == MethodGroupCollapsed || + aData->mMethodName == MethodGroupEnd) { + ComposeGroupName(cx, aData->mArguments, event.mGroupName); } - else if (aData.mMethodName == MethodTime && !aData.mArguments.IsEmpty()) { - event.mTimer = StartTimer(cx, aData.mArguments[0], aData.mMonotonicTimer); + else if (aData->mMethodName == MethodTime && !aData->mArguments.IsEmpty()) { + event.mTimer = StartTimer(cx, aData->mArguments[0], aData->mMonotonicTimer); } - else if (aData.mMethodName == MethodTimeEnd && !aData.mArguments.IsEmpty()) { - event.mTimer = StopTimer(cx, aData.mArguments[0], aData.mMonotonicTimer); + else if (aData->mMethodName == MethodTimeEnd && !aData->mArguments.IsEmpty()) { + event.mTimer = StopTimer(cx, aData->mArguments[0], aData->mMonotonicTimer); } - else if (aData.mMethodName == MethodCount) { - event.mCounter = IncreaseCounter(cx, frame, aData.mArguments); + else if (aData->mMethodName == MethodCount) { + event.mCounter = IncreaseCounter(cx, frame, aData->mArguments); } JS::Rooted eventValue(cx); @@ -1395,5 +1418,13 @@ Console::IncreaseCounter(JSContext* aCx, const ConsoleStackEntry& aFrame, return value; } +void +Console::ClearConsoleData() +{ + while (ConsoleCallData* data = mQueuedCalls.popFirst()) { + delete data; + } +} + } // namespace dom } // namespace mozilla diff --git a/dom/base/Console.h b/dom/base/Console.h index 2b26f6f52817..5c6bfe59c378 100644 --- a/dom/base/Console.h +++ b/dom/base/Console.h @@ -128,10 +128,10 @@ private: const Sequence& aData); void - AppendCallData(const ConsoleCallData& aData); + AppendCallData(ConsoleCallData* aData); void - ProcessCallData(ConsoleCallData& aData); + ProcessCallData(ConsoleCallData* aData); // If the first JS::Value of the array is a string, this method uses it to // format a string. The supported sequences are: @@ -181,11 +181,14 @@ private: IncreaseCounter(JSContext* aCx, const ConsoleStackEntry& aFrame, const nsTArray>& aArguments); + void + ClearConsoleData(); + nsCOMPtr mWindow; nsCOMPtr mTimer; nsCOMPtr mStorage; - nsTArray mQueuedCalls; + LinkedList mQueuedCalls; nsDataHashtable mTimerRegistry; nsDataHashtable mCounterRegistry; diff --git a/dom/base/test/mochitest.ini b/dom/base/test/mochitest.ini index b11ccacbe09c..dc0c690802a9 100644 --- a/dom/base/test/mochitest.ini +++ b/dom/base/test/mochitest.ini @@ -9,6 +9,7 @@ support-files = [test_Image_constructor.html] [test_appname_override.html] [test_bug913761.html] +[test_bug978522.html] [test_clearTimeoutIntervalNoArg.html] [test_consoleEmptyStack.html] [test_constructor-assignment.html] @@ -16,6 +17,7 @@ support-files = [test_document.all_unqualified.html] [test_domcursor.html] [test_domrequest.html] +[test_domwindowutils.html] [test_e4x_for_each.html] [test_error.html] [test_gsp-qualified.html] @@ -52,4 +54,3 @@ support-files = [test_window_extensible.html] [test_window_indexing.html] [test_writable-replaceable.html] -[test_domwindowutils.html] diff --git a/dom/base/test/test_bug978522.html b/dom/base/test/test_bug978522.html new file mode 100644 index 000000000000..33d1d56a8f04 --- /dev/null +++ b/dom/base/test/test_bug978522.html @@ -0,0 +1,32 @@ + + + + + + Test for Bug 978522 - basic support + + + + +Mozilla Bug 978522 + + + diff --git a/dom/camera/GonkCameraParameters.cpp b/dom/camera/GonkCameraParameters.cpp index 5989f67152bf..ee291d547225 100644 --- a/dom/camera/GonkCameraParameters.cpp +++ b/dom/camera/GonkCameraParameters.cpp @@ -147,15 +147,18 @@ GonkCameraParameters::Initialize() rv = GetImpl(CAMERA_PARAM_SUPPORTED_MINEXPOSURECOMPENSATION, mExposureCompensationMin); if (NS_FAILED(rv)) { - return rv; + NS_WARNING("Failed to initialize minimum exposure compensation"); + mExposureCompensationMin = 0; } rv = GetImpl(CAMERA_PARAM_SUPPORTED_EXPOSURECOMPENSATIONSTEP, mExposureCompensationStep); if (NS_FAILED(rv)) { - return rv; + NS_WARNING("Failed to initialize exposure compensation step size"); + mExposureCompensationStep = 0; } rv = GetListAsArray(CAMERA_PARAM_SUPPORTED_ZOOMRATIOS, mZoomRatios); if (NS_FAILED(rv)) { - return rv; + // zoom is not supported + mZoomRatios.Clear(); } mInitialized = true; @@ -410,6 +413,11 @@ GonkCameraParameters::SetTranslated(uint32_t aKey, const double& aValue) switch (aKey) { case CAMERA_PARAM_EXPOSURECOMPENSATION: + if (mExposureCompensationStep == 0) { + DOM_CAMERA_LOGE("Exposure compensation not supported, can't set %f\n", aValue); + return NS_ERROR_NOT_AVAILABLE; + } + /** * Convert from real value to a Gonk index, round * to the nearest step; index is 1-based. @@ -422,34 +430,46 @@ GonkCameraParameters::SetTranslated(uint32_t aKey, const double& aValue) case CAMERA_PARAM_ZOOM: { + if (mZoomRatios.Length() == 0) { + DOM_CAMERA_LOGE("Zoom not supported, can't set %fx\n", aValue); + return NS_ERROR_NOT_AVAILABLE; + } + /** * Convert from a real zoom multipler (e.g. 2.5x) to * the index of the nearest supported value. */ value = aValue * 100.0; - // mZoomRatios is sorted, so we can binary search it - unsigned int bottom = 0; - unsigned int top = mZoomRatios.Length() - 1; - unsigned int middle; + if (value < mZoomRatios[0]) { + index = 0; + } else if (value > mZoomRatios.LastElement()) { + index = mZoomRatios.Length() - 1; + } else { + // mZoomRatios is sorted, so we can binary search it + int bottom = 0; + int top = mZoomRatios.Length() - 1; + int middle; - while (bottom != top) { - middle = (top + bottom) / 2; - if (value == mZoomRatios[middle]) { - // exact match - break; - } - if (value > mZoomRatios[middle] && value < mZoomRatios[middle + 1]) { - // the specified zoom value lies in this interval - break; - } - if (value > mZoomRatios[middle]) { - bottom = middle + 1; - } else { - top = middle - 1; + while (top >= bottom) { + middle = (top + bottom) / 2; + if (value == mZoomRatios[middle]) { + // exact match + break; + } + if (value > mZoomRatios[middle] && value < mZoomRatios[middle + 1]) { + // the specified zoom value lies in this interval + break; + } + if (value > mZoomRatios[middle]) { + bottom = middle + 1; + } else { + top = middle - 1; + } } + index = middle; } - index = middle; + DOM_CAMERA_LOGI("Zoom = %fx --> index = %d\n", aValue, index); } return SetImpl(CAMERA_PARAM_ZOOM, index); } @@ -616,16 +636,19 @@ GonkCameraParameters::GetListAsArray(uint32_t aKey, nsTArray& aArray) if (NS_FAILED(rv)) { return rv; } - if (!p) { - DOM_CAMERA_LOGW("Camera parameter %d not available (value is null)\n", aKey); - return NS_ERROR_NOT_AVAILABLE; - } - if (*p == '\0') { - DOM_CAMERA_LOGW("Camera parameter %d not available (value is empty string)\n", aKey); - return NS_ERROR_NOT_AVAILABLE; - } aArray.Clear(); + + // If there is no value available, just return the empty array. + if (!p) { + DOM_CAMERA_LOGI("Camera parameter %d not available (value is null)\n", aKey); + return NS_OK; + } + if (*p == '\0') { + DOM_CAMERA_LOGI("Camera parameter %d not available (value is empty string)\n", aKey); + return NS_OK; + } + const char* comma; while (p) { diff --git a/dom/camera/TestGonkCameraHardware.cpp b/dom/camera/TestGonkCameraHardware.cpp index 05ed6c6a850c..1f32b5375de4 100644 --- a/dom/camera/TestGonkCameraHardware.cpp +++ b/dom/camera/TestGonkCameraHardware.cpp @@ -56,6 +56,33 @@ TestGonkCameraHardware::TestCase() return test; } +const nsCString +TestGonkCameraHardware::GetExtraParameters() +{ + /** + * The contents of this pref are appended to the flattened string of + * parameters stuffed into GonkCameraParameters by the camera library. + * It consists of semicolon-delimited key=value pairs, e.g. + * + * focus-mode=auto;flash-mode=auto;preview-size=1024x768 + * + * The unflattening process breaks this string up on semicolon boundaries + * and sets an entry in a hashtable of strings with the token before + * the equals sign as the key, and the token after as the value. Because + * the string is parsed in order, key=value pairs occuring later in the + * string will replace value pairs appearing earlier, making it easy to + * inject fake, testable values into the parameters table. + * + * One constraint of this approach is that neither the key nor the value + * may contain equals signs or semicolons. We don't enforce that here + * so that we can also test correct handling of improperly-formatted values. + */ + const nsCString parameters = Preferences::GetCString("camera.control.test.hardware.gonk.parameters"); + DOM_CAMERA_LOGA("TestGonkCameraHardware : extra-parameters '%s'\n", + parameters.get()); + return parameters; +} + bool TestGonkCameraHardware::IsTestCaseInternal(const char* aTest, const char* aFile, int aLine) { @@ -174,7 +201,14 @@ TestGonkCameraHardware::PullParameters(GonkCameraParameters& aParams) return static_cast(TestCaseError(UNKNOWN_ERROR)); } - return GonkCameraHardware::PullParameters(aParams); + String8 s = mCamera->getParameters(); + nsCString extra = GetExtraParameters(); + if (!extra.IsEmpty()) { + s += ";"; + s += extra.get(); + } + + return aParams.Unflatten(s); } int diff --git a/dom/camera/TestGonkCameraHardware.h b/dom/camera/TestGonkCameraHardware.h index 2ee7d700bb24..04b27ad95bbf 100644 --- a/dom/camera/TestGonkCameraHardware.h +++ b/dom/camera/TestGonkCameraHardware.h @@ -55,6 +55,7 @@ public: protected: const nsCString TestCase(); + const nsCString GetExtraParameters(); bool IsTestCaseInternal(const char* aTest, const char* aFile, int aLine); int TestCaseError(int aDefaultError); diff --git a/dom/camera/test/camera_common.js b/dom/camera/test/camera_common.js index 0718e7f63de3..6f0a1c52db65 100644 --- a/dom/camera/test/camera_common.js +++ b/dom/camera/test/camera_common.js @@ -18,13 +18,41 @@ var CameraTest = (function() { * 'take-picture-process-failure' will simulate a failure of the * asynchronous picture-taking process, even if the initial API call * path seems to have succeeded. + * + * If 'camera.control.test.hardware.gonk.parameters' is set, it will cause + * the contents of that string to be appended to the string of parameters + * pulled from the Gonk camera library. This allows tests to inject fake + * settings/capabilities for features not supported by the emulator. These + * parameters are one or more semicolon-delimited key=value pairs, e.g. to + * pretend the emulator supports zoom: + * + * zoom-ratios=100,150,200,300,400;max-zoom=4 + * + * This means (of course) that neither the key not the value tokens can + * contain either equals signs or semicolons. The test shim doesn't enforce + * this so that we can test getting junk from the camera library as well. */ const PREF_TEST_ENABLED = "camera.control.test.enabled"; const PREF_TEST_HARDWARE = "camera.control.test.hardware"; + const PREF_TEST_EXTRA_PARAMETERS = "camera.control.test.hardware.gonk.parameters"; var oldTestEnabled; var oldTestHw; var testMode; + function testHardwareSetFakeParameters(parameters, callback) { + SpecialPowers.pushPrefEnv({'set': [[PREF_TEST_EXTRA_PARAMETERS, parameters]]}, function() { + var setParams = SpecialPowers.getCharPref(PREF_TEST_EXTRA_PARAMETERS); + ise(setParams, parameters, "Extra test parameters '" + setParams + "'"); + if (callback) { + callback(setParams); + } + }); + } + + function testHardwareClearFakeParameters(callback) { + SpecialPowers.pushPrefEnv({'clear': [[PREF_TEST_EXTRA_PARAMETERS]]}, callback); + } + function testHardwareSet(test, callback) { SpecialPowers.pushPrefEnv({'set': [[PREF_TEST_HARDWARE, test]]}, function() { var setTest = SpecialPowers.getCharPref(PREF_TEST_HARDWARE); @@ -58,6 +86,8 @@ var CameraTest = (function() { } catch(e) { } testMode = { set: testHardwareSet, + setFakeParameters: testHardwareSetFakeParameters, + clearFakeParameters: testHardwareClearFakeParameters, done: testHardwareDone }; if (callback) { @@ -68,32 +98,40 @@ var CameraTest = (function() { } function testEnd(callback) { - function allDone(cb) { - function cb2() { - SimpleTest.finish(); - if (cb) { - cb(); - } + // A chain of clean-up functions.... + function allCleanedUp() { + SimpleTest.finish(); + if (callback) { + callback(); } + } + function cleanUpTestEnabled() { + var next = allCleanedUp; if (oldTestEnabled) { - SpecialPowers.pushPrefEnv({'set': [[PREF_TEST_ENABLED, oldTestEnabled]]}, cb2); + SpecialPowers.pushPrefEnv({'set': [[PREF_TEST_ENABLED, oldTestEnabled]]}, next); } else { - SpecialPowers.pushPrefEnv({'clear': [[PREF_TEST_ENABLED]]}, cb2); + SpecialPowers.pushPrefEnv({'clear': [[PREF_TEST_ENABLED]]}, next); + } + } + function cleanUpTest() { + var next = cleanUpTestEnabled; + if (testMode) { + testMode.done(next); + testMode = null; + } else { + next(); + } + } + function cleanUpExtraParameters() { + var next = cleanUpTest; + if (testMode) { + testMode.clearFakeParameters(next); + } else { + next(); } } - if (testMode) { - testMode.done(function() { - allDone(callback); - }); - testMode = null; - } else { - allDone(function() { - if (callback) { - callback(); - } - }); - } + cleanUpExtraParameters(); } ise(SpecialPowers.sanityCheck(), "foo", "SpecialPowers passed sanity check"); diff --git a/dom/camera/test/mochitest.ini b/dom/camera/test/mochitest.ini index 6eefa4bef1df..1dd0cb2ba7da 100644 --- a/dom/camera/test/mochitest.ini +++ b/dom/camera/test/mochitest.ini @@ -7,3 +7,4 @@ support-files = camera_common.js [test_camera_hardware_init_failure.html] [test_camera_hardware_failures.html] [test_bug975472.html] +[test_camera_fake_parameters.html] diff --git a/dom/camera/test/test_camera_fake_parameters.html b/dom/camera/test/test_camera_fake_parameters.html new file mode 100644 index 000000000000..629c961159a4 --- /dev/null +++ b/dom/camera/test/test_camera_fake_parameters.html @@ -0,0 +1,135 @@ + + + + Test for CameraParameters we need to fake + + + + + + + Mozilla Bug 976802 + + This image is going to load + + + + + diff --git a/dom/devicestorage/nsDeviceStorage.cpp b/dom/devicestorage/nsDeviceStorage.cpp index 913ecd164869..c616f184b636 100644 --- a/dom/devicestorage/nsDeviceStorage.cpp +++ b/dom/devicestorage/nsDeviceStorage.cpp @@ -18,6 +18,7 @@ #include "mozilla/dom/PermissionMessageUtils.h" #include "mozilla/LazyIdleThread.h" #include "mozilla/Preferences.h" +#include "mozilla/Scoped.h" #include "mozilla/Services.h" #include "nsAutoPtr.h" @@ -74,6 +75,10 @@ using namespace mozilla::ipc; #include "nsDirectoryServiceDefs.h" +namespace mozilla { + MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE(ScopedPRFileDesc, PRFileDesc, PR_Close); +} + StaticAutoPtr DeviceStorageUsedSpaceCache::sDeviceStorageUsedSpaceCache; @@ -933,14 +938,16 @@ DeviceStorageFile::AppendRelativePath(const nsAString& aPath) { nsresult DeviceStorageFile::CreateFileDescriptor(FileDescriptor& aFileDescriptor) { - PRFileDesc* fd; + ScopedPRFileDesc fd; nsresult rv = mFile->OpenNSPRFileDesc(PR_RDWR | PR_CREATE_FILE, - 0660, &fd); + 0660, &fd.rwget()); NS_ENSURE_SUCCESS(rv, rv); + // NOTE: The FileDescriptor::PlatformHandleType constructor returns a dup of + // the file descriptor, so we don't need the original fd after this. + // Our scoped file descriptor will automatically close fd. aFileDescriptor = FileDescriptor::PlatformHandleType(PR_FileDesc2NativeHandle(fd)); - return NS_OK; } diff --git a/dom/events/DataTransfer.cpp b/dom/events/DataTransfer.cpp index 30a8fa4ec12a..fd1f06e9bd56 100644 --- a/dom/events/DataTransfer.cpp +++ b/dom/events/DataTransfer.cpp @@ -56,6 +56,7 @@ NS_IMPL_CYCLE_COLLECTING_ADDREF(DataTransfer) NS_IMPL_CYCLE_COLLECTING_RELEASE(DataTransfer) NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DataTransfer) + NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY NS_INTERFACE_MAP_ENTRY(mozilla::dom::DataTransfer) NS_INTERFACE_MAP_ENTRY(nsIDOMDataTransfer) NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMDataTransfer) diff --git a/dom/events/nsIMEStateManager.cpp b/dom/events/nsIMEStateManager.cpp index 5393be127be8..4110c6c94944 100644 --- a/dom/events/nsIMEStateManager.cpp +++ b/dom/events/nsIMEStateManager.cpp @@ -35,6 +35,10 @@ #include "TextComposition.h" #include "mozilla/Preferences.h" #include "nsAsyncDOMEvent.h" +#include "nsIDocShell.h" +#include "nsIReflowObserver.h" +#include "nsIScrollObserver.h" +#include "nsWeakReference.h" using namespace mozilla; using namespace mozilla::dom; @@ -46,7 +50,10 @@ using namespace mozilla::widget; // sTextStateObserver is null if there is no focused editor class nsTextStateManager MOZ_FINAL : public nsISelectionListener, - public nsStubMutationObserver + public nsStubMutationObserver, + public nsIReflowObserver, + public nsIScrollObserver, + public nsSupportsWeakReference { public: nsTextStateManager() @@ -61,6 +68,10 @@ public: NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTEWILLCHANGE NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTECHANGED + NS_DECL_NSIREFLOWOBSERVER + + // nsIScrollObserver + virtual void ScrollPositionChanged() MOZ_OVERRIDE; void Init(nsIWidget* aWidget, nsPresContext* aPresContext, @@ -82,6 +93,7 @@ private: void NotifyContentAdded(nsINode* aContainer, int32_t aStart, int32_t aEnd); void ObserveEditableNode(); + nsCOMPtr mDocShell; nsIMEUpdatePreference mUpdatePreference; uint32_t mPreAttrChangeLength; }; @@ -752,6 +764,8 @@ nsTextStateManager::Init(nsIWidget* aWidget, return; } + mDocShell = aPresContext->GetDocShell(); + ObserveEditableNode(); } @@ -774,6 +788,13 @@ nsTextStateManager::ObserveEditableNode() // add text change observer mRootContent->AddMutationObserver(this); } + + if (mUpdatePreference.WantPositionChanged() && mDocShell) { + // Add scroll position listener and reflow observer to detect position and + // size changes + mDocShell->AddWeakScrollObserver(this); + mDocShell->AddWeakReflowObserver(this); + } } void @@ -800,8 +821,13 @@ nsTextStateManager::Destroy(void) if (mUpdatePreference.WantTextChange() && mRootContent) { mRootContent->RemoveMutationObserver(this); } + if (mUpdatePreference.WantPositionChanged() && mDocShell) { + mDocShell->RemoveWeakScrollObserver(this); + mDocShell->RemoveWeakReflowObserver(this); + } mRootContent = nullptr; mEditableNode = nullptr; + mDocShell = nullptr; mUpdatePreference.mWantUpdates = nsIMEUpdatePreference::NOTIFY_NOTHING; } @@ -833,9 +859,12 @@ nsTextStateManager::IsEditorHandlingEventForComposition() const return composition->IsEditorHandlingEvent(); } -NS_IMPL_ISUPPORTS2(nsTextStateManager, +NS_IMPL_ISUPPORTS5(nsTextStateManager, nsIMutationObserver, - nsISelectionListener) + nsISelectionListener, + nsIReflowObserver, + nsIScrollObserver, + nsISupportsWeakReference) // Helper class, used for selection change notification class SelectionChangeEvent : public nsRunnable { @@ -917,6 +946,54 @@ private: bool mCausedByComposition; }; +class PositionChangeEvent MOZ_FINAL : public nsRunnable +{ +public: + PositionChangeEvent(nsTextStateManager* aDispatcher) + : mDispatcher(aDispatcher) { + MOZ_ASSERT(mDispatcher); + } + + NS_IMETHOD Run() { + if (mDispatcher->mWidget) { + mDispatcher->mWidget->NotifyIME( + IMENotification(NOTIFY_IME_OF_POSITION_CHANGE)); + } + return NS_OK; + } + +private: + nsRefPtr mDispatcher; +}; + +void +nsTextStateManager::ScrollPositionChanged() +{ + if (mWidget) { + nsContentUtils::AddScriptRunner(new PositionChangeEvent(this)); + } +} + +NS_IMETHODIMP +nsTextStateManager::Reflow(DOMHighResTimeStamp aStart, + DOMHighResTimeStamp aEnd) +{ + if (mWidget) { + nsContentUtils::AddScriptRunner(new PositionChangeEvent(this)); + } + return NS_OK; +} + +NS_IMETHODIMP +nsTextStateManager::ReflowInterruptible(DOMHighResTimeStamp aStart, + DOMHighResTimeStamp aEnd) +{ + if (mWidget) { + nsContentUtils::AddScriptRunner(new PositionChangeEvent(this)); + } + return NS_OK; +} + void nsTextStateManager::CharacterDataChanged(nsIDocument* aDocument, nsIContent* aContent, diff --git a/dom/src/geolocation/nsGeolocation.cpp b/dom/src/geolocation/nsGeolocation.cpp index ead7aabb2ccd..bcd04a9f4d97 100644 --- a/dom/src/geolocation/nsGeolocation.cpp +++ b/dom/src/geolocation/nsGeolocation.cpp @@ -694,6 +694,10 @@ nsresult nsGeolocationService::Init() } #endif + if (Preferences::GetBool("geo.provider.use_mls", false)) { + mProvider = do_GetService("@mozilla.org/geolocation/mls-provider;1"); + } + // Override platform-specific providers with the default (network) // provider while testing. Our tests are currently not meant to exercise // the provider, and some tests rely on the network provider being used. diff --git a/dom/system/NetworkGeolocationProvider.manifest b/dom/system/NetworkGeolocationProvider.manifest index 50f5c925b4d3..3ba4ba06ee9a 100644 --- a/dom/system/NetworkGeolocationProvider.manifest +++ b/dom/system/NetworkGeolocationProvider.manifest @@ -1,2 +1,3 @@ component {77DA64D3-7458-4920-9491-86CC9914F904} NetworkGeolocationProvider.js contract @mozilla.org/geolocation/provider;1 {77DA64D3-7458-4920-9491-86CC9914F904} +contract @mozilla.org/geolocation/mls-provider;1 {77DA64D3-7458-4920-9491-86CC9914F904} diff --git a/dom/system/gonk/tests/test_ril_worker_icc.js b/dom/system/gonk/tests/test_ril_worker_icc.js index ac806c33036e..1616c157919f 100644 --- a/dom/system/gonk/tests/test_ril_worker_icc.js +++ b/dom/system/gonk/tests/test_ril_worker_icc.js @@ -2102,6 +2102,30 @@ add_test(function test_error_message_update_icc_contact() { run_next_test(); }); +add_test(function test_process_icc_io_error() { + let worker = newUint8Worker(); + let context = worker.ContextPool._contexts[0]; + let ioHelper = context.ICCIOHelper; + + function do_test(errorCode, expectedErrorMsg) { + let called = false; + function errorCb(errorMsg) { + called = true; + do_check_eq(errorMsg, expectedErrorMsg); + } + + ioHelper.processICCIOError({rilRequestError: errorCode, + onerror: errorCb}); + do_check_true(called); + } + + for (let i = 0; i < ERROR_REJECTED_BY_REMOTE + 1; i++) { + do_test(i, RIL_ERROR_TO_GECKO_ERROR[i]); + } + + run_next_test(); +}); + add_test(function test_personalization_state() { let worker = newUint8Worker(); let context = worker.ContextPool._contexts[0]; diff --git a/dom/system/moz.build b/dom/system/moz.build index ffbf74c05f12..971637b4adaa 100644 --- a/dom/system/moz.build +++ b/dom/system/moz.build @@ -38,13 +38,10 @@ UNIFIED_SOURCES += [ 'OSFileConstants.cpp', ] -# On Systems that have build in geolocation providers, -# we really do not need these. -if CONFIG['OS_TARGET'] != 'Android' or CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk': - EXTRA_COMPONENTS += [ - 'NetworkGeolocationProvider.js', - 'NetworkGeolocationProvider.manifest', - ] +EXTRA_COMPONENTS += [ + 'NetworkGeolocationProvider.js', + 'NetworkGeolocationProvider.manifest', +] FAIL_ON_WARNINGS = True diff --git a/dom/tests/mochitest/localstorage/test_localStorageEnablePref.html b/dom/tests/mochitest/localstorage/test_localStorageEnablePref.html index b6d26068f129..88fd81e0b5a7 100644 --- a/dom/tests/mochitest/localstorage/test_localStorageEnablePref.html +++ b/dom/tests/mochitest/localstorage/test_localStorageEnablePref.html @@ -7,6 +7,8 @@ + diff --git a/layout/base/tests/bug687297_b.html b/layout/base/tests/bug687297_b.html new file mode 100644 index 000000000000..34f682354dc3 --- /dev/null +++ b/layout/base/tests/bug687297_b.html @@ -0,0 +1,17 @@ + + + + + Test companion for Bug 687297 + + + +
ABCDEFG 0123456
+ + + diff --git a/layout/base/tests/bug687297_c.html b/layout/base/tests/bug687297_c.html new file mode 100644 index 000000000000..ea029d24e551 --- /dev/null +++ b/layout/base/tests/bug687297_c.html @@ -0,0 +1,17 @@ + + + + + Test companion for Bug 687297 + + + +
ABCDEFG 0123456
+ + + diff --git a/layout/base/tests/mochitest.ini b/layout/base/tests/mochitest.ini index e3089a04fac7..901d5325559b 100644 --- a/layout/base/tests/mochitest.ini +++ b/layout/base/tests/mochitest.ini @@ -453,3 +453,8 @@ skip-if = toolkit == "win" skip-if = toolkit == "win" [test_flush_on_paint.html] skip-if = true || (toolkit == 'android') || (toolkit == "cocoa") # Bug 688128, bug 539356 +[test_bug687297.html] +support-files = + bug687297_a.html + bug687297_b.html + bug687297_c.html diff --git a/layout/base/tests/test_bug687297.html b/layout/base/tests/test_bug687297.html new file mode 100644 index 000000000000..6ec9aaf4fe39 --- /dev/null +++ b/layout/base/tests/test_bug687297.html @@ -0,0 +1,54 @@ + + + + + + Test for Bug 687297 + + + + + +Mozilla Bug 687297 +

+ +
+  
+
+ + diff --git a/layout/forms/nsColorControlFrame.cpp b/layout/forms/nsColorControlFrame.cpp index ff3fbd374111..8140c37f6f77 100644 --- a/layout/forms/nsColorControlFrame.cpp +++ b/layout/forms/nsColorControlFrame.cpp @@ -31,6 +31,7 @@ NS_NewColorControlFrame(nsIPresShell* aPresShell, nsStyleContext* aContext) NS_IMPL_FRAMEARENA_HELPERS(nsColorControlFrame) NS_QUERYFRAME_HEAD(nsColorControlFrame) + NS_QUERYFRAME_ENTRY(nsColorControlFrame) NS_QUERYFRAME_ENTRY(nsIAnonymousContentCreator) NS_QUERYFRAME_TAIL_INHERITING(nsColorControlFrameSuper) diff --git a/layout/forms/nsColorControlFrame.h b/layout/forms/nsColorControlFrame.h index b796d1b94516..832996639775 100644 --- a/layout/forms/nsColorControlFrame.h +++ b/layout/forms/nsColorControlFrame.h @@ -25,8 +25,9 @@ public: virtual void DestroyFrom(nsIFrame* aDestructRoot) MOZ_OVERRIDE; - NS_DECL_FRAMEARENA_HELPERS + NS_DECL_QUERYFRAME_TARGET(nsColorControlFrame) NS_DECL_QUERYFRAME + NS_DECL_FRAMEARENA_HELPERS virtual nsIAtom* GetType() const MOZ_OVERRIDE; @@ -48,12 +49,12 @@ public: virtual Element* GetPseudoElement(nsCSSPseudoElements::Type aType) MOZ_OVERRIDE; + // Refresh the color swatch, using associated input's value + nsresult UpdateColor(); + private: nsColorControlFrame(nsStyleContext* aContext); - // Update the color swatch - nsresult UpdateColor(); - nsCOMPtr mColorContent; }; diff --git a/layout/generic/crashtests/513110-1.html b/layout/generic/crashtests/513110-1.html new file mode 100644 index 000000000000..f33067cd4e1e --- /dev/null +++ b/layout/generic/crashtests/513110-1.html @@ -0,0 +1,23 @@ + + + + + + + +a +
+ + + diff --git a/layout/generic/crashtests/513110-2.xhtml b/layout/generic/crashtests/513110-2.xhtml new file mode 100644 index 000000000000..e1fcb499d97b --- /dev/null +++ b/layout/generic/crashtests/513110-2.xhtml @@ -0,0 +1,5 @@ + + +1
+ + diff --git a/layout/generic/crashtests/crashtests.list b/layout/generic/crashtests/crashtests.list index 326b0f3993bb..fb913e751f74 100644 --- a/layout/generic/crashtests/crashtests.list +++ b/layout/generic/crashtests/crashtests.list @@ -105,7 +105,7 @@ load 375831.html load 376419.html load 377522.html load 379217-1.xhtml -asserts(1-2) load 379217-2.xhtml # Bug 439204 +load 379217-2.xhtml load 379917-1.xhtml load 380012-1.html load 381152-1.html @@ -125,7 +125,7 @@ load 385344-2.html load 385414-1.html load 385414-2.html load 385426-1.html -skip-if(B2G) load 385526.html # Bug 891347 +skip-if(B2G) skip-if(Android&&AndroidVersion==10) load 385526.html # Bug 891347 load 385681.html load 385885-1.xul load 386799-1.html @@ -368,6 +368,8 @@ load 511482.html load 512724-1.html load 512725-1.html load 512749-1.html +load 513110-1.html +load 513110-2.xhtml load 513394-1.html load 514098-1.xhtml load 514800-1.html @@ -523,3 +525,4 @@ test-pref(layout.css.sticky.enabled,true) load 915475.xhtml load 943509-1.html asserts(4-8) load 944909-1.html test-pref(layout.css.sticky.enabled,true) load 949932.html +load outline-on-frameset.xhtml diff --git a/layout/generic/crashtests/outline-on-frameset.xhtml b/layout/generic/crashtests/outline-on-frameset.xhtml new file mode 100644 index 000000000000..9f72d10cc18a --- /dev/null +++ b/layout/generic/crashtests/outline-on-frameset.xhtml @@ -0,0 +1 @@ + diff --git a/layout/generic/nsBlockFrame.cpp b/layout/generic/nsBlockFrame.cpp index c2c57ad904ec..c1e45d42788f 100644 --- a/layout/generic/nsBlockFrame.cpp +++ b/layout/generic/nsBlockFrame.cpp @@ -1385,7 +1385,7 @@ nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState, // Include the float manager's state to properly account for the // bottom margin of any floated elements; e.g., inside a table cell. nscoord floatHeight = - aState.ClearFloats(bottomEdgeOfChildren, NS_STYLE_CLEAR_LEFT_AND_RIGHT, + aState.ClearFloats(bottomEdgeOfChildren, NS_STYLE_CLEAR_BOTH, nullptr, nsFloatManager::DONT_CLEAR_PUSHED_FLOATS); bottomEdgeOfChildren = std::max(bottomEdgeOfChildren, floatHeight); } @@ -3756,7 +3756,7 @@ nsBlockFrame::ReflowInlineFrame(nsBlockReflowState& aState, uint8_t breakType = NS_INLINE_GET_BREAK_TYPE(frameReflowStatus); NS_ASSERTION((NS_STYLE_CLEAR_NONE != breakType) || (NS_STYLE_CLEAR_NONE != aState.mFloatBreakType), "bad break type"); - NS_ASSERTION(NS_STYLE_CLEAR_LAST_VALUE >= breakType, "invalid break type"); + NS_ASSERTION(NS_STYLE_CLEAR_MAX >= breakType, "invalid break type"); if (NS_INLINE_IS_BREAK_BEFORE(frameReflowStatus)) { // Break-before cases. @@ -5978,7 +5978,7 @@ nsBlockFrame::ReflowPushedFloats(nsBlockReflowState& aState, } // If there are continued floats, then we may need to continue BR clearance - if (0 != aState.ClearFloats(0, NS_STYLE_CLEAR_LEFT_AND_RIGHT)) { + if (0 != aState.ClearFloats(0, NS_STYLE_CLEAR_BOTH)) { aState.mFloatBreakType = static_cast(GetPrevInFlow()) ->FindTrailingClear(); } diff --git a/layout/generic/nsFloatManager.cpp b/layout/generic/nsFloatManager.cpp index 56bb61bef893..467e0d056ba4 100644 --- a/layout/generic/nsFloatManager.cpp +++ b/layout/generic/nsFloatManager.cpp @@ -455,7 +455,7 @@ nsFloatManager::ClearFloats(nscoord aY, uint8_t aBreakType, const FloatInfo &tail = mFloats[mFloats.Length() - 1]; switch (aBreakType) { - case NS_STYLE_CLEAR_LEFT_AND_RIGHT: + case NS_STYLE_CLEAR_BOTH: bottom = std::max(bottom, tail.mLeftYMost); bottom = std::max(bottom, tail.mRightYMost); break; @@ -479,10 +479,10 @@ bool nsFloatManager::ClearContinues(uint8_t aBreakType) const { return ((mPushedLeftFloatPastBreak || mSplitLeftFloatAcrossBreak) && - (aBreakType == NS_STYLE_CLEAR_LEFT_AND_RIGHT || + (aBreakType == NS_STYLE_CLEAR_BOTH || aBreakType == NS_STYLE_CLEAR_LEFT)) || ((mPushedRightFloatPastBreak || mSplitRightFloatAcrossBreak) && - (aBreakType == NS_STYLE_CLEAR_LEFT_AND_RIGHT || + (aBreakType == NS_STYLE_CLEAR_BOTH || aBreakType == NS_STYLE_CLEAR_RIGHT)); } diff --git a/layout/generic/nsFrame.cpp b/layout/generic/nsFrame.cpp index a8bc8791a1b3..c647148c7dc6 100644 --- a/layout/generic/nsFrame.cpp +++ b/layout/generic/nsFrame.cpp @@ -3804,7 +3804,7 @@ nsIFrame::InlinePrefWidthData::ForceBreak(nsRenderingContext *aRenderingContext) const nsStyleDisplay *floatDisp = floatInfo.Frame()->StyleDisplay(); if (floatDisp->mBreakType == NS_STYLE_CLEAR_LEFT || floatDisp->mBreakType == NS_STYLE_CLEAR_RIGHT || - floatDisp->mBreakType == NS_STYLE_CLEAR_LEFT_AND_RIGHT) { + floatDisp->mBreakType == NS_STYLE_CLEAR_BOTH) { nscoord floats_cur = NSCoordSaturatingAdd(floats_cur_left, floats_cur_right); if (floats_cur > floats_done) diff --git a/layout/generic/nsFrameList.h b/layout/generic/nsFrameList.h index abe6a621100a..ff1e16539970 100644 --- a/layout/generic/nsFrameList.h +++ b/layout/generic/nsFrameList.h @@ -9,7 +9,7 @@ #include /* for FILE* */ #include "nsDebug.h" -#ifdef DEBUG +#if defined(DEBUG) || defined(MOZ_DUMP_PAINTING) // DEBUG_FRAME_DUMP enables nsIFrame::List and related methods. // You can also define this in a non-DEBUG build if you need frame dumps. #define DEBUG_FRAME_DUMP 1 diff --git a/layout/generic/nsFrameSetFrame.cpp b/layout/generic/nsFrameSetFrame.cpp index c2e080836088..38873121dbc7 100644 --- a/layout/generic/nsFrameSetFrame.cpp +++ b/layout/generic/nsFrameSetFrame.cpp @@ -1137,6 +1137,7 @@ nsHTMLFramesetFrame::Reflow(nsPresContext* aPresContext, mDrag.UnSet(); aDesiredSize.SetOverflowAreasToDesiredBounds(); + FinishAndStoreOverflow(&aDesiredSize); NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize); return NS_OK; diff --git a/layout/generic/nsGfxScrollFrame.cpp b/layout/generic/nsGfxScrollFrame.cpp index 7f011c494780..5a31048656c5 100644 --- a/layout/generic/nsGfxScrollFrame.cpp +++ b/layout/generic/nsGfxScrollFrame.cpp @@ -2085,6 +2085,8 @@ ScrollFrameHelper::ScrollToImpl(nsPoint aPt, const nsRect& aRange, nsIAtom* aOri for (uint32_t i = 0; i < mListeners.Length(); i++) { mListeners[i]->ScrollPositionDidChange(pt.x, pt.y); } + + presContext->GetDocShell()->NotifyScrollObservers(); } static void diff --git a/layout/generic/nsLineBox.cpp b/layout/generic/nsLineBox.cpp index f1b553a27bd4..039d8b062f04 100644 --- a/layout/generic/nsLineBox.cpp +++ b/layout/generic/nsLineBox.cpp @@ -43,7 +43,7 @@ nsLineBox::nsLineBox(nsIFrame* aFrame, int32_t aCount, bool aIsBlock) } #endif - static_assert(NS_STYLE_CLEAR_LAST_VALUE <= 15, + static_assert(NS_STYLE_CLEAR_MAX <= 15, "FlagBits needs more bits to store the full range of " "break type ('clear') values"); #if NS_STYLE_CLEAR_NONE > 0 @@ -197,7 +197,7 @@ BreakTypeToString(uint8_t aBreakType) case NS_STYLE_CLEAR_NONE: return "nobr"; case NS_STYLE_CLEAR_LEFT: return "leftbr"; case NS_STYLE_CLEAR_RIGHT: return "rightbr"; - case NS_STYLE_CLEAR_LEFT_AND_RIGHT: return "leftbr+rightbr"; + case NS_STYLE_CLEAR_BOTH: return "leftbr+rightbr"; case NS_STYLE_CLEAR_LINE: return "linebr"; default: break; diff --git a/layout/generic/nsLineBox.h b/layout/generic/nsLineBox.h index f9b8b3215a9f..6920404edc48 100644 --- a/layout/generic/nsLineBox.h +++ b/layout/generic/nsLineBox.h @@ -399,7 +399,10 @@ public: } void SetBreakTypeBefore(uint8_t aBreakType) { NS_ASSERTION(IsBlock(), "Only blocks have break-before"); - NS_ASSERTION(aBreakType <= NS_STYLE_CLEAR_LEFT_AND_RIGHT, + NS_ASSERTION(aBreakType == NS_STYLE_CLEAR_NONE || + aBreakType == NS_STYLE_CLEAR_LEFT || + aBreakType == NS_STYLE_CLEAR_RIGHT || + aBreakType == NS_STYLE_CLEAR_BOTH, "Only float break types are allowed before a line"); mFlags.mBreakType = aBreakType; } @@ -418,7 +421,7 @@ public: bool HasFloatBreakAfter() const { return !IsBlock() && (NS_STYLE_CLEAR_LEFT == mFlags.mBreakType || NS_STYLE_CLEAR_RIGHT == mFlags.mBreakType || - NS_STYLE_CLEAR_LEFT_AND_RIGHT == mFlags.mBreakType); + NS_STYLE_CLEAR_BOTH == mFlags.mBreakType); } uint8_t GetBreakTypeAfter() const { return !IsBlock() ? mFlags.mBreakType : NS_STYLE_CLEAR_NONE; diff --git a/layout/generic/nsLineLayout.cpp b/layout/generic/nsLineLayout.cpp index a8ad279caee2..d79e0420610b 100644 --- a/layout/generic/nsLineLayout.cpp +++ b/layout/generic/nsLineLayout.cpp @@ -323,8 +323,6 @@ nsLineLayout::UpdateBand(const nsRect& aNewAvailSpace, for (PerSpanData* psd = mCurrentSpan; psd; psd = psd->mParent) { psd->mRightEdge += deltaWidth; psd->mContainsFloat = true; - NS_ASSERTION(psd->mX - mTrimmableWidth <= psd->mRightEdge, - "We placed a float where there was no room!"); #ifdef NOISY_REFLOW printf(" span %p: oldRightEdge=%d newRightEdge=%d\n", psd, psd->mRightEdge - deltaRightEdge, psd->mRightEdge); diff --git a/layout/reftests/border-radius/clipping-6-ref.html b/layout/reftests/border-radius/clipping-6-ref.html new file mode 100644 index 000000000000..0a7ba42bd8a8 --- /dev/null +++ b/layout/reftests/border-radius/clipping-6-ref.html @@ -0,0 +1,15 @@ + + + + + + +
+
+
+
Hi
+
+
+
+ diff --git a/layout/reftests/border-radius/clipping-6.html b/layout/reftests/border-radius/clipping-6.html new file mode 100644 index 000000000000..ad456d32fa34 --- /dev/null +++ b/layout/reftests/border-radius/clipping-6.html @@ -0,0 +1,13 @@ + + + + + + +
+
+
Hi
+
+
+ diff --git a/layout/reftests/border-radius/clipping-7-ref.html b/layout/reftests/border-radius/clipping-7-ref.html new file mode 100644 index 000000000000..1d83e5baa0ae --- /dev/null +++ b/layout/reftests/border-radius/clipping-7-ref.html @@ -0,0 +1,13 @@ + + + + + + +
+
+
+
+
+ diff --git a/layout/reftests/border-radius/clipping-7.html b/layout/reftests/border-radius/clipping-7.html new file mode 100644 index 000000000000..f435d2c41c7b --- /dev/null +++ b/layout/reftests/border-radius/clipping-7.html @@ -0,0 +1,13 @@ + + + + + + +
+
+
+
+
+ diff --git a/layout/reftests/border-radius/reftest.list b/layout/reftests/border-radius/reftest.list index 5adce02b2376..e339a15ee24f 100644 --- a/layout/reftests/border-radius/reftest.list +++ b/layout/reftests/border-radius/reftest.list @@ -49,6 +49,8 @@ fuzzy-if(/^Windows\x20NT\x206\.2/.test(http.oscpu),1,5) == clipping-5-image.html fuzzy-if(/^Windows\x20NT\x206\.2/.test(http.oscpu),1,5) == clipping-5-overflow-hidden.html clipping-5-ref.html fuzzy-if(/^Windows\x20NT\x206\.2/.test(http.oscpu),1,5) fuzzy-if(Android,5,21) == clipping-5-refi.html clipping-5-ref.html fuzzy-if(true,1,7) fuzzy-if(cocoaWidget,1,99) fuzzy-if(Android&&browserIsRemote,7,89) fuzzy-if(Android&&!browserIsRemote,99,115) == clipping-5-refc.html clipping-5-ref.html # bug 732535 +fuzzy-if(winWidget,105,71) fuzzy-if(Android,8,464) == clipping-6.html clipping-6-ref.html # ThebesLayer and MaskLayer with transforms that aren't identical +fuzzy-if(true,1,29) fuzzy-if(Android&&AndroidVersion<15,12,81) fuzzy-if(Android&&AndroidVersion>=15,255,586) == clipping-7.html clipping-7-ref.html # ColorLayer and MaskLayer with transforms that aren't identical. Reference image rendered without using layers (which causes fuzzy failures). fuzzy-if(/^Windows\x20NT\x206\.2/.test(http.oscpu),1,5) == clipping-and-zindex-1.html clipping-and-zindex-1-ref.html fuzzy-if(cocoaWidget,1,4) == intersecting-clipping-1-canvas.html intersecting-clipping-1-refc.html == intersecting-clipping-1-image.html intersecting-clipping-1-refi.html diff --git a/layout/reftests/bugs/reftest.list b/layout/reftests/bugs/reftest.list index 450ac3378211..ccc90196c73c 100644 --- a/layout/reftests/bugs/reftest.list +++ b/layout/reftests/bugs/reftest.list @@ -1721,7 +1721,7 @@ skip-if(B2G) == 751012-1b.html 751012-1-ref.html random-if(Android) == 753329-1.html about:blank == 758561-1.html 758561-1-ref.html fuzzy-if(true,1,19) fails-if(d2d) random-if(Android&&AndroidVersion<15) == 759036-1.html 759036-1-ref.html -fuzzy-if(true,17,5860) random-if(Android&&AndroidVersion<15) == 759036-2.html 759036-2-ref.html +fuzzy-if(true,17,5879) random-if(Android&&AndroidVersion<15) == 759036-2.html 759036-2-ref.html random-if(Android&&AndroidVersion<15) == 776265-1a.html 776265-1-ref.html == 776265-1b.html 776265-1-ref.html == 776265-1c.html 776265-1-ref.html diff --git a/layout/reftests/font-features/reftest.list b/layout/reftests/font-features/reftest.list index 073d910f7b61..bd225bb4bcdc 100644 --- a/layout/reftests/font-features/reftest.list +++ b/layout/reftests/font-features/reftest.list @@ -14,8 +14,7 @@ HTTP(..) != font-features-noliga.html font-features-ref.html HTTP(..) != font-features-hlig.html font-features-ref.html # compare Turkish rendering with reference using ZWNJ to break the ligature -# (also works via Pango) -fails-if(d2d) HTTP(..) == font-features-turkish.html font-features-turkish-ref.html +HTTP(..) == font-features-turkish.html font-features-turkish-ref.html # compare Turkish rendering with explicitly disabled ligatures HTTP(..) == font-features-turkish.html font-features-noliga.html diff --git a/layout/reftests/forms/input/color/block-invalidate-2-ref.html b/layout/reftests/forms/input/color/block-invalidate-2-ref.html new file mode 100644 index 000000000000..9def78fad153 --- /dev/null +++ b/layout/reftests/forms/input/color/block-invalidate-2-ref.html @@ -0,0 +1,9 @@ + + + +

Test for bug 977038

+
+ +
+ + diff --git a/layout/reftests/forms/input/color/block-invalidate-2.html b/layout/reftests/forms/input/color/block-invalidate-2.html new file mode 100644 index 000000000000..efc2acb84172 --- /dev/null +++ b/layout/reftests/forms/input/color/block-invalidate-2.html @@ -0,0 +1,19 @@ + + + + +

Test for bug 977038

+
+ +
+ + diff --git a/layout/reftests/forms/input/color/reftest.list b/layout/reftests/forms/input/color/reftest.list index 9d87224fb8d3..dd30d1dcfc70 100644 --- a/layout/reftests/forms/input/color/reftest.list +++ b/layout/reftests/forms/input/color/reftest.list @@ -9,6 +9,7 @@ default-preferences pref(dom.forms.color,true) # excluded from some style in forms.css, which makes the following tests fail. fails-if(B2G||Android) == margin-padding-1.html margin-padding-1-ref.html == block-invalidate-1.html block-invalidate-1-ref.html +== block-invalidate-2.html block-invalidate-2-ref.html fails-if(B2G||Android) == transformations-1.html transformations-1-ref.html fails-if(B2G||Android) == custom-style-1.html custom-style-1-ref.html fails-if(B2G||Android) == custom-style-2.html custom-style-2-ref.html diff --git a/layout/reftests/invalidation/test-image-layers-ref.html b/layout/reftests/invalidation/test-image-layers-ref.html index 46af2e2a93fb..fce127b73713 100644 --- a/layout/reftests/invalidation/test-image-layers-ref.html +++ b/layout/reftests/invalidation/test-image-layers-ref.html @@ -2,7 +2,7 @@
- +
diff --git a/layout/reftests/invalidation/test-image-layers.html b/layout/reftests/invalidation/test-image-layers.html index 57acc99a7c03..7c1ae7d8e035 100644 --- a/layout/reftests/invalidation/test-image-layers.html +++ b/layout/reftests/invalidation/test-image-layers.html @@ -2,7 +2,7 @@
- +