diff --git a/accessible/tests/mochitest/test_nsIAccessibleDocument.html b/accessible/tests/mochitest/test_nsIAccessibleDocument.html index 9eb61e18d27d..12b46643495d 100644 --- a/accessible/tests/mochitest/test_nsIAccessibleDocument.html +++ b/accessible/tests/mochitest/test_nsIAccessibleDocument.html @@ -15,8 +15,11 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=441737 + + diff --git a/content/html/content/test/file_fullscreen-api.html b/content/html/content/test/file_fullscreen-api.html index e69e465ffb2f..70e2e483ee34 100644 --- a/content/html/content/test/file_fullscreen-api.html +++ b/content/html/content/test/file_fullscreen-api.html @@ -16,7 +16,7 @@ Test DOM full-screen API. } - + diff --git a/content/html/content/test/file_fullscreen-denied.html b/content/html/content/test/file_fullscreen-denied.html index d1391390a4a2..161eacfe2756 100644 --- a/content/html/content/test/file_fullscreen-denied.html +++ b/content/html/content/test/file_fullscreen-denied.html @@ -15,7 +15,7 @@ Test DOM full-screen API. } - + diff --git a/content/html/content/test/file_fullscreen-hidden.html b/content/html/content/test/file_fullscreen-hidden.html index 5049cfae86da..2a1fd0dc053b 100644 --- a/content/html/content/test/file_fullscreen-hidden.html +++ b/content/html/content/test/file_fullscreen-hidden.html @@ -8,7 +8,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=697636 - + @@ -25,7 +25,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=697636 var frameWin; var e1; -function boom() +function begin() { frameWin = document.getElementById("f").contentWindow; e1 = frameWin.document.documentElement; diff --git a/content/html/content/test/file_fullscreen-navigation.html b/content/html/content/test/file_fullscreen-navigation.html index 5c3f2ba27e28..e38a7b3850c1 100644 --- a/content/html/content/test/file_fullscreen-navigation.html +++ b/content/html/content/test/file_fullscreen-navigation.html @@ -8,7 +8,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=685402 - + @@ -27,16 +27,17 @@ var e1; var prevEnabled; var prevTrusted; -function boom() +function begin() { frameWin = document.getElementById("f").contentWindow; e1 = frameWin.document.body; + document.addEventListener("mozfullscreenchange", function onfullscreen() { + document.removeEventListener("mozfullscreenchange", onfullscreen, false); + opener.ok(document.mozFullScreen, "[navigation] Request should be granted"); + frameWin.location = "data:text/html,2"; + }, false); + e1.mozRequestFullScreen(); - setTimeout( - function() { - opener.ok(document.mozFullScreen, "[navigation] Request should be granted"); - frameWin.location = "data:text/html,2"; - }, 0); } function b2() diff --git a/content/html/content/test/file_fullscreen-plugins.html b/content/html/content/test/file_fullscreen-plugins.html index 9ed09ec43eeb..0455d9210860 100644 --- a/content/html/content/test/file_fullscreen-plugins.html +++ b/content/html/content/test/file_fullscreen-plugins.html @@ -21,7 +21,7 @@ Test plugins with DOM full-screen API: } - + @@ -59,7 +59,7 @@ const isMacOs = navigator.appVersion.indexOf("Macintosh") != -1; var windowedPlugin = null; -function scheduleTest() { +function begin() { // Delay test startup long enough for the windowed plugin in the subframe to // start up and create its window. opener.SimpleTest.executeSoon(function() { diff --git a/content/html/content/test/file_fullscreen-rollback.html b/content/html/content/test/file_fullscreen-rollback.html index aac68d7d0cd8..626f66c9e1df 100644 --- a/content/html/content/test/file_fullscreen-rollback.html +++ b/content/html/content/test/file_fullscreen-rollback.html @@ -20,7 +20,7 @@ Tests: Test for Bug 700764 - +
@@ -54,13 +54,9 @@ function e(id) { return document.getElementById(id); } -function start() { - SimpleTest.waitForFocus( - function() { - addListener("change", change1); - e("fse").mozRequestFullScreen(); - } - ); +function begin() { + addListener("change", change1); + e("fse").mozRequestFullScreen(); } function change1() { diff --git a/content/html/content/test/test_fullscreen-api.html b/content/html/content/test/test_fullscreen-api.html index fe84d0d4ca8e..5991baeb7dff 100644 --- a/content/html/content/test/test_fullscreen-api.html +++ b/content/html/content/test/test_fullscreen-api.html @@ -24,12 +24,10 @@ /** Tests for Bug 545812 **/ // Ensure the full-screen api is enabled, and will be disabled on test exit. -var prevEnabled = SpecialPowers.getBoolPref("full-screen-api.enabled"); SpecialPowers.setBoolPref("full-screen-api.enabled", true); // Disable the requirement for trusted contexts only, so the tests are easier // to write. -var prevTrusted = SpecialPowers.getBoolPref("full-screen-api.allow-trusted-requests-only"); SpecialPowers.setBoolPref("full-screen-api.allow-trusted-requests-only", false); // Run the tests which go full-screen in new windows, as mochitests normally @@ -50,6 +48,7 @@ var testWindow = null; var gTestIndex = 0; const isWinXP = navigator.userAgent.indexOf("Windows NT 5.1") != -1; +const isOSXLion = navigator.userAgent.indexOf("Mac OS X 10.7") != -1; function nextTest() { if (isWinXP) { @@ -59,13 +58,34 @@ function nextTest() { } if (testWindow) { testWindow.close(); + if (isOSXLion) { + // On OS X Lion, tests cause problems. Timeouts are a bad way to get around + // the problem and may lead to future [orange], but they are the only option + // at this point. + SimpleTest.waitForFocus(function() { setTimeout(runNextTest, 3000); }); + return; + } } + runNextTest(); +} + +function runNextTest() { if (gTestIndex < gTestWindows.length) { testWindow = window.open(gTestWindows[gTestIndex], "", "width=500,height=500"); + // We'll wait for the window to load, then make sure our window is refocused + // before starting the test, which will get kicked off on "focus". + // This ensures that we're essentially back on the primary "desktop" on + // OS X Lion before we run the test. + testWindow.addEventListener("load", function onload() { + testWindow.removeEventListener("load", onload, false); + SimpleTest.waitForFocus(function() { + SimpleTest.waitForFocus(testWindow.begin, testWindow); + }); + }, false); gTestIndex++; } else { - SpecialPowers.setBoolPref("full-screen-api.enabled", prevEnabled); - SpecialPowers.setBoolPref("full-screen-api.allow-trusted-requests-only", prevTrusted); + SpecialPowers.clearUserPref("full-screen-api.enabled"); + SpecialPowers.clearUserPref("full-screen-api.allow-trusted-requests-only"); SimpleTest.finish(); } } diff --git a/content/html/document/src/nsHTMLContentSink.cpp b/content/html/document/src/nsHTMLContentSink.cpp index 4e3dabca9e59..9a6f5d18481d 100644 --- a/content/html/document/src/nsHTMLContentSink.cpp +++ b/content/html/document/src/nsHTMLContentSink.cpp @@ -407,7 +407,10 @@ HTMLContentSink::AddAttributes(const nsIParserNode& aNode, nsAutoString key; for (; i != limit; i += step) { // Get lower-cased key - nsContentUtils::ASCIIToLower(aNode.GetKeyAt(i), key); + nsresult rv = nsContentUtils::ASCIIToLower(aNode.GetKeyAt(i), key); + if (NS_FAILED(rv)) { + return rv; + } nsCOMPtr keyAtom = do_GetAtom(key); diff --git a/content/smil/nsSMILAnimationController.cpp b/content/smil/nsSMILAnimationController.cpp index 036ed92a08a9..667c2d5735ad 100644 --- a/content/smil/nsSMILAnimationController.cpp +++ b/content/smil/nsSMILAnimationController.cpp @@ -399,8 +399,14 @@ nsSMILAnimationController::DoSample(bool aSkipUnchangedContainers) // Set running sample flag -- do this before flushing styles so that when we // flush styles we don't end up requesting extra samples mRunningSample = true; + nsCOMPtr kungFuDeathGrip(mDocument); // keeps 'this' alive too mDocument->FlushPendingNotifications(Flush_Style); + // WARNING: + // WARNING: the above flush may have destroyed the pres shell and/or + // WARNING: frames and other layout related objects. + // WARNING: + // STEP 1: Bring model up to date // (i) Rewind elements where necessary // (ii) Run milestone samples diff --git a/content/smil/nsSMILAnimationController.h b/content/smil/nsSMILAnimationController.h index e2c9c4eba63f..2101feb775b8 100644 --- a/content/smil/nsSMILAnimationController.h +++ b/content/smil/nsSMILAnimationController.h @@ -95,6 +95,7 @@ public: // Methods for resampling all animations // (A resample performs the same operations as a sample but doesn't advance // the current time and doesn't check if the container is paused) + // This will flush pending style changes for the document. void Resample() { DoSample(false); } void SetResampleNeeded() @@ -106,6 +107,8 @@ public: mResampleNeeded = true; } } + + // This will flush pending style changes for the document. void FlushResampleRequests() { if (!mResampleNeeded) diff --git a/content/svg/content/src/nsSVGDataParser.cpp b/content/svg/content/src/nsSVGDataParser.cpp index 5b5e51d840bc..097dad8005e3 100644 --- a/content/svg/content/src/nsSVGDataParser.cpp +++ b/content/svg/content/src/nsSVGDataParser.cpp @@ -52,6 +52,8 @@ #include "prdtoa.h" #include "nsSVGUtils.h" #include "nsMathUtils.h" +#include "nsMemory.h" +#include "nsReadableUtils.h" #include #include diff --git a/content/svg/content/src/nsSVGFilters.cpp b/content/svg/content/src/nsSVGFilters.cpp index f97e8e4035c2..e15706512946 100644 --- a/content/svg/content/src/nsSVGFilters.cpp +++ b/content/svg/content/src/nsSVGFilters.cpp @@ -3800,17 +3800,10 @@ nsSVGFEMorphologyElement::Filter(nsSVGFilterInstance *instance, PRUint8* sourceData = aSources[0]->mImage->Data(); PRUint8* targetData = aTarget->mImage->Data(); PRUint32 stride = aTarget->mImage->Stride(); - PRUint32 xExt[4], yExt[4]; // X, Y indices of RGBA extrema PRUint8 extrema[4]; // RGBA magnitude of extrema PRUint16 op = mEnumAttributes[OPERATOR].GetAnimValue(); - /* Scan the kernel for each pixel to determine max/min RGBA values. Note that - * as we advance in the x direction, each kernel overlaps the previous kernel. - * Thus, we can avoid iterating over the entire kernel by comparing the - * leading edge of the new kernel against the extrema found in the previous - * kernel. We must still scan the entire kernel if the previous extrema do - * not fall within the current kernel or if we are starting a new row. - */ + // Scan the kernel for each pixel to determine max/min RGBA values. for (PRInt32 y = rect.y; y < rect.YMost(); y++) { PRUint32 startY = NS_MAX(0, y - ry); // We need to read pixels not just in 'rect', which is limited to @@ -3822,39 +3815,18 @@ nsSVGFEMorphologyElement::Filter(nsSVGFilterInstance *instance, PRUint32 endX = NS_MIN(x + rx, instance->GetSurfaceWidth() - 1); PRUint32 targIndex = y * stride + 4 * x; - // We need to scan the entire kernel - if (x == rect.x || xExt[0] <= startX || xExt[1] <= startX || - xExt[2] <= startX || xExt[3] <= startX) { - PRUint32 i; - for (i = 0; i < 4; i++) { - extrema[i] = sourceData[targIndex + i]; - } - for (PRUint32 y1 = startY; y1 <= endY; y1++) { - for (PRUint32 x1 = startX; x1 <= endX; x1++) { - for (i = 0; i < 4; i++) { - PRUint8 pixel = sourceData[y1 * stride + 4 * x1 + i]; - if ((extrema[i] >= pixel && - op == nsSVGFEMorphologyElement::SVG_OPERATOR_ERODE) || - (extrema[i] <= pixel && - op == nsSVGFEMorphologyElement::SVG_OPERATOR_DILATE)) { - extrema[i] = pixel; - xExt[i] = x1; - yExt[i] = y1; - } - } - } - } - } else { // We only need to look at the newest column - for (PRUint32 y1 = startY; y1 <= endY; y1++) { + for (PRUint32 i = 0; i < 4; i++) { + extrema[i] = sourceData[targIndex + i]; + } + for (PRUint32 y1 = startY; y1 <= endY; y1++) { + for (PRUint32 x1 = startX; x1 <= endX; x1++) { for (PRUint32 i = 0; i < 4; i++) { - PRUint8 pixel = sourceData[y1 * stride + 4 * endX + i]; - if ((extrema[i] >= pixel && + PRUint8 pixel = sourceData[y1 * stride + 4 * x1 + i]; + if ((extrema[i] > pixel && op == nsSVGFEMorphologyElement::SVG_OPERATOR_ERODE) || - (extrema[i] <= pixel && + (extrema[i] < pixel && op == nsSVGFEMorphologyElement::SVG_OPERATOR_DILATE)) { - extrema[i] = pixel; - xExt[i] = endX; - yExt[i] = y1; + extrema[i] = pixel; } } } @@ -5119,14 +5091,11 @@ nsSVGFELightingElement::Filter(nsSVGFilterInstance *instance, S[2] = pointsAt[2] - lightPos[2]; NORMALIZE(S); float dot = -DOT(L, S); - if (dot < cosConeAngle) { - color = NS_RGB(0, 0, 0); - } else { - float tmp = pow(dot, specularExponent); - color = NS_RGB(PRUint8(NS_GET_R(lightColor) * tmp), - PRUint8(NS_GET_G(lightColor) * tmp), - PRUint8(NS_GET_B(lightColor) * tmp)); - } + if (dot < cosConeAngle) dot = 0; + float tmp = pow(dot, specularExponent); + color = NS_RGB(PRUint8(NS_GET_R(lightColor) * tmp), + PRUint8(NS_GET_G(lightColor) * tmp), + PRUint8(NS_GET_B(lightColor) * tmp)); } else { color = lightColor; } @@ -5293,19 +5262,14 @@ nsSVGFEDiffuseLightingElement::LightPixel(const float *N, const float *L, float diffuseNL = mNumberAttributes[DIFFUSE_CONSTANT].GetAnimValue() * DOT(N, L); - if (diffuseNL > 0) { - targetData[GFX_ARGB32_OFFSET_B] = - NS_MIN(PRUint32(diffuseNL * NS_GET_B(color)), 255U); - targetData[GFX_ARGB32_OFFSET_G] = - NS_MIN(PRUint32(diffuseNL * NS_GET_G(color)), 255U); - targetData[GFX_ARGB32_OFFSET_R] = - NS_MIN(PRUint32(diffuseNL * NS_GET_R(color)), 255U); - } else { - targetData[GFX_ARGB32_OFFSET_B] = 0; - targetData[GFX_ARGB32_OFFSET_G] = 0; - targetData[GFX_ARGB32_OFFSET_R] = 0; - } + if (diffuseNL < 0) diffuseNL = 0; + targetData[GFX_ARGB32_OFFSET_B] = + NS_MIN(PRUint32(diffuseNL * NS_GET_B(color)), 255U); + targetData[GFX_ARGB32_OFFSET_G] = + NS_MIN(PRUint32(diffuseNL * NS_GET_G(color)), 255U); + targetData[GFX_ARGB32_OFFSET_R] = + NS_MIN(PRUint32(diffuseNL * NS_GET_R(color)), 255U); targetData[GFX_ARGB32_OFFSET_A] = 255; } @@ -5460,27 +5424,24 @@ nsSVGFESpecularLightingElement::LightPixel(const float *N, const float *L, float kS = mNumberAttributes[SPECULAR_CONSTANT].GetAnimValue(); float dotNH = DOT(N, H); - if (dotNH > 0 && kS > 0) { - float specularNH = - kS * pow(dotNH, mNumberAttributes[SPECULAR_EXPONENT].GetAnimValue()); + bool invalid = dotNH <= 0 || kS <= 0; + kS *= invalid ? 0 : 1; + PRUint8 minAlpha = invalid ? 255 : 0; - targetData[GFX_ARGB32_OFFSET_B] = - NS_MIN(PRUint32(specularNH * NS_GET_B(color)), 255U); - targetData[GFX_ARGB32_OFFSET_G] = - NS_MIN(PRUint32(specularNH * NS_GET_G(color)), 255U); - targetData[GFX_ARGB32_OFFSET_R] = - NS_MIN(PRUint32(specularNH * NS_GET_R(color)), 255U); + float specularNH = + kS * pow(dotNH, mNumberAttributes[SPECULAR_EXPONENT].GetAnimValue()); - targetData[GFX_ARGB32_OFFSET_A] = - NS_MAX(targetData[GFX_ARGB32_OFFSET_B], - NS_MAX(targetData[GFX_ARGB32_OFFSET_G], - targetData[GFX_ARGB32_OFFSET_R])); - } else { - targetData[GFX_ARGB32_OFFSET_B] = 0; - targetData[GFX_ARGB32_OFFSET_G] = 0; - targetData[GFX_ARGB32_OFFSET_R] = 0; - targetData[GFX_ARGB32_OFFSET_A] = 255; - } + targetData[GFX_ARGB32_OFFSET_B] = + NS_MIN(PRUint32(specularNH * NS_GET_B(color)), 255U); + targetData[GFX_ARGB32_OFFSET_G] = + NS_MIN(PRUint32(specularNH * NS_GET_G(color)), 255U); + targetData[GFX_ARGB32_OFFSET_R] = + NS_MIN(PRUint32(specularNH * NS_GET_R(color)), 255U); + + targetData[GFX_ARGB32_OFFSET_A] = + NS_MAX(minAlpha, NS_MAX(targetData[GFX_ARGB32_OFFSET_B], + NS_MAX(targetData[GFX_ARGB32_OFFSET_G], + targetData[GFX_ARGB32_OFFSET_R]))); } //---------------------Image------------------------ @@ -5989,6 +5950,8 @@ nsSVGFEDisplacementMapElement::Filter(nsSVGFilterInstance *instance, PRUint8* targetData = aTarget->mImage->Data(); PRUint32 stride = aTarget->mImage->Stride(); + static PRUint8 dummyData[4] = { 0, 0, 0, 0 }; + static const PRUint16 channelMap[5] = { 0, GFX_ARGB32_OFFSET_R, @@ -6011,13 +5974,20 @@ nsSVGFEDisplacementMapElement::Filter(nsSVGFilterInstance *instance, PRInt32 sourceY = y + NSToIntFloor(scaleOver255 * displacementData[targIndex + yChannel] + scaleAdjustment); - if (sourceX < 0 || sourceX >= width || - sourceY < 0 || sourceY >= height) { - *(PRUint32*)(targetData + targIndex) = 0; + + bool outOfBounds = sourceX < 0 || sourceX >= width || + sourceY < 0 || sourceY >= height; + PRUint8* data; + PRInt32 multiplier; + if (outOfBounds) { + data = dummyData; + multiplier = 0; } else { - *(PRUint32*)(targetData + targIndex) = - *(PRUint32*)(sourceData + sourceY * stride + 4 * sourceX); + data = sourceData; + multiplier = 1; } + *(PRUint32*)(targetData + targIndex) = + *(PRUint32*)(data + multiplier * (sourceY * stride + 4 * sourceX)); } } return NS_OK; diff --git a/content/svg/content/src/nsSVGSVGElement.cpp b/content/svg/content/src/nsSVGSVGElement.cpp index 0fdeaada9103..04c47080fc5a 100644 --- a/content/svg/content/src/nsSVGSVGElement.cpp +++ b/content/svg/content/src/nsSVGSVGElement.cpp @@ -202,7 +202,6 @@ nsSVGSVGElement::nsSVGSVGElement(already_AddRefed aNodeInfo, mCurrentScale(1.0f), mPreviousTranslate(0.0f, 0.0f), mPreviousScale(1.0f), - mRedrawSuspendCount(0), mStartAnimationOnBindToTree(!aFromParser), mImageNeedsTransformInvalidation(false), mIsPaintingSVGImageElement(false) @@ -379,20 +378,9 @@ nsSVGSVGElement::GetCurrentTranslate(nsIDOMSVGPoint * *aCurrentTranslate) NS_IMETHODIMP nsSVGSVGElement::SuspendRedraw(PRUint32 max_wait_milliseconds, PRUint32 *_retval) { + // suspendRedraw is a no-op in Mozilla, so it doesn't matter what + // we set the ID out-param to: *_retval = 1; - - if (++mRedrawSuspendCount > 1) - return NS_OK; - - nsIFrame* frame = GetPrimaryFrame(); - if (frame) { - nsISVGSVGFrame* svgframe = do_QueryFrame(frame); - // might fail this check if we've failed conditional processing - if (svgframe) { - svgframe->SuspendRedraw(); - } - } - return NS_OK; } @@ -400,32 +388,15 @@ nsSVGSVGElement::SuspendRedraw(PRUint32 max_wait_milliseconds, PRUint32 *_retval NS_IMETHODIMP nsSVGSVGElement::UnsuspendRedraw(PRUint32 suspend_handle_id) { - if (mRedrawSuspendCount == 0) { - return NS_ERROR_FAILURE; - } - - if (mRedrawSuspendCount > 1) { - --mRedrawSuspendCount; - return NS_OK; - } - - return UnsuspendRedrawAll(); + // no-op + return NS_OK; } /* void unsuspendRedrawAll (); */ NS_IMETHODIMP nsSVGSVGElement::UnsuspendRedrawAll() { - mRedrawSuspendCount = 0; - - nsIFrame* frame = GetPrimaryFrame(); - if (frame) { - nsISVGSVGFrame* svgframe = do_QueryFrame(frame); - // might fail this check if we've failed conditional processing - if (svgframe) { - svgframe->UnsuspendRedraw(); - } - } + // no-op return NS_OK; } diff --git a/content/svg/content/src/nsSVGSwitchElement.cpp b/content/svg/content/src/nsSVGSwitchElement.cpp index abe51b1961a1..efcae0304b23 100644 --- a/content/svg/content/src/nsSVGSwitchElement.cpp +++ b/content/svg/content/src/nsSVGSwitchElement.cpp @@ -87,18 +87,22 @@ nsSVGSwitchElement::nsSVGSwitchElement(already_AddRefed aNodeInfo) void nsSVGSwitchElement::MaybeInvalidate() { - // We don't reuse UpdateActiveChild() and check if mActiveChild has changed - // to determine if we should invalidate. If we did that, - // nsSVGUtils::UpdateGraphic would not invalidate the old mActiveChild area! + // We must not change mActiveChild until after + // InvalidateAndScheduleBoundsUpdate has been called, otherwise + // it will not correctly invalidate the old mActiveChild area. - if (FindActiveChild() == mActiveChild) { + nsIContent *newActiveChild = FindActiveChild(); + + if (newActiveChild == mActiveChild) { return; } nsIFrame *frame = GetPrimaryFrame(); if (frame) { - nsSVGUtils::UpdateGraphic(frame); + nsSVGUtils::InvalidateAndScheduleBoundsUpdate(frame); } + + mActiveChild = newActiveChild; } //---------------------------------------------------------------------- diff --git a/dom/base/ScreenOrientation.h b/dom/base/ScreenOrientation.h index 90ba25c068df..938d171a6d60 100644 --- a/dom/base/ScreenOrientation.h +++ b/dom/base/ScreenOrientation.h @@ -8,6 +8,9 @@ namespace mozilla { namespace dom { +// Make sure that any change here is also made in +// * mobile/android/base/GeckoScreenOrientationListener.java +// * embedding/android/GeckoScreenOrientationListener.java enum ScreenOrientation { eScreenOrientation_Current = 0, eScreenOrientation_PortraitPrimary = 1, // 00000001 diff --git a/dom/interfaces/events/nsIDOMDataTransfer.idl b/dom/interfaces/events/nsIDOMDataTransfer.idl index 8517e87bd81b..f03361998ac2 100644 --- a/dom/interfaces/events/nsIDOMDataTransfer.idl +++ b/dom/interfaces/events/nsIDOMDataTransfer.idl @@ -40,7 +40,7 @@ interface nsIVariant; interface nsIDOMFileList; -[scriptable, uuid(E929ACB6-435C-4CB8-9AD1-AE3B9353BCC5)] +[scriptable, uuid(7D73CFBF-EC30-4F8E-B6A4-BB31EB943580)] interface nsIDOMDataTransfer : nsISupports { /** @@ -264,8 +264,11 @@ interface nsIDOMDataTransfer : nsISupports /** * Creates a copy of the data transfer object, for the given event type and - * user cancelled flag. + * user cancelled flag. If isCrossDomainSubFrameDrop is set, then this is a + * cross-domain drop from a subframe where access to the data should be + * prevented. */ [noscript] nsIDOMDataTransfer clone(in PRUint32 aEventType, - in boolean aUserCancelled); + in boolean aUserCancelled, + in boolean isCrossDomainSubFrameDrop); }; diff --git a/dom/plugins/test/mochitest/cocoa_focus.html b/dom/plugins/test/mochitest/cocoa_focus.html index c67857c7f4f9..edc623d24401 100644 --- a/dom/plugins/test/mochitest/cocoa_focus.html +++ b/dom/plugins/test/mochitest/cocoa_focus.html @@ -33,8 +33,8 @@ const NSLeftMouseDown = 1, NSLeftMouseUp = 2; - // Don't run any tests if we're not testing the Cocoa event model. if (plugin1.getEventModel() != 1) { + window.opener.todo(false, "Skipping this test when not testing the Cocoa event model"); window.opener.testsFinished(); return; } diff --git a/dom/plugins/test/mochitest/cocoa_window_focus.html b/dom/plugins/test/mochitest/cocoa_window_focus.html index 3cee18df729a..71a864f1a1b1 100644 --- a/dom/plugins/test/mochitest/cocoa_window_focus.html +++ b/dom/plugins/test/mochitest/cocoa_window_focus.html @@ -26,8 +26,8 @@ var plugin1 = document.getElementById("plugin1"); var plugin2 = document.getElementById("plugin2"); - // Don't run any tests if we're not testing the Cocoa event model. if (plugin1.getEventModel() != 1) { + window.opener.todo(false, "Skipping this test when not testing the Cocoa event model"); window.opener.testsFinished(); return; } diff --git a/dom/plugins/test/mochitest/test_pluginstream_seek_close.html b/dom/plugins/test/mochitest/test_pluginstream_seek_close.html index e8a02434a326..21b92cc8a412 100644 --- a/dom/plugins/test/mochitest/test_pluginstream_seek_close.html +++ b/dom/plugins/test/mochitest/test_pluginstream_seek_close.html @@ -5,7 +5,7 @@ src="/tests/SimpleTest/SimpleTest.js"> - + + + + diff --git a/layout/base/crashtests/crashtests.list b/layout/base/crashtests/crashtests.list index 52b4f0fb1343..dc9a818a7067 100644 --- a/layout/base/crashtests/crashtests.list +++ b/layout/base/crashtests/crashtests.list @@ -352,5 +352,6 @@ load 707098.html load 722137.html load 725535.html load 727601.html -load 736389-1.xhtml +asserts(0-2) pref(dom.disable_open_during_load,false) load 735943.html # the assertion is bug 735966 +asserts(0-2) load 736389-1.xhtml # sometimes the above assertions are delayed and is reported on this test instead load 736924-1.html diff --git a/layout/base/nsCSSFrameConstructor.cpp b/layout/base/nsCSSFrameConstructor.cpp index 4ad3b8b41374..8dae61a3e276 100644 --- a/layout/base/nsCSSFrameConstructor.cpp +++ b/layout/base/nsCSSFrameConstructor.cpp @@ -7621,12 +7621,11 @@ DoApplyRenderingChangeToTree(nsIFrame* aFrame, if (aChange & nsChangeHint_RepaintFrame) { if (aFrame->IsFrameOfType(nsIFrame::eSVG)) { if (aChange & nsChangeHint_UpdateEffects) { - // Invalidate the frame's old bounds, update its bounds, invalidate its new - // bounds, and then inform anyone observing _us_ that we've changed: - nsSVGUtils::UpdateGraphic(aFrame); + // Invalidate and update our area: + nsSVGUtils::InvalidateAndScheduleBoundsUpdate(aFrame); } else { // Just invalidate our area: - nsSVGUtils::InvalidateCoveredRegion(aFrame); + nsSVGUtils::InvalidateBounds(aFrame); } } else { aFrame->InvalidateOverflowRect(); @@ -10710,13 +10709,15 @@ nsCSSFrameConstructor::ConstructInline(nsFrameConstructorState& aState, nsIContent* const content = aItem.mContent; nsStyleContext* const styleContext = aItem.mStyleContext; - nsIFrame *newFrame; - bool positioned = NS_STYLE_DISPLAY_INLINE == aDisplay->mDisplay && (NS_STYLE_POSITION_RELATIVE == aDisplay->mPosition || aDisplay->HasTransform()); - newFrame = NS_NewInlineFrame(mPresShell, styleContext); + + nsIFrame* newFrame = NS_NewInlineFrame(mPresShell, styleContext); + if (!newFrame) { + return NS_ERROR_OUT_OF_MEMORY; + } // Initialize the frame InitAndRestoreFrame(aState, content, aParentFrame, nsnull, newFrame); @@ -10736,7 +10737,11 @@ nsCSSFrameConstructor::ConstructInline(nsFrameConstructorState& aState, nsresult rv = ConstructFramesFromItemList(aState, aItem.mChildItems, newFrame, childItems); if (NS_FAILED(rv)) { - // Clean up? + // Clean up. + // Link up any successfully-created child frames here, so that we'll + // clean them up as well. + newFrame->SetInitialChildList(kPrincipalList, childItems); + newFrame->Destroy(); return rv; } diff --git a/layout/base/nsCSSRendering.cpp b/layout/base/nsCSSRendering.cpp index baf3df5ba2f8..977a5de33a84 100644 --- a/layout/base/nsCSSRendering.cpp +++ b/layout/base/nsCSSRendering.cpp @@ -71,6 +71,7 @@ #include "nsINameSpaceManager.h" #include "nsBlockFrame.h" #include "gfxContext.h" +#include "nsRenderingContext.h" #include "nsIInterfaceRequestorUtils.h" #include "gfxPlatform.h" #include "gfxImageSurface.h" diff --git a/layout/base/nsLayoutUtils.cpp b/layout/base/nsLayoutUtils.cpp index 69325124bc30..a188d1b27fa6 100644 --- a/layout/base/nsLayoutUtils.cpp +++ b/layout/base/nsLayoutUtils.cpp @@ -69,6 +69,7 @@ #include "gfxRect.h" #include "gfxContext.h" #include "gfxFont.h" +#include "nsRenderingContext.h" #include "nsIInterfaceRequestorUtils.h" #include "nsCSSRendering.h" #include "nsContentUtils.h" diff --git a/layout/base/nsPresShell.cpp b/layout/base/nsPresShell.cpp index b5e51d0df5a2..00f7df56c8ef 100644 --- a/layout/base/nsPresShell.cpp +++ b/layout/base/nsPresShell.cpp @@ -3965,9 +3965,12 @@ PresShell::FlushPendingNotifications(mozFlushType aType) mDocument->GetAnimationController()->FlushResampleRequests(); } - nsAutoScriptBlocker scriptBlocker; - mFrameConstructor->CreateNeededFrames(); - mFrameConstructor->ProcessPendingRestyles(); + // The FlushResampleRequests() above flushed style changes. + if (!mIsDestroying) { + nsAutoScriptBlocker scriptBlocker; + mFrameConstructor->CreateNeededFrames(); + mFrameConstructor->ProcessPendingRestyles(); + } } // Dispatch any 'animationstart' events those (or earlier) restyles diff --git a/layout/generic/crashtests/737313-1.html b/layout/generic/crashtests/737313-1.html new file mode 100644 index 000000000000..e30f50ef88d0 --- /dev/null +++ b/layout/generic/crashtests/737313-1.html @@ -0,0 +1,5 @@ + + +
+ diff --git a/layout/generic/crashtests/737313-2.html b/layout/generic/crashtests/737313-2.html new file mode 100644 index 000000000000..ba735f344af8 --- /dev/null +++ b/layout/generic/crashtests/737313-2.html @@ -0,0 +1,5 @@ + + + some text
+ diff --git a/layout/generic/crashtests/737313-3.html b/layout/generic/crashtests/737313-3.html new file mode 100644 index 000000000000..8dce15f53e26 --- /dev/null +++ b/layout/generic/crashtests/737313-3.html @@ -0,0 +1,5 @@ + + +
a block
+ diff --git a/layout/generic/crashtests/crashtests.list b/layout/generic/crashtests/crashtests.list index 843dfd10e4f2..1ad6748b2790 100644 --- a/layout/generic/crashtests/crashtests.list +++ b/layout/generic/crashtests/crashtests.list @@ -386,3 +386,6 @@ load text-overflow-bug713610.html load 700031.xhtml load first-letter-638937.html asserts(18) load first-letter-638937-2.html +load 737313-1.html +load 737313-2.html +load 737313-3.html diff --git a/layout/generic/nsFrame.cpp b/layout/generic/nsFrame.cpp index aa56c6bcf1e9..276c9672e104 100644 --- a/layout/generic/nsFrame.cpp +++ b/layout/generic/nsFrame.cpp @@ -124,6 +124,7 @@ #include "nsDeckFrame.h" #include "gfxContext.h" +#include "nsRenderingContext.h" #include "CSSCalc.h" #include "nsAbsoluteContainingBlock.h" diff --git a/layout/reftests/bugs/723484-1-ref.html b/layout/reftests/bugs/723484-1-ref.html new file mode 100644 index 000000000000..124ee0cde09d --- /dev/null +++ b/layout/reftests/bugs/723484-1-ref.html @@ -0,0 +1,6 @@ + + + + + + diff --git a/layout/reftests/bugs/723484-1.html b/layout/reftests/bugs/723484-1.html new file mode 100644 index 000000000000..0e3e8bb5d501 --- /dev/null +++ b/layout/reftests/bugs/723484-1.html @@ -0,0 +1,13 @@ + + + + + + + diff --git a/layout/reftests/bugs/reftest.list b/layout/reftests/bugs/reftest.list index 1ae352e963c8..86287b079052 100644 --- a/layout/reftests/bugs/reftest.list +++ b/layout/reftests/bugs/reftest.list @@ -1693,6 +1693,7 @@ needs-focus != 703186-1.html 703186-2.html fuzzy-if(d2d,1,19) fuzzy-if(cocoaWidget,1,170) == 718521.html 718521-ref.html == 720987.html 720987-ref.html == 722923-1.html 722923-1-ref.html +== 723484-1.html 723484-1-ref.html == 729143-1.html 729143-1-ref.html needs-focus == 731726-1.html 731726-1-ref.html == 735481-1.html 735481-1-ref.html diff --git a/layout/reftests/svg/reftest.list b/layout/reftests/svg/reftest.list index 867d7c09ca8c..2f020a51ad0b 100644 --- a/layout/reftests/svg/reftest.list +++ b/layout/reftests/svg/reftest.list @@ -227,9 +227,9 @@ random-if(gtk2Widget) == objectBoundingBox-and-fePointLight-02.svg objectBoundin == svg-in-foreignObject-01.xhtml svg-in-foreignObject-01-ref.xhtml == svg-in-foreignObject-02.xhtml svg-in-foreignObject-01-ref.xhtml # reuse -01-ref.xhtml == switch-01.svg pass.svg -== suspend-01.svg about:blank +== suspend-01.svg pass.svg == suspend-02.svg pass.svg -fails == suspend-03.svg pass.svg # bug 724242 +== suspend-03.svg pass.svg == suspend-04.svg pass.svg == suspend-05.svg pass.svg == suspend-06.svg pass.svg diff --git a/layout/reftests/svg/suspend-01.svg b/layout/reftests/svg/suspend-01.svg index ff98340cdca8..fa681fbe60da 100644 --- a/layout/reftests/svg/suspend-01.svg +++ b/layout/reftests/svg/suspend-01.svg @@ -4,10 +4,10 @@ http://creativecommons.org/licenses/publicdomain/ --> - Test that suspendRedraw works - + Test that suspendRedraw doesn't apply after the end of a script + - + diff --git a/layout/reftests/svg/suspend-02.svg b/layout/reftests/svg/suspend-02.svg index 2bd52945c877..1084e762eb1e 100644 --- a/layout/reftests/svg/suspend-02.svg +++ b/layout/reftests/svg/suspend-02.svg @@ -4,8 +4,8 @@ http://creativecommons.org/licenses/publicdomain/ --> - Test that suspendRedraw works - + Test that suspendRedraw doesn't apply after the end of a script + - + diff --git a/layout/reftests/svg/suspend-03.svg b/layout/reftests/svg/suspend-03.svg index e3c9d185c0b5..33ceb092861a 100644 --- a/layout/reftests/svg/suspend-03.svg +++ b/layout/reftests/svg/suspend-03.svg @@ -4,8 +4,8 @@ http://creativecommons.org/licenses/publicdomain/ --> - Test that suspendRedraw works - + Test that suspendRedraw doesn't apply after the end of a script + - - + + diff --git a/layout/reftests/svg/suspend-04.svg b/layout/reftests/svg/suspend-04.svg index 590e9708460f..79c351fb2c46 100644 --- a/layout/reftests/svg/suspend-04.svg +++ b/layout/reftests/svg/suspend-04.svg @@ -4,7 +4,7 @@ http://creativecommons.org/licenses/publicdomain/ --> - Test that suspendRedraw works + Test that suspendRedraw doesn't apply after the end of a script - + diff --git a/layout/svg/base/src/nsISVGChildFrame.h b/layout/svg/base/src/nsISVGChildFrame.h index faa457ece7d7..b2800eeb8979 100644 --- a/layout/svg/base/src/nsISVGChildFrame.h +++ b/layout/svg/base/src/nsISVGChildFrame.h @@ -39,21 +39,21 @@ #ifndef __NS_ISVGCHILDFRAME_H__ #define __NS_ISVGCHILDFRAME_H__ - -#include "nsQueryFrame.h" -#include "nsCOMPtr.h" -#include "nsRect.h" #include "gfxRect.h" -#include "gfxMatrix.h" +#include "nsQueryFrame.h" +#include "nsRect.h" -class gfxContext; +class nsIFrame; class nsRenderingContext; +struct gfxMatrix; +struct nsPoint; + namespace mozilla { -class SVGAnimatedNumberList; -class SVGNumberList; class SVGAnimatedLengthList; +class SVGAnimatedNumberList; class SVGLengthList; +class SVGNumberList; class SVGUserUnitList; } @@ -88,13 +88,13 @@ public: // Get bounds in our gfxContext's coordinates space (in app units) NS_IMETHOD_(nsRect) GetCoveredRegion()=0; - NS_IMETHOD UpdateCoveredRegion()=0; - // Called once on SVG child frames except descendants of , either - // when their nsSVGOuterSVGFrame receives its initial reflow (i.e. once - // the SVG viewport dimensions are known), or else when they're inserted - // into the frame tree (if they're inserted after the initial reflow). - NS_IMETHOD InitialUpdate()=0; + // Called on SVG child frames (except NS_STATE_SVG_NONDISPLAY_CHILD frames) + // to update and then invalidate their cached bounds. This method is not + // called until after the nsSVGOuterSVGFrame has had its initial reflow + // (i.e. once the SVG viewport dimensions are known). It should also only + // be called by nsSVGOuterSVGFrame during its reflow. + virtual void UpdateBounds()=0; // Flags to pass to NotifySVGChange: // @@ -112,8 +112,6 @@ public: COORD_CONTEXT_CHANGED = 0x04 }; virtual void NotifySVGChanged(PRUint32 aFlags)=0; - virtual void NotifyRedrawSuspended()=0; - virtual void NotifyRedrawUnsuspended()=0; /** * Get this frame's contribution to the rect returned by a GetBBox() call diff --git a/layout/svg/base/src/nsISVGGlyphFragmentNode.h b/layout/svg/base/src/nsISVGGlyphFragmentNode.h index a5bb6773ebb2..0c1ade5e6b08 100644 --- a/layout/svg/base/src/nsISVGGlyphFragmentNode.h +++ b/layout/svg/base/src/nsISVGGlyphFragmentNode.h @@ -43,6 +43,7 @@ #include "nsQueryFrame.h" class nsIDOMSVGPoint; +class nsSVGGlyphFrame; class nsISVGGlyphFragmentNode : public nsQueryFrame { diff --git a/layout/svg/base/src/nsISVGSVGFrame.h b/layout/svg/base/src/nsISVGSVGFrame.h index 07abeb6dd785..f042e66903fb 100644 --- a/layout/svg/base/src/nsISVGSVGFrame.h +++ b/layout/svg/base/src/nsISVGSVGFrame.h @@ -46,8 +46,6 @@ class nsISVGSVGFrame public: NS_DECL_QUERYFRAME_TARGET(nsISVGSVGFrame) - virtual void SuspendRedraw()=0; - virtual void UnsuspendRedraw()=0; virtual void NotifyViewportChange()=0; }; diff --git a/layout/svg/base/src/nsSVGClipPathFrame.cpp b/layout/svg/base/src/nsSVGClipPathFrame.cpp index a375f1e1f73d..12757b556e1e 100644 --- a/layout/svg/base/src/nsSVGClipPathFrame.cpp +++ b/layout/svg/base/src/nsSVGClipPathFrame.cpp @@ -34,10 +34,12 @@ * * ***** END LICENSE BLOCK ***** */ +#include "nsSVGClipPathFrame.h" + #include "nsIDOMDocument.h" #include "nsIDocument.h" #include "nsIDOMSVGClipPathElement.h" -#include "nsSVGClipPathFrame.h" +#include "nsRenderingContext.h" #include "nsGkAtoms.h" #include "nsSVGUtils.h" #include "nsSVGEffects.h" diff --git a/layout/svg/base/src/nsSVGClipPathFrame.h b/layout/svg/base/src/nsSVGClipPathFrame.h index bf4025935781..56f4284617dd 100644 --- a/layout/svg/base/src/nsSVGClipPathFrame.h +++ b/layout/svg/base/src/nsSVGClipPathFrame.h @@ -37,9 +37,9 @@ #ifndef __NS_SVGCLIPPATHFRAME_H__ #define __NS_SVGCLIPPATHFRAME_H__ +#include "gfxMatrix.h" #include "nsSVGContainerFrame.h" #include "nsSVGUtils.h" -#include "gfxMatrix.h" class nsRenderingContext; diff --git a/layout/svg/base/src/nsSVGContainerFrame.cpp b/layout/svg/base/src/nsSVGContainerFrame.cpp index beb78a9181de..5e889d6a1b1d 100644 --- a/layout/svg/base/src/nsSVGContainerFrame.cpp +++ b/layout/svg/base/src/nsSVGContainerFrame.cpp @@ -101,8 +101,7 @@ nsSVGDisplayContainerFrame::Init(nsIContent* aContent, { if (!(GetStateBits() & NS_STATE_IS_OUTER_SVG)) { AddStateBits(aParent->GetStateBits() & - (NS_STATE_SVG_NONDISPLAY_CHILD | NS_STATE_SVG_CLIPPATH_CHILD | - NS_STATE_SVG_REDRAW_SUSPENDED)); + (NS_STATE_SVG_NONDISPLAY_CHILD | NS_STATE_SVG_CLIPPATH_CHILD)); } nsresult rv = nsSVGContainerFrame::Init(aContent, aParent, aPrevInFlow); return rv; @@ -123,14 +122,23 @@ nsSVGDisplayContainerFrame::InsertFrames(ChildListID aListID, // Insert the new frames nsSVGContainerFrame::InsertFrames(aListID, aPrevFrame, aFrameList); - // Call InitialUpdate on the new frames ONLY if our nsSVGOuterSVGFrame has had - // its initial reflow (our NS_FRAME_FIRST_REFLOW bit is clear) - bug 399863. - if (!(GetStateBits() & NS_FRAME_FIRST_REFLOW)) { + // If we are not a non-display SVG frame and we do not have a bounds update + // pending, then we need to schedule one for our new children: + if (!(GetStateBits() & + (NS_FRAME_IS_DIRTY | NS_FRAME_HAS_DIRTY_CHILDREN | + NS_STATE_SVG_NONDISPLAY_CHILD))) { for (nsIFrame* kid = firstNewFrame; kid != firstOldFrame; kid = kid->GetNextSibling()) { nsISVGChildFrame* SVGFrame = do_QueryFrame(kid); if (SVGFrame) { - SVGFrame->InitialUpdate(); + NS_ABORT_IF_FALSE(!(kid->GetStateBits() & NS_STATE_SVG_NONDISPLAY_CHILD), + "Check for this explicitly in the |if|, then"); + // Remove bits so that ScheduleBoundsUpdate will work: + kid->RemoveStateBits(NS_FRAME_FIRST_REFLOW | NS_FRAME_IS_DIRTY | + NS_FRAME_HAS_DIRTY_CHILDREN); + // No need to invalidate the new kid's old bounds, so we just use + // nsSVGUtils::ScheduleBoundsUpdate. + nsSVGUtils::ScheduleBoundsUpdate(kid); } } } @@ -142,10 +150,7 @@ NS_IMETHODIMP nsSVGDisplayContainerFrame::RemoveFrame(ChildListID aListID, nsIFrame* aOldFrame) { - // Force the invalidation before it's too late - RemoveStateBits(NS_STATE_SVG_REDRAW_SUSPENDED); - - nsSVGUtils::InvalidateCoveredRegion(aOldFrame); + nsSVGUtils::InvalidateBounds(aOldFrame); nsresult rv = nsSVGContainerFrame::RemoveFrame(aListID, aOldFrame); @@ -187,42 +192,48 @@ nsSVGDisplayContainerFrame::GetCoveredRegion() return nsSVGUtils::GetCoveredRegion(mFrames); } -NS_IMETHODIMP -nsSVGDisplayContainerFrame::UpdateCoveredRegion() +void +nsSVGDisplayContainerFrame::UpdateBounds() { - for (nsIFrame* kid = mFrames.FirstChild(); kid; - kid = kid->GetNextSibling()) { - nsISVGChildFrame* SVGFrame = do_QueryFrame(kid); - if (SVGFrame) { - SVGFrame->UpdateCoveredRegion(); - } - } - return NS_OK; -} + NS_ASSERTION(nsSVGUtils::OuterSVGIsCallingUpdateBounds(this), + "This call is probaby a wasteful mistake"); -NS_IMETHODIMP -nsSVGDisplayContainerFrame::InitialUpdate() -{ - NS_ASSERTION(GetStateBits() & NS_FRAME_FIRST_REFLOW, - "Yikes! We've been called already! Hopefully we weren't called " - "before our nsSVGOuterSVGFrame's initial Reflow()!!!"); + NS_ABORT_IF_FALSE(!(GetStateBits() & NS_STATE_SVG_NONDISPLAY_CHILD), + "UpdateBounds mechanism not designed for this"); + + if (!nsSVGUtils::NeedsUpdatedBounds(this)) { + return; + } + + // If the NS_FRAME_FIRST_REFLOW bit has been removed from our parent frame, + // then our outer- has previously had its initial reflow. In that case + // we need to make sure that that bit has been removed from ourself _before_ + // recursing over our children to ensure that they know too. Otherwise, we + // need to remove it _after_ recursing over our children so that they know + // the initial reflow is currently underway. + + bool outerSVGHasHadFirstReflow = + (GetParent()->GetStateBits() & NS_FRAME_FIRST_REFLOW) == 0; + + if (outerSVGHasHadFirstReflow) { + mState &= ~NS_FRAME_FIRST_REFLOW; // tell our children + } for (nsIFrame* kid = mFrames.FirstChild(); kid; kid = kid->GetNextSibling()) { nsISVGChildFrame* SVGFrame = do_QueryFrame(kid); if (SVGFrame) { - SVGFrame->InitialUpdate(); + NS_ABORT_IF_FALSE(!(kid->GetStateBits() & NS_STATE_SVG_NONDISPLAY_CHILD), + "Check for this explicitly in the |if|, then"); + SVGFrame->UpdateBounds(); } } - NS_ASSERTION(!(mState & NS_FRAME_IN_REFLOW), - "We don't actually participate in reflow"); - - // Do unset the various reflow bits, though. mState &= ~(NS_FRAME_FIRST_REFLOW | NS_FRAME_IS_DIRTY | NS_FRAME_HAS_DIRTY_CHILDREN); - - return NS_OK; + + // XXXsvgreflow once we store bounds on containers, do... + // nsSVGUtils::InvalidateBounds(this); } void @@ -238,18 +249,6 @@ nsSVGDisplayContainerFrame::NotifySVGChanged(PRUint32 aFlags) nsSVGUtils::NotifyChildrenOfSVGChange(this, aFlags); } -void -nsSVGDisplayContainerFrame::NotifyRedrawSuspended() -{ - nsSVGUtils::NotifyRedrawSuspended(this); -} - -void -nsSVGDisplayContainerFrame::NotifyRedrawUnsuspended() -{ - nsSVGUtils::NotifyRedrawUnsuspended(this); -} - gfxRect nsSVGDisplayContainerFrame::GetBBoxContribution( const gfxMatrix &aToBBoxUserspace, diff --git a/layout/svg/base/src/nsSVGContainerFrame.h b/layout/svg/base/src/nsSVGContainerFrame.h index 2845717aadac..1c88409b8674 100644 --- a/layout/svg/base/src/nsSVGContainerFrame.h +++ b/layout/svg/base/src/nsSVGContainerFrame.h @@ -37,12 +37,22 @@ #ifndef NS_SVGCONTAINERFRAME_H #define NS_SVGCONTAINERFRAME_H -#include "nsContainerFrame.h" -#include "nsISVGChildFrame.h" -#include "gfxRect.h" #include "gfxMatrix.h" +#include "gfxRect.h" +#include "nsContainerFrame.h" +#include "nsFrame.h" +#include "nsIFrame.h" +#include "nsISVGChildFrame.h" +#include "nsQueryFrame.h" +#include "nsRect.h" +class nsFrameList; +class nsIContent; +class nsIPresShell; class nsRenderingContext; +class nsStyleContext; + +struct nsPoint; typedef nsContainerFrame nsSVGContainerFrameBase; @@ -116,11 +126,8 @@ public: const nsIntRect *aDirtyRect); NS_IMETHOD_(nsIFrame*) GetFrameForPoint(const nsPoint &aPoint); NS_IMETHOD_(nsRect) GetCoveredRegion(); - NS_IMETHOD UpdateCoveredRegion(); - NS_IMETHOD InitialUpdate(); + virtual void UpdateBounds(); virtual void NotifySVGChanged(PRUint32 aFlags); - virtual void NotifyRedrawSuspended(); - virtual void NotifyRedrawUnsuspended(); virtual gfxRect GetBBoxContribution(const gfxMatrix &aToBBoxUserspace, PRUint32 aFlags); NS_IMETHOD_(bool) IsDisplayContainer() { return true; } diff --git a/layout/svg/base/src/nsSVGEffects.cpp b/layout/svg/base/src/nsSVGEffects.cpp index 6492a69809ee..d6e3c78a5098 100644 --- a/layout/svg/base/src/nsSVGEffects.cpp +++ b/layout/svg/base/src/nsSVGEffects.cpp @@ -331,7 +331,7 @@ nsSVGPaintingProperty::DoUpdate() return; if (mFrame->IsFrameOfType(nsIFrame::eSVG)) { - nsSVGUtils::InvalidateCoveredRegion(mFrame); + nsSVGUtils::InvalidateBounds(mFrame); } else { InvalidateAllContinuations(mFrame); } diff --git a/layout/svg/base/src/nsSVGEffects.h b/layout/svg/base/src/nsSVGEffects.h index aceb26867442..bd61f9b1e22f 100644 --- a/layout/svg/base/src/nsSVGEffects.h +++ b/layout/svg/base/src/nsSVGEffects.h @@ -38,14 +38,25 @@ #ifndef NSSVGEFFECTS_H_ #define NSSVGEFFECTS_H_ -#include "nsIContent.h" +#include "FramePropertyTable.h" +#include "mozilla/dom/Element.h" +#include "nsHashKeys.h" +#include "nsID.h" #include "nsIFrame.h" +#include "nsIMutationObserver.h" +#include "nsInterfaceHashtable.h" +#include "nsISupportsBase.h" +#include "nsISupportsImpl.h" #include "nsReferencedElement.h" #include "nsStubMutationObserver.h" #include "nsSVGUtils.h" -#include "nsInterfaceHashtable.h" +#include "nsTHashtable.h" +#include "nsTraceRefcnt.h" #include "nsURIHashKey.h" +class nsIAtom; +class nsIPresShell; +class nsIURI; class nsSVGClipPathFrame; class nsSVGFilterFrame; class nsSVGMaskFrame; diff --git a/layout/svg/base/src/nsSVGFilterFrame.cpp b/layout/svg/base/src/nsSVGFilterFrame.cpp index 9df040b4f25a..c3b58266c7dd 100644 --- a/layout/svg/base/src/nsSVGFilterFrame.cpp +++ b/layout/svg/base/src/nsSVGFilterFrame.cpp @@ -35,6 +35,8 @@ * ***** END LICENSE BLOCK ***** */ #include "nsSVGFilterFrame.h" + +#include "nsRenderingContext.h" #include "nsIDocument.h" #include "nsSVGOuterSVGFrame.h" #include "nsGkAtoms.h" diff --git a/layout/svg/base/src/nsSVGFilterFrame.h b/layout/svg/base/src/nsSVGFilterFrame.h index 77d3c79651ee..c67a9f5c4a36 100644 --- a/layout/svg/base/src/nsSVGFilterFrame.h +++ b/layout/svg/base/src/nsSVGFilterFrame.h @@ -37,14 +37,22 @@ #ifndef __NS_SVGFILTERFRAME_H__ #define __NS_SVGFILTERFRAME_H__ +#include "nsFrame.h" +#include "nsQueryFrame.h" #include "nsRect.h" #include "nsSVGContainerFrame.h" #include "nsSVGUtils.h" +class nsIAtom; +class nsIContent; +class nsIFrame; +class nsIPresShell; class nsRenderingContext; +class nsStyleContext; class nsSVGFilterPaintCallback; typedef nsSVGContainerFrame nsSVGFilterFrameBase; + class nsSVGFilterFrame : public nsSVGFilterFrameBase { friend nsIFrame* diff --git a/layout/svg/base/src/nsSVGFilterInstance.cpp b/layout/svg/base/src/nsSVGFilterInstance.cpp index 4c694c37b1dd..2f52b7faf484 100644 --- a/layout/svg/base/src/nsSVGFilterInstance.cpp +++ b/layout/svg/base/src/nsSVGFilterInstance.cpp @@ -35,6 +35,8 @@ * ***** END LICENSE BLOCK ***** */ #include "nsSVGFilterInstance.h" + +#include "nsRenderingContext.h" #include "nsSVGUtils.h" #include "nsIDOMSVGUnitTypes.h" #include "gfxPlatform.h" diff --git a/layout/svg/base/src/nsSVGFilterInstance.h b/layout/svg/base/src/nsSVGFilterInstance.h index 2d80d8376723..60b463e2c774 100644 --- a/layout/svg/base/src/nsSVGFilterInstance.h +++ b/layout/svg/base/src/nsSVGFilterInstance.h @@ -37,21 +37,24 @@ #ifndef __NS_SVGFILTERINSTANCE_H__ #define __NS_SVGFILTERINSTANCE_H__ -#include "nsIDOMSVGLength.h" -#include "nsIDOMSVGFilters.h" +#include "gfxMatrix.h" +#include "gfxPoint.h" +#include "gfxRect.h" +#include "nsCOMPtr.h" +#include "nsHashKeys.h" +#include "nsPoint.h" #include "nsRect.h" -#include "nsIContent.h" -#include "nsAutoPtr.h" +#include "nsSize.h" #include "nsSVGFilters.h" #include "nsSVGNumber2.h" #include "nsSVGNumberPair.h" +#include "nsTArray.h" -#include "gfxImageSurface.h" - -class nsSVGElement; +class gfxASurface; +class gfxImageSurface; +class nsIFrame; class nsSVGFilterElement; class nsSVGFilterPaintCallback; -struct gfxRect; /** * This class performs all filter processing. diff --git a/layout/svg/base/src/nsSVGFilterPaintCallback.h b/layout/svg/base/src/nsSVGFilterPaintCallback.h index 49c56afff326..1b5c2a9704bb 100644 --- a/layout/svg/base/src/nsSVGFilterPaintCallback.h +++ b/layout/svg/base/src/nsSVGFilterPaintCallback.h @@ -37,11 +37,11 @@ #ifndef __NS_SVGFILTERPAINTCALLBACK_H__ #define __NS_SVGFILTERPAINTCALLBACK_H__ -#include "nsRect.h" - class nsIFrame; class nsRenderingContext; +struct nsIntRect; + class nsSVGFilterPaintCallback { public: /** diff --git a/layout/svg/base/src/nsSVGForeignObjectFrame.cpp b/layout/svg/base/src/nsSVGForeignObjectFrame.cpp index 0d9a7b642c93..11817e3c4dc4 100644 --- a/layout/svg/base/src/nsSVGForeignObjectFrame.cpp +++ b/layout/svg/base/src/nsSVGForeignObjectFrame.cpp @@ -42,12 +42,14 @@ #include "nsIDOMSVGSVGElement.h" #include "nsSVGOuterSVGFrame.h" #include "nsRegion.h" +#include "nsRenderingContext.h" #include "nsGkAtoms.h" #include "nsLayoutUtils.h" #include "nsSVGUtils.h" #include "nsIURI.h" #include "nsSVGRect.h" #include "nsINameSpaceManager.h" +#include "nsSVGEffects.h" #include "nsSVGForeignObjectElement.h" #include "nsSVGContainerFrame.h" #include "gfxContext.h" @@ -91,20 +93,10 @@ nsSVGForeignObjectFrame::Init(nsIContent* aContent, nsresult rv = nsSVGForeignObjectFrameBase::Init(aContent, aParent, aPrevInFlow); AddStateBits(aParent->GetStateBits() & - (NS_STATE_SVG_NONDISPLAY_CHILD | NS_STATE_SVG_CLIPPATH_CHILD | - NS_STATE_SVG_REDRAW_SUSPENDED)); - if (NS_SUCCEEDED(rv)) { - nsSVGUtils::GetOuterSVGFrame(this)->RegisterForeignObject(this); - } + (NS_STATE_SVG_NONDISPLAY_CHILD | NS_STATE_SVG_CLIPPATH_CHILD)); return rv; } -void nsSVGForeignObjectFrame::DestroyFrom(nsIFrame* aDestructRoot) -{ - nsSVGUtils::GetOuterSVGFrame(this)->UnregisterForeignObject(this); - nsSVGForeignObjectFrameBase::DestroyFrom(aDestructRoot); -} - nsIAtom * nsSVGForeignObjectFrame::GetType() const { @@ -119,17 +111,18 @@ nsSVGForeignObjectFrame::AttributeChanged(PRInt32 aNameSpaceID, if (aNameSpaceID == kNameSpaceID_None) { if (aAttribute == nsGkAtoms::width || aAttribute == nsGkAtoms::height) { - UpdateGraphic(); // update mRect before requesting reflow + nsSVGUtils::InvalidateAndScheduleBoundsUpdate(this); // XXXjwatt: why mark intrinsic widths dirty? can't we just use eResize? RequestReflow(nsIPresShell::eStyleChange); } else if (aAttribute == nsGkAtoms::x || aAttribute == nsGkAtoms::y || - aAttribute == nsGkAtoms::viewBox || - aAttribute == nsGkAtoms::preserveAspectRatio || aAttribute == nsGkAtoms::transform) { // make sure our cached transform matrix gets (lazily) updated mCanvasTM = nsnull; - UpdateGraphic(); + nsSVGUtils::InvalidateAndScheduleBoundsUpdate(this); + } else if (aAttribute == nsGkAtoms::viewBox || + aAttribute == nsGkAtoms::preserveAspectRatio) { + nsSVGUtils::InvalidateBounds(this); } } @@ -145,7 +138,10 @@ nsSVGForeignObjectFrame::DidSetStyleContext(nsStyleContext* aOldStyleContext) // Moreover we haven't been initialised properly yet so we may not have the // right state bits. if (!(GetStateBits() & NS_FRAME_FIRST_REFLOW)) { - UpdateGraphic(); + // XXXperf: probably only need a bounds update if 'font-size' changed and + // we have em unit width/height. Or, once we map 'transform' into style, + // if some transform property changed. + nsSVGUtils::InvalidateAndScheduleBoundsUpdate(this); } } @@ -155,8 +151,18 @@ nsSVGForeignObjectFrame::Reflow(nsPresContext* aPresContext, const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus) { - // InitialUpdate and AttributeChanged make sure mRect is up to date before - // we're called (UpdateCoveredRegion sets mRect). + NS_ABORT_IF_FALSE(!(GetStateBits() & NS_STATE_SVG_NONDISPLAY_CHILD), + "Should not have been called"); + + // Only InvalidateAndScheduleBoundsUpdate marks us with NS_FRAME_IS_DIRTY, + // so if that bit is still set we still have a resize pending. If we hit + // this assertion, then we should get the presShell to skip reflow roots + // that have a dirty parent since a reflow is going to come via the + // reflow root's parent anyway. + NS_ASSERTION(!(GetStateBits() & NS_FRAME_IS_DIRTY), + "Reflowing while a resize is pending is wasteful"); + + // UpdateBounds makes sure mRect is up to date before we're called. NS_ASSERTION(!aReflowState.parentReflowState, "should only get reflow from being reflow root"); @@ -183,13 +189,27 @@ nsSVGForeignObjectFrame::InvalidateInternal(const nsRect& aDamageRect, { // This is called by our descendants when they change. - if (GetStateBits() & NS_STATE_SVG_NONDISPLAY_CHILD) + if (GetStateBits() & NS_FRAME_IS_DIRTY) { + // Our entire area has been (or will be) invalidated, so no point + // keeping track of sub-areas that our descendants dirty. return; + } + + if (GetStateBits() & NS_STATE_SVG_NONDISPLAY_CHILD) { + nsSVGEffects::InvalidateRenderingObservers(this); + return; + } + + if (!mInReflow) { + // We can't collect dirty areas, since we don't have a place to reliably + // call FlushDirtyRegion before we paint, so we have to invalidate now. + InvalidateDirtyRect(nsSVGUtils::GetOuterSVGFrame(this), aDamageRect + nsPoint(aX, aY), aFlags); + return; + } nsRegion* region = (aFlags & INVALIDATE_CROSS_DOC) ? &mSubDocDirtyRegion : &mSameDocDirtyRegion; region->Or(*region, aDamageRect + nsPoint(aX, aY)); - FlushDirtyRegion(aFlags); } @@ -345,11 +365,21 @@ nsSVGForeignObjectFrame::GetCoveredRegion() return mCoveredRegion; } -NS_IMETHODIMP -nsSVGForeignObjectFrame::UpdateCoveredRegion() +void +nsSVGForeignObjectFrame::UpdateBounds() { - if (GetStateBits() & NS_STATE_SVG_NONDISPLAY_CHILD) - return NS_ERROR_FAILURE; + NS_ASSERTION(nsSVGUtils::OuterSVGIsCallingUpdateBounds(this), + "This call is probaby a wasteful mistake"); + + NS_ABORT_IF_FALSE(!(GetStateBits() & NS_STATE_SVG_NONDISPLAY_CHILD), + "UpdateBounds mechanism not designed for this"); + + if (!nsSVGUtils::NeedsUpdatedBounds(this)) { + return; + } + + // We update mRect before the DoReflow call so that DoReflow uses the + // correct dimensions: float x, y, w, h; static_cast(mContent)-> @@ -365,30 +395,32 @@ nsSVGForeignObjectFrame::UpdateCoveredRegion() PresContext()->AppUnitsPerCSSPixel()); mCoveredRegion = ToCanvasBounds(gfxRect(0.0, 0.0, w, h), GetCanvasTM(), PresContext()); - return NS_OK; -} + // Since we'll invalidate our entire area at the end of this method, we + // empty our cached dirty regions to prevent FlushDirtyRegion under DoReflow + // from wasting time invalidating: + mSameDocDirtyRegion.SetEmpty(); + mSubDocDirtyRegion.SetEmpty(); -NS_IMETHODIMP -nsSVGForeignObjectFrame::InitialUpdate() -{ - NS_ASSERTION(GetStateBits() & NS_FRAME_FIRST_REFLOW, - "Yikes! We've been called already! Hopefully we weren't called " - "before our nsSVGOuterSVGFrame's initial Reflow()!!!"); + // Fully mark our kid dirty so that it gets resized if necessary + // (NS_FRAME_HAS_DIRTY_CHILDREN isn't enough in that case): + nsIFrame* kid = GetFirstPrincipalChild(); + kid->AddStateBits(NS_FRAME_IS_DIRTY); - UpdateCoveredRegion(); - - // Make sure to not allow interrupts if we're not being reflown as a root + // Make sure to not allow interrupts if we're not being reflown as a root: nsPresContext::InterruptPreventer noInterrupts(PresContext()); + DoReflow(); - NS_ASSERTION(!(mState & NS_FRAME_IN_REFLOW), - "We don't actually participate in reflow"); - - // Do unset the various reflow bits, though. + // Now unset the various reflow bits: mState &= ~(NS_FRAME_FIRST_REFLOW | NS_FRAME_IS_DIRTY | NS_FRAME_HAS_DIRTY_CHILDREN); - return NS_OK; + if (!(GetParent()->GetStateBits() & NS_FRAME_FIRST_REFLOW)) { + // We only invalidate if our outer- has already had its + // initial reflow (since if it hasn't, its entire area will be + // invalidated when it gets that initial reflow): + nsSVGUtils::InvalidateBounds(this, true); + } } void @@ -401,9 +433,32 @@ nsSVGForeignObjectFrame::NotifySVGChanged(PRUint32 aFlags) NS_ABORT_IF_FALSE(aFlags & (TRANSFORM_CHANGED | COORD_CONTEXT_CHANGED), "Invalidation logic may need adjusting"); - bool reflow = false; + bool needNewBounds = false; // i.e. mRect or visual overflow rect + bool needReflow = false; + bool needNewCanvasTM = false; + + if (aFlags & COORD_CONTEXT_CHANGED) { + nsSVGForeignObjectElement *fO = + static_cast(mContent); + // Coordinate context changes affect mCanvasTM if we have a + // percentage 'x' or 'y' + if (fO->mLengthAttributes[nsSVGForeignObjectElement::X].IsPercentage() || + fO->mLengthAttributes[nsSVGForeignObjectElement::Y].IsPercentage()) { + needNewBounds = true; + needNewCanvasTM = true; + } + // Our coordinate context's width/height has changed. If we have a + // percentage width/height our dimensions will change so we must reflow. + if (fO->mLengthAttributes[nsSVGForeignObjectElement::WIDTH].IsPercentage() || + fO->mLengthAttributes[nsSVGForeignObjectElement::HEIGHT].IsPercentage()) { + needNewBounds = true; + needReflow = true; + } + } if (aFlags & TRANSFORM_CHANGED) { + needNewBounds = true; // needed if it was _our_ transform that changed + needNewCanvasTM = true; // In an ideal world we would reflow when our CTM changes. This is because // glyph metrics do not necessarily scale uniformly with change in scale // and, as a result, CTM changes may require text to break at different @@ -411,60 +466,28 @@ nsSVGForeignObjectFrame::NotifySVGChanged(PRUint32 aFlags) // e.g. the transform of an ancestor is animated. // We also seem to get some sort of infinite loop post bug 421584 if we // reflow. + } + + if (needNewBounds && + !(aFlags & DO_NOT_NOTIFY_RENDERING_OBSERVERS)) { + nsSVGUtils::InvalidateAndScheduleBoundsUpdate(this); + } + + // If we're called while the PresShell is handling reflow events then we + // must have been called as a result of the NotifyViewportChange() call in + // our nsSVGOuterSVGFrame's Reflow() method. We must not call RequestReflow + // at this point (i.e. during reflow) because it could confuse the + // PresShell and prevent it from reflowing us properly in future. Besides + // that, nsSVGOuterSVGFrame::DidReflow will take care of reflowing us + // synchronously, so there's no need. + if (needReflow && !PresContext()->PresShell()->IsReflowLocked()) { + RequestReflow(nsIPresShell::eResize); + } + + if (needNewCanvasTM) { + // Do this after calling InvalidateAndScheduleBoundsUpdate in case we + // change the code and it needs to use it. mCanvasTM = nsnull; - if (!(aFlags & DO_NOT_NOTIFY_RENDERING_OBSERVERS)) { - UpdateGraphic(); - } - - } else if (aFlags & COORD_CONTEXT_CHANGED) { - nsSVGForeignObjectElement *fO = - static_cast(mContent); - // Coordinate context changes affect mCanvasTM if we have a - // percentage 'x' or 'y' - if (fO->mLengthAttributes[nsSVGForeignObjectElement::X].IsPercentage() || - fO->mLengthAttributes[nsSVGForeignObjectElement::Y].IsPercentage()) { - mCanvasTM = nsnull; - } - // Our coordinate context's width/height has changed. If we have a - // percentage width/height our dimensions will change so we must reflow. - if (fO->mLengthAttributes[nsSVGForeignObjectElement::WIDTH].IsPercentage() || - fO->mLengthAttributes[nsSVGForeignObjectElement::HEIGHT].IsPercentage()) { - reflow = true; - } - } - - if (reflow) { - // If we're called while the PresShell is handling reflow events then we - // must have been called as a result of the NotifyViewportChange() call in - // our nsSVGOuterSVGFrame's Reflow() method. We must not call RequestReflow - // at this point (i.e. during reflow) because it could confuse the - // PresShell and prevent it from reflowing us properly in future. Besides - // that, nsSVGOuterSVGFrame::DidReflow will take care of reflowing us - // synchronously, so there's no need. - if (!PresContext()->PresShell()->IsReflowLocked()) { - UpdateGraphic(); // update mRect before requesting reflow - RequestReflow(nsIPresShell::eResize); - } - } -} - -void -nsSVGForeignObjectFrame::NotifyRedrawSuspended() -{ - AddStateBits(NS_STATE_SVG_REDRAW_SUSPENDED); -} - -void -nsSVGForeignObjectFrame::NotifyRedrawUnsuspended() -{ - RemoveStateBits(NS_STATE_SVG_REDRAW_SUSPENDED); - - if (!(GetStateBits() & NS_STATE_SVG_NONDISPLAY_CHILD)) { - if (GetStateBits() & NS_STATE_SVG_DIRTY) { - UpdateGraphic(); // invalidate our entire area - } else { - FlushDirtyRegion(0); // only invalidate areas dirtied by our descendants - } } } @@ -522,7 +545,7 @@ nsSVGForeignObjectFrame::GetCanvasTMForChildren() void nsSVGForeignObjectFrame::RequestReflow(nsIPresShell::IntrinsicDirty aType) { if (GetStateBits() & NS_FRAME_FIRST_REFLOW) - // If we haven't had an InitialUpdate yet, nothing to do. + // If we haven't had a UpdateBounds yet, nothing to do. return; nsIFrame* kid = GetFirstPrincipalChild(); @@ -532,63 +555,14 @@ void nsSVGForeignObjectFrame::RequestReflow(nsIPresShell::IntrinsicDirty aType) PresContext()->PresShell()->FrameNeedsReflow(kid, aType, NS_FRAME_IS_DIRTY); } -void nsSVGForeignObjectFrame::UpdateGraphic() -{ - nsSVGUtils::UpdateGraphic(this); - - // We just invalidated our entire area, so clear the caches of areas dirtied - // by our descendants: - mSameDocDirtyRegion.SetEmpty(); - mSubDocDirtyRegion.SetEmpty(); -} - -void -nsSVGForeignObjectFrame::MaybeReflowFromOuterSVGFrame() -{ - // If IsDisabled() is true, then we know that our DoReflow() call will return - // early, leaving us with a marked-dirty but not-reflowed kid. That'd be bad; - // it'd mean that all future calls to this method would be doomed to take the - // NS_FRAME_IS_DIRTY early-return below. To avoid that problem, we need to - // bail out *before* we mark our kid as dirty. - if (IsDisabled()) { - return; - } - - nsIFrame* kid = GetFirstPrincipalChild(); - - // If we're already scheduled to reflow (if we or our kid is dirty) we don't - // want to reflow now or else our presShell will do extra work trying to - // reflow us a second time. (It will also complain if it finds that a reflow - // root scheduled for reflow isn't dirty). - - if (kid->GetStateBits() & NS_FRAME_IS_DIRTY) { - return; - } - kid->AddStateBits(NS_FRAME_IS_DIRTY); // we must be fully marked dirty - if (kid->GetStateBits() & NS_FRAME_HAS_DIRTY_CHILDREN) { - return; - } - - // Make sure to not allow interrupts if we're not being reflown as a root - nsPresContext::InterruptPreventer noInterrupts(PresContext()); - DoReflow(); -} - void nsSVGForeignObjectFrame::DoReflow() { - NS_ASSERTION(!(nsSVGUtils::GetOuterSVGFrame(this)-> - GetStateBits() & NS_FRAME_FIRST_REFLOW), - "Calling InitialUpdate too early - must not call DoReflow!!!"); - // Skip reflow if we're zero-sized, unless this is our first reflow. if (IsDisabled() && !(GetStateBits() & NS_FRAME_FIRST_REFLOW)) return; - if (GetStateBits() & NS_STATE_SVG_NONDISPLAY_CHILD) - return; - nsPresContext *presContext = PresContext(); nsIFrame* kid = GetFirstPrincipalChild(); if (!kid) @@ -602,48 +576,36 @@ nsSVGForeignObjectFrame::DoReflow() if (!renderingContext) return; - nsSVGForeignObjectElement *fO = static_cast - (mContent); - - float width = - fO->mLengthAttributes[nsSVGForeignObjectElement::WIDTH].GetAnimValue(fO); - float height = - fO->mLengthAttributes[nsSVGForeignObjectElement::HEIGHT].GetAnimValue(fO); - - // Clamp height & width to be non-negative (to match UpdateCoveredRegion). - width = NS_MAX(width, 0.0f); - height = NS_MAX(height, 0.0f); - - nsSize size(nsPresContext::CSSPixelsToAppUnits(width), - nsPresContext::CSSPixelsToAppUnits(height)); - mInReflow = true; nsHTMLReflowState reflowState(presContext, kid, renderingContext, - nsSize(size.width, NS_UNCONSTRAINEDSIZE)); + nsSize(mRect.width, NS_UNCONSTRAINEDSIZE)); nsHTMLReflowMetrics desiredSize; nsReflowStatus status; - // We don't use size.height above because that tells the child to do + // We don't use mRect.height above because that tells the child to do // page/column breaking at that height. NS_ASSERTION(reflowState.mComputedBorderPadding == nsMargin(0, 0, 0, 0) && reflowState.mComputedMargin == nsMargin(0, 0, 0, 0), "style system should ensure that :-moz-svg-foreign-content " "does not get styled"); - NS_ASSERTION(reflowState.ComputedWidth() == size.width, + NS_ASSERTION(reflowState.ComputedWidth() == mRect.width, "reflow state made child wrong size"); - reflowState.SetComputedHeight(size.height); - + reflowState.SetComputedHeight(mRect.height); + ReflowChild(kid, presContext, desiredSize, reflowState, 0, 0, NS_FRAME_NO_MOVE_FRAME, status); - NS_ASSERTION(size.width == desiredSize.width && - size.height == desiredSize.height, "unexpected size"); + NS_ASSERTION(mRect.width == desiredSize.width && + mRect.height == desiredSize.height, "unexpected size"); FinishReflowChild(kid, presContext, &reflowState, desiredSize, 0, 0, NS_FRAME_NO_MOVE_FRAME); mInReflow = false; - FlushDirtyRegion(0); + + if (!(GetStateBits() & NS_STATE_SVG_NONDISPLAY_CHILD)) { + FlushDirtyRegion(0); + } } void @@ -672,10 +634,15 @@ nsSVGForeignObjectFrame::InvalidateDirtyRect(nsSVGOuterSVGFrame* aOuter, void nsSVGForeignObjectFrame::FlushDirtyRegion(PRUint32 aFlags) { - if ((mSameDocDirtyRegion.IsEmpty() && mSubDocDirtyRegion.IsEmpty()) || - mInReflow || - (GetStateBits() & NS_STATE_SVG_REDRAW_SUSPENDED)) + NS_ABORT_IF_FALSE(!(GetStateBits() & NS_STATE_SVG_NONDISPLAY_CHILD), + "Should not have been called"); + + NS_ASSERTION(!mInReflow, + "We shouldn't be flushing while we have a pending flush"); + + if (mSameDocDirtyRegion.IsEmpty() && mSubDocDirtyRegion.IsEmpty()) { return; + } nsSVGOuterSVGFrame *outerSVGFrame = nsSVGUtils::GetOuterSVGFrame(this); if (!outerSVGFrame) { diff --git a/layout/svg/base/src/nsSVGForeignObjectFrame.h b/layout/svg/base/src/nsSVGForeignObjectFrame.h index 5085734eb041..7a8995c0eeb6 100644 --- a/layout/svg/base/src/nsSVGForeignObjectFrame.h +++ b/layout/svg/base/src/nsSVGForeignObjectFrame.h @@ -40,11 +40,10 @@ #define NSSVGFOREIGNOBJECTFRAME_H__ #include "nsContainerFrame.h" -#include "nsISVGChildFrame.h" -#include "nsSVGUtils.h" -#include "nsRegion.h" #include "nsIPresShell.h" -#include "mozilla/Attributes.h" +#include "nsISVGChildFrame.h" +#include "nsRegion.h" +#include "nsSVGUtils.h" class nsRenderingContext; class nsSVGOuterSVGFrame; @@ -67,7 +66,6 @@ public: NS_IMETHOD Init(nsIContent* aContent, nsIFrame* aParent, nsIFrame* aPrevInFlow); - virtual void DestroyFrom(nsIFrame* aDestructRoot); NS_IMETHOD AttributeChanged(PRInt32 aNameSpaceID, nsIAtom* aAttribute, PRInt32 aModType); @@ -126,11 +124,8 @@ public: const nsIntRect *aDirtyRect); NS_IMETHOD_(nsIFrame*) GetFrameForPoint(const nsPoint &aPoint); NS_IMETHOD_(nsRect) GetCoveredRegion(); - NS_IMETHOD UpdateCoveredRegion(); - NS_IMETHOD InitialUpdate(); + virtual void UpdateBounds(); virtual void NotifySVGChanged(PRUint32 aFlags); - virtual void NotifyRedrawSuspended(); - virtual void NotifyRedrawUnsuspended(); virtual gfxRect GetBBoxContribution(const gfxMatrix &aToBBoxUserspace, PRUint32 aFlags); NS_IMETHOD_(bool) IsDisplayContainer() { return true; } @@ -140,14 +135,10 @@ public: gfxMatrix GetCanvasTM(); - // This method allows our nsSVGOuterSVGFrame to reflow us as necessary. - void MaybeReflowFromOuterSVGFrame(); - protected: // implementation helpers: void DoReflow(); void RequestReflow(nsIPresShell::IntrinsicDirty aType); - void UpdateGraphic(); // Returns GetCanvasTM followed by a scale from CSS px to Dev px. Used for // painting, because children expect to paint to device space, not userspace. diff --git a/layout/svg/base/src/nsSVGGFrame.h b/layout/svg/base/src/nsSVGGFrame.h index 2b3b3784310a..82d268eda1c5 100644 --- a/layout/svg/base/src/nsSVGGFrame.h +++ b/layout/svg/base/src/nsSVGGFrame.h @@ -39,8 +39,8 @@ #ifndef NSSVGGFRAME_H #define NSSVGGFRAME_H -#include "nsSVGContainerFrame.h" #include "gfxMatrix.h" +#include "nsSVGContainerFrame.h" typedef nsSVGDisplayContainerFrame nsSVGGFrameBase; diff --git a/layout/svg/base/src/nsSVGGenericContainerFrame.h b/layout/svg/base/src/nsSVGGenericContainerFrame.h index ace4ec3bcbf7..b60a7bbc1935 100644 --- a/layout/svg/base/src/nsSVGGenericContainerFrame.h +++ b/layout/svg/base/src/nsSVGGenericContainerFrame.h @@ -39,10 +39,16 @@ #ifndef __NS_SVGGENERICCONTAINERFRAME_H__ #define __NS_SVGGENERICCONTAINERFRAME_H__ -#include "nsIDOMSVGGElement.h" -#include "nsSVGContainerFrame.h" -#include "nsGkAtoms.h" #include "gfxMatrix.h" +#include "nsFrame.h" +#include "nsLiteralString.h" +#include "nsQueryFrame.h" +#include "nsSVGContainerFrame.h" + +class nsIAtom; +class nsIFrame; +class nsIPresShell; +class nsStyleContext; typedef nsSVGDisplayContainerFrame nsSVGGenericContainerFrameBase; diff --git a/layout/svg/base/src/nsSVGGeometryFrame.cpp b/layout/svg/base/src/nsSVGGeometryFrame.cpp index ea7ef9143948..5ce63db3e9ed 100644 --- a/layout/svg/base/src/nsSVGGeometryFrame.cpp +++ b/layout/svg/base/src/nsSVGGeometryFrame.cpp @@ -54,8 +54,7 @@ nsSVGGeometryFrame::Init(nsIContent* aContent, nsIFrame* aPrevInFlow) { AddStateBits(aParent->GetStateBits() & - (NS_STATE_SVG_NONDISPLAY_CHILD | NS_STATE_SVG_CLIPPATH_CHILD | - NS_STATE_SVG_REDRAW_SUSPENDED)); + (NS_STATE_SVG_NONDISPLAY_CHILD | NS_STATE_SVG_CLIPPATH_CHILD)); nsresult rv = nsSVGGeometryFrameBase::Init(aContent, aParent, aPrevInFlow); return rv; } diff --git a/layout/svg/base/src/nsSVGGeometryFrame.h b/layout/svg/base/src/nsSVGGeometryFrame.h index 07e0d6581288..a4a166551581 100644 --- a/layout/svg/base/src/nsSVGGeometryFrame.h +++ b/layout/svg/base/src/nsSVGGeometryFrame.h @@ -38,11 +38,19 @@ #ifndef __NS_SVGGEOMETRYFRAME_H__ #define __NS_SVGGEOMETRYFRAME_H__ -#include "nsFrame.h" #include "gfxMatrix.h" +#include "gfxTypes.h" +#include "nsFrame.h" +#include "nsIFrame.h" +#include "nsQueryFrame.h" +#include "nsRect.h" -class nsSVGPaintServerFrame; class gfxContext; +class nsIContent; +class nsStyleContext; +class nsSVGPaintServerFrame; + +struct nsStyleSVGPaint; typedef nsFrame nsSVGGeometryFrameBase; diff --git a/layout/svg/base/src/nsSVGGlyphFrame.cpp b/layout/svg/base/src/nsSVGGlyphFrame.cpp index 8b5cef7b616b..2c24d7f26073 100644 --- a/layout/svg/base/src/nsSVGGlyphFrame.cpp +++ b/layout/svg/base/src/nsSVGGlyphFrame.cpp @@ -36,6 +36,9 @@ * * ***** END LICENSE BLOCK ***** */ +#include "nsSVGGlyphFrame.h" + +#include "nsRenderingContext.h" #include "nsSVGTextFrame.h" #include "mozilla/LookAndFeel.h" #include "nsTextFragment.h" @@ -45,7 +48,6 @@ #include "nsIDOMSVGLength.h" #include "nsIDOMSVGRect.h" #include "DOMSVGPoint.h" -#include "nsSVGGlyphFrame.h" #include "nsSVGTextPathFrame.h" #include "nsSVGPathElement.h" #include "nsSVGRect.h" @@ -254,11 +256,18 @@ NS_QUERYFRAME_TAIL_INHERITING(nsSVGGlyphFrameBase) NS_IMETHODIMP nsSVGGlyphFrame::CharacterDataChanged(CharacterDataChangeInfo* aInfo) { - ClearTextRun(); + // NotifyGlyphMetricsChange takes care of calling + // nsSVGUtils::InvalidateAndScheduleBoundsUpdate on the appropriate frames. + NotifyGlyphMetricsChange(); + + ClearTextRun(); if (IsTextEmpty()) { - // That's it for this frame. Leave no trace we were here - nsSVGUtils::UpdateGraphic(this); + // The one time that NotifyGlyphMetricsChange fails to call + // nsSVGUtils::InvalidateAndScheduleBoundsUpdate properly is when all our + // text is gone, since it skips empty frames. So we have to invalidate + // ourself. + nsSVGUtils::InvalidateBounds(this); } return NS_OK; @@ -445,9 +454,15 @@ nsSVGGlyphFrame::GetCoveredRegion() return mCoveredRegion; } -NS_IMETHODIMP -nsSVGGlyphFrame::UpdateCoveredRegion() +void +nsSVGGlyphFrame::UpdateBounds() { + NS_ASSERTION(nsSVGUtils::OuterSVGIsCallingUpdateBounds(this), + "This call is probaby a wasteful mistake"); + + NS_ABORT_IF_FALSE(!(GetStateBits() & NS_STATE_SVG_NONDISPLAY_CHILD), + "UpdateBounds mechanism not designed for this"); + mRect.SetEmpty(); // XXX here we have tmpCtx use its default identity matrix, but does this @@ -458,7 +473,7 @@ nsSVGGlyphFrame::UpdateCoveredRegion() if (hasStroke) { SetupCairoStrokeGeometry(tmpCtx); } else if (GetStyleSVG()->mFill.mType == eStyleSVGPaintType_None) { - return NS_OK; + return; } CharacterIterator iter(this, true); @@ -498,24 +513,15 @@ nsSVGGlyphFrame::UpdateCoveredRegion() mCoveredRegion = nsSVGUtils::TransformFrameRectToOuterSVG( mRect, GetCanvasTM(), PresContext()); - return NS_OK; -} - -NS_IMETHODIMP -nsSVGGlyphFrame::InitialUpdate() -{ - NS_ASSERTION(GetStateBits() & NS_FRAME_FIRST_REFLOW, - "Yikes! We've been called already! Hopefully we weren't called " - "before our nsSVGOuterSVGFrame's initial Reflow()!!!"); - - NS_ASSERTION(!(mState & NS_FRAME_IN_REFLOW), - "We don't actually participate in reflow"); - - // Do unset the various reflow bits, though. mState &= ~(NS_FRAME_FIRST_REFLOW | NS_FRAME_IS_DIRTY | NS_FRAME_HAS_DIRTY_CHILDREN); - - return NS_OK; + + if (!(GetParent()->GetStateBits() & NS_FRAME_FIRST_REFLOW)) { + // We only invalidate if our outer- has already had its + // initial reflow (since if it hasn't, its entire area will be + // invalidated when it gets that initial reflow): + nsSVGUtils::InvalidateBounds(this, true); + } } void @@ -528,27 +534,15 @@ nsSVGGlyphFrame::NotifySVGChanged(PRUint32 aFlags) NS_ABORT_IF_FALSE(aFlags & (TRANSFORM_CHANGED | COORD_CONTEXT_CHANGED), "Invalidation logic may need adjusting"); + // XXXjwatt: seems to me that this could change the glyph metrics, + // in which case we should call NotifyGlyphMetricsChange instead. + if (!(aFlags & DO_NOT_NOTIFY_RENDERING_OBSERVERS)) { + nsSVGUtils::InvalidateAndScheduleBoundsUpdate(this); + } + if (aFlags & TRANSFORM_CHANGED) { ClearTextRun(); } - if (!(aFlags & DO_NOT_NOTIFY_RENDERING_OBSERVERS)) { - nsSVGUtils::UpdateGraphic(this); - } -} - -void -nsSVGGlyphFrame::NotifyRedrawSuspended() -{ - AddStateBits(NS_STATE_SVG_REDRAW_SUSPENDED); -} - -void -nsSVGGlyphFrame::NotifyRedrawUnsuspended() -{ - RemoveStateBits(NS_STATE_SVG_REDRAW_SUSPENDED); - - if (GetStateBits() & NS_STATE_SVG_DIRTY) - nsSVGUtils::UpdateGraphic(this); } void diff --git a/layout/svg/base/src/nsSVGGlyphFrame.h b/layout/svg/base/src/nsSVGGlyphFrame.h index fc1c99ee066f..a845c9478754 100644 --- a/layout/svg/base/src/nsSVGGlyphFrame.h +++ b/layout/svg/base/src/nsSVGGlyphFrame.h @@ -39,19 +39,21 @@ #ifndef __NS_SVGGLYPHFRAME_H__ #define __NS_SVGGLYPHFRAME_H__ -#include "nsSVGGeometryFrame.h" +#include "gfxFont.h" #include "nsISVGGlyphFragmentNode.h" #include "nsISVGChildFrame.h" +#include "nsSVGGeometryFrame.h" #include "nsSVGUtils.h" -#include "gfxContext.h" -#include "gfxFont.h" #include "nsTextFragment.h" +class CharacterIterator; +class gfxContext; +class nsIDOMSVGRect; class nsRenderingContext; +class nsSVGGlyphFrame; class nsSVGTextFrame; class nsSVGTextPathFrame; -class nsSVGGlyphFrame; -class CharacterIterator; + struct CharacterPosition; typedef gfxFont::DrawMode DrawMode; @@ -176,15 +178,12 @@ public: NS_IMETHOD PaintSVG(nsRenderingContext *aContext, const nsIntRect *aDirtyRect); NS_IMETHOD_(nsIFrame*) GetFrameForPoint(const nsPoint &aPoint); - NS_IMETHOD UpdateCoveredRegion(); virtual gfxRect GetBBoxContribution(const gfxMatrix &aToBBoxUserspace, PRUint32 aFlags); NS_IMETHOD_(nsRect) GetCoveredRegion(); - NS_IMETHOD InitialUpdate(); + virtual void UpdateBounds(); virtual void NotifySVGChanged(PRUint32 aFlags); - virtual void NotifyRedrawSuspended(); - virtual void NotifyRedrawUnsuspended(); NS_IMETHOD_(bool) IsDisplayContainer() { return false; } NS_IMETHOD_(bool) HasValidCoveredRect() { return !(GetStateBits() & NS_STATE_SVG_NONDISPLAY_CHILD); diff --git a/layout/svg/base/src/nsSVGGradientFrame.cpp b/layout/svg/base/src/nsSVGGradientFrame.cpp index 8a1b7c2bb53e..f214d0c96a44 100644 --- a/layout/svg/base/src/nsSVGGradientFrame.cpp +++ b/layout/svg/base/src/nsSVGGradientFrame.cpp @@ -172,6 +172,19 @@ nsSVGGradientFrame::GetEnumValue(PRUint32 aIndex, nsIContent *aDefault) mEnumAttributes[aIndex].GetAnimValue(); } +PRUint16 +nsSVGGradientFrame::GetGradientUnits() +{ + // This getter is called every time the others are called - maybe cache it? + return GetEnumValue(nsSVGGradientElement::GRADIENTUNITS); +} + +PRUint16 +nsSVGGradientFrame::GetSpreadMethod() +{ + return GetEnumValue(nsSVGGradientElement::SPREADMETHOD); +} + const SVGAnimatedTransformList* nsSVGGradientFrame::GetGradientTransformList(nsIContent* aDefault) { diff --git a/layout/svg/base/src/nsSVGGradientFrame.h b/layout/svg/base/src/nsSVGGradientFrame.h index 3a19414417cb..dad4d6b05767 100644 --- a/layout/svg/base/src/nsSVGGradientFrame.h +++ b/layout/svg/base/src/nsSVGGradientFrame.h @@ -39,11 +39,26 @@ #ifndef __NS_SVGGRADIENTFRAME_H__ #define __NS_SVGGRADIENTFRAME_H__ +#include "gfxMatrix.h" +#include "nsCOMPtr.h" +#include "nsFrame.h" +#include "nsLiteralString.h" #include "nsSVGPaintServerFrame.h" -#include "nsSVGElement.h" -#include "gfxPattern.h" -class nsIDOMSVGStopElement; +class gfxPattern; +class nsIAtom; +class nsIContent; +class nsIFrame; +class nsIPresShell; +class nsStyleContext; +class nsSVGLinearGradientElement; +class nsSVGRadialGradientElement; + +struct gfxRect; + +namespace mozilla { +class SVGAnimatedTransformList; +} typedef nsSVGPaintServerFrame nsSVGGradientFrameBase; @@ -112,15 +127,8 @@ protected: { return GetEnumValue(aIndex, mContent); } - PRUint16 GetGradientUnits() - { - // This getter is called every time the others are called - maybe cache it? - return GetEnumValue(nsSVGGradientElement::GRADIENTUNITS); - } - PRUint16 GetSpreadMethod() - { - return GetEnumValue(nsSVGGradientElement::SPREADMETHOD); - } + PRUint16 GetGradientUnits(); + PRUint16 GetSpreadMethod(); // Gradient-type-specific lookups since the length values differ between // linear and radial gradients diff --git a/layout/svg/base/src/nsSVGImageFrame.cpp b/layout/svg/base/src/nsSVGImageFrame.cpp index b153b5f0559d..7cb6b37efd08 100644 --- a/layout/svg/base/src/nsSVGImageFrame.cpp +++ b/layout/svg/base/src/nsSVGImageFrame.cpp @@ -35,11 +35,14 @@ * ***** END LICENSE BLOCK ***** */ #include "nsSVGPathGeometryFrame.h" + +#include "nsRenderingContext.h" #include "imgIContainer.h" #include "nsStubImageDecoderObserver.h" #include "nsImageLoadingContent.h" #include "nsIDOMSVGImageElement.h" #include "nsLayoutUtils.h" +#include "nsSVGEffects.h" #include "nsSVGImageElement.h" #include "nsSVGUtils.h" #include "gfxContext.h" @@ -93,9 +96,9 @@ public: // nsISVGChildFrame interface: NS_IMETHOD PaintSVG(nsRenderingContext *aContext, const nsIntRect *aDirtyRect); NS_IMETHOD_(nsIFrame*) GetFrameForPoint(const nsPoint &aPoint); + virtual void UpdateBounds(); // nsSVGPathGeometryFrame methods: - NS_IMETHOD UpdateCoveredRegion(); virtual PRUint16 GetHitTestFlags(); // nsIFrame interface: @@ -218,14 +221,18 @@ nsSVGImageFrame::AttributeChanged(PRInt32 aNameSpaceID, nsIAtom* aAttribute, PRInt32 aModType) { - if (aNameSpaceID == kNameSpaceID_None && - (aAttribute == nsGkAtoms::x || - aAttribute == nsGkAtoms::y || - aAttribute == nsGkAtoms::width || - aAttribute == nsGkAtoms::height || - aAttribute == nsGkAtoms::preserveAspectRatio)) { - nsSVGUtils::UpdateGraphic(this); - return NS_OK; + if (aNameSpaceID == kNameSpaceID_None) { + if (aAttribute == nsGkAtoms::x || + aAttribute == nsGkAtoms::y || + aAttribute == nsGkAtoms::width || + aAttribute == nsGkAtoms::height) { + nsSVGUtils::InvalidateAndScheduleBoundsUpdate(this); + return NS_OK; + } + else if (aAttribute == nsGkAtoms::preserveAspectRatio) { + nsSVGUtils::InvalidateBounds(this); + return NS_OK; + } } if (aNameSpaceID == kNameSpaceID_XLink && aAttribute == nsGkAtoms::href) { @@ -479,10 +486,18 @@ nsSVGImageFrame::GetType() const // Lie about our fill/stroke so that covered region and hit detection work properly -NS_IMETHODIMP -nsSVGImageFrame::UpdateCoveredRegion() +void +nsSVGImageFrame::UpdateBounds() { - mRect.SetEmpty(); + NS_ASSERTION(nsSVGUtils::OuterSVGIsCallingUpdateBounds(this), + "This call is probaby a wasteful mistake"); + + NS_ABORT_IF_FALSE(!(GetStateBits() & NS_STATE_SVG_NONDISPLAY_CHILD), + "UpdateBounds mechanism not designed for this"); + + if (!nsSVGUtils::NeedsUpdatedBounds(this)) { + return; + } gfxContext context(gfxPlatform::GetPlatform()->ScreenReferenceSurface()); @@ -494,13 +509,23 @@ nsSVGImageFrame::UpdateCoveredRegion() if (!extent.IsEmpty()) { mRect = nsLayoutUtils::RoundGfxRectToAppRect(extent, PresContext()->AppUnitsPerCSSPixel()); + } else { + mRect.SetEmpty(); } // See bug 614732 comment 32. mCoveredRegion = nsSVGUtils::TransformFrameRectToOuterSVG( mRect, GetCanvasTM(), PresContext()); - return NS_OK; + mState &= ~(NS_FRAME_FIRST_REFLOW | NS_FRAME_IS_DIRTY | + NS_FRAME_HAS_DIRTY_CHILDREN); + + if (!(GetParent()->GetStateBits() & NS_FRAME_FIRST_REFLOW)) { + // We only invalidate if our outer- has already had its + // initial reflow (since if it hasn't, its entire area will be + // invalidated when it gets that initial reflow): + nsSVGUtils::InvalidateBounds(this, true); + } } PRUint16 @@ -560,7 +585,7 @@ NS_IMETHODIMP nsSVGImageListener::OnStopDecode(imgIRequest *aRequest, if (!mFrame) return NS_ERROR_FAILURE; - nsSVGUtils::UpdateGraphic(mFrame); + nsSVGUtils::InvalidateAndScheduleBoundsUpdate(mFrame); return NS_OK; } @@ -571,18 +596,23 @@ NS_IMETHODIMP nsSVGImageListener::FrameChanged(imgIRequest *aRequest, if (!mFrame) return NS_ERROR_FAILURE; - nsSVGUtils::UpdateGraphic(mFrame); + // No new dimensions, so we don't need to call + // nsSVGUtils::InvalidateAndScheduleBoundsUpdate. + nsSVGEffects::InvalidateRenderingObservers(mFrame); + nsSVGUtils::InvalidateBounds(mFrame); return NS_OK; } NS_IMETHODIMP nsSVGImageListener::OnStartContainer(imgIRequest *aRequest, imgIContainer *aContainer) { + // Called once the resource's dimensions have been obtained. + if (!mFrame) return NS_ERROR_FAILURE; mFrame->mImageContainer = aContainer; - nsSVGUtils::UpdateGraphic(mFrame); + nsSVGUtils::InvalidateAndScheduleBoundsUpdate(mFrame); return NS_OK; } diff --git a/layout/svg/base/src/nsSVGInnerSVGFrame.cpp b/layout/svg/base/src/nsSVGInnerSVGFrame.cpp index 5d3b8db4a260..1174acfedda5 100644 --- a/layout/svg/base/src/nsSVGInnerSVGFrame.cpp +++ b/layout/svg/base/src/nsSVGInnerSVGFrame.cpp @@ -37,6 +37,8 @@ * ***** END LICENSE BLOCK ***** */ #include "nsSVGInnerSVGFrame.h" + +#include "nsRenderingContext.h" #include "nsIFrame.h" #include "nsISVGChildFrame.h" #include "nsIDOMSVGAnimatedRect.h" @@ -232,24 +234,6 @@ nsSVGInnerSVGFrame::GetFrameForPoint(const nsPoint &aPoint) //---------------------------------------------------------------------- // nsISVGSVGFrame methods: -void -nsSVGInnerSVGFrame::SuspendRedraw() -{ - if (GetParent()->GetStateBits() & NS_STATE_SVG_REDRAW_SUSPENDED) - return; - - nsSVGUtils::NotifyRedrawSuspended(this); -} - -void -nsSVGInnerSVGFrame::UnsuspendRedraw() -{ - if (GetParent()->GetStateBits() & NS_STATE_SVG_REDRAW_SUSPENDED) - return; - - nsSVGUtils::NotifyRedrawUnsuspended(this); -} - void nsSVGInnerSVGFrame::NotifyViewportChange() { diff --git a/layout/svg/base/src/nsSVGInnerSVGFrame.h b/layout/svg/base/src/nsSVGInnerSVGFrame.h index 2b8990e696b7..101686ca6486 100644 --- a/layout/svg/base/src/nsSVGInnerSVGFrame.h +++ b/layout/svg/base/src/nsSVGInnerSVGFrame.h @@ -91,8 +91,6 @@ public: virtual gfxMatrix GetCanvasTM(); // nsISVGSVGFrame interface: - virtual void SuspendRedraw(); - virtual void UnsuspendRedraw(); virtual void NotifyViewportChange(); protected: diff --git a/layout/svg/base/src/nsSVGIntegrationUtils.cpp b/layout/svg/base/src/nsSVGIntegrationUtils.cpp index 5238807190d3..9a4a408ebe7c 100644 --- a/layout/svg/base/src/nsSVGIntegrationUtils.cpp +++ b/layout/svg/base/src/nsSVGIntegrationUtils.cpp @@ -37,6 +37,7 @@ #include "nsSVGIntegrationUtils.h" +#include "nsRenderingContext.h" #include "nsSVGUtils.h" #include "nsSVGEffects.h" #include "nsRegion.h" diff --git a/layout/svg/base/src/nsSVGIntegrationUtils.h b/layout/svg/base/src/nsSVGIntegrationUtils.h index 1539675a5075..9a4160bbd2f8 100644 --- a/layout/svg/base/src/nsSVGIntegrationUtils.h +++ b/layout/svg/base/src/nsSVGIntegrationUtils.h @@ -38,17 +38,19 @@ #ifndef NSSVGINTEGRATIONUTILS_H_ #define NSSVGINTEGRATIONUTILS_H_ -#include "nsPoint.h" -#include "nsRect.h" -#include "gfxRect.h" #include "gfxMatrix.h" #include "gfxPattern.h" +#include "gfxRect.h" +#include "nsRect.h" -class nsIFrame; -class nsDisplayListBuilder; class nsDisplayList; +class nsDisplayListBuilder; +class nsIFrame; class nsRenderingContext; +struct nsPoint; +struct nsSize; + /***** Integration of SVG effects with regular frame painting *****/ class nsSVGIntegrationUtils diff --git a/layout/svg/base/src/nsSVGMarkerFrame.cpp b/layout/svg/base/src/nsSVGMarkerFrame.cpp index 3cb173244893..5615d6cb65ca 100644 --- a/layout/svg/base/src/nsSVGMarkerFrame.cpp +++ b/layout/svg/base/src/nsSVGMarkerFrame.cpp @@ -34,10 +34,12 @@ * * ***** END LICENSE BLOCK ***** */ +#include "nsSVGMarkerFrame.h" + #include "nsIDOMSVGAnimatedRect.h" #include "nsIDOMSVGRect.h" #include "nsIDocument.h" -#include "nsSVGMarkerFrame.h" +#include "nsRenderingContext.h" #include "nsSVGPathGeometryFrame.h" #include "nsSVGEffects.h" #include "nsSVGMarkerElement.h" diff --git a/layout/svg/base/src/nsSVGMarkerFrame.h b/layout/svg/base/src/nsSVGMarkerFrame.h index e80270cf6b8b..ab39451bcf27 100644 --- a/layout/svg/base/src/nsSVGMarkerFrame.h +++ b/layout/svg/base/src/nsSVGMarkerFrame.h @@ -37,16 +37,23 @@ #ifndef __NS_SVGMARKERFRAME_H__ #define __NS_SVGMARKERFRAME_H__ +#include "gfxMatrix.h" +#include "gfxRect.h" +#include "nsFrame.h" +#include "nsLiteralString.h" +#include "nsQueryFrame.h" #include "nsSVGContainerFrame.h" #include "nsSVGUtils.h" -#include "gfxMatrix.h" -class gfxContext; +class nsIAtom; +class nsIContent; +class nsIFrame; +class nsIPresShell; class nsRenderingContext; +class nsStyleContext; class nsSVGPathGeometryFrame; class nsSVGSVGElement; -class nsIURI; -class nsIContent; + struct nsSVGMark; typedef nsSVGContainerFrame nsSVGMarkerFrameBase; diff --git a/layout/svg/base/src/nsSVGMaskFrame.cpp b/layout/svg/base/src/nsSVGMaskFrame.cpp index ba92b9f7eecf..1bee54889d49 100644 --- a/layout/svg/base/src/nsSVGMaskFrame.cpp +++ b/layout/svg/base/src/nsSVGMaskFrame.cpp @@ -34,8 +34,10 @@ * * ***** END LICENSE BLOCK ***** */ -#include "nsIDocument.h" #include "nsSVGMaskFrame.h" + +#include "nsIDocument.h" +#include "nsRenderingContext.h" #include "nsSVGContainerFrame.h" #include "nsSVGMaskElement.h" #include "nsSVGEffects.h" diff --git a/layout/svg/base/src/nsSVGMaskFrame.h b/layout/svg/base/src/nsSVGMaskFrame.h index 3ff468a84fdd..59f9da10c479 100644 --- a/layout/svg/base/src/nsSVGMaskFrame.h +++ b/layout/svg/base/src/nsSVGMaskFrame.h @@ -37,10 +37,10 @@ #ifndef __NS_SVGMASKFRAME_H__ #define __NS_SVGMASKFRAME_H__ -#include "nsSVGContainerFrame.h" -#include "nsSVGUtils.h" #include "gfxPattern.h" #include "gfxMatrix.h" +#include "nsSVGContainerFrame.h" +#include "nsSVGUtils.h" class gfxContext; class nsRenderingContext; diff --git a/layout/svg/base/src/nsSVGOuterSVGFrame.cpp b/layout/svg/base/src/nsSVGOuterSVGFrame.cpp index 9c77a8c02c6f..d7be9a831a1b 100644 --- a/layout/svg/base/src/nsSVGOuterSVGFrame.cpp +++ b/layout/svg/base/src/nsSVGOuterSVGFrame.cpp @@ -37,10 +37,11 @@ * ***** END LICENSE BLOCK ***** */ #include "nsSVGOuterSVGFrame.h" + #include "nsIDOMSVGSVGElement.h" +#include "nsRenderingContext.h" #include "nsSVGSVGElement.h" #include "nsSVGTextFrame.h" -#include "nsSVGForeignObjectFrame.h" #include "DOMSVGTests.h" #include "nsDisplayList.h" #include "nsStubMutationObserver.h" @@ -141,7 +142,6 @@ NS_IMPL_FRAMEARENA_HELPERS(nsSVGOuterSVGFrame) nsSVGOuterSVGFrame::nsSVGOuterSVGFrame(nsStyleContext* aContext) : nsSVGOuterSVGFrameBase(aContext) - , mRedrawSuspendCount(0) , mFullZoom(0) , mViewportInitialized(false) #ifdef XP_MACOSX @@ -166,6 +166,11 @@ nsSVGOuterSVGFrame::Init(nsIContent* aContent, // Check for conditional processing attributes here rather than in // nsCSSFrameConstructor::FindSVGData because we want to avoid // simply giving failing outer elements an nsSVGContainerFrame. + // We don't create other SVG frames if PassesConditionalProcessingTests + // returns false, but since we do create nsSVGOuterSVGFrame frames we + // prevent them from painting by [ab]use NS_STATE_SVG_NONDISPLAY_CHILD. The + // frame will be recreated via an nsChangeHint_ReconstructFrame restyle if + // the value returned by PassesConditionalProcessingTests changes. nsSVGSVGElement *svg = static_cast(aContent); if (!svg->PassesConditionalProcessingTests()) { AddStateBits(NS_STATE_SVG_NONDISPLAY_CHILD); @@ -184,8 +189,6 @@ nsSVGOuterSVGFrame::Init(nsIContent* aContent, doc->AddMutationObserverUnlessExists(&sSVGMutationObserver); } - SuspendRedraw(); // UnsuspendRedraw is in DidReflow - return rv; } @@ -414,14 +417,6 @@ nsSVGOuterSVGFrame::Reflow(nsPresContext* aPresContext, return NS_OK; } -static PLDHashOperator -ReflowForeignObject(nsVoidPtrHashKey *aEntry, void* aUserArg) -{ - static_cast - (const_cast(aEntry->GetKey()))->MaybeReflowFromOuterSVGFrame(); - return PL_DHASH_NEXT; -} - NS_IMETHODIMP nsSVGOuterSVGFrame::DidReflow(nsPresContext* aPresContext, const nsHTMLReflowState* aReflowState, @@ -432,30 +427,40 @@ nsSVGOuterSVGFrame::DidReflow(nsPresContext* aPresContext, nsresult rv = nsSVGOuterSVGFrameBase::DidReflow(aPresContext,aReflowState,aStatus); if (firstReflow) { - // call InitialUpdate() on all frames: + // Temporarily add back the NS_FRAME_FIRST_REFLOW bit to indicate + // to the children that we are still to receive the invalidation + // for our first reflow: + AddStateBits(NS_FRAME_FIRST_REFLOW); + } + +#ifdef DEBUG + mCallingUpdateBounds = true; +#endif + + if (!(mState & NS_STATE_SVG_NONDISPLAY_CHILD)) { nsIFrame* kid = mFrames.FirstChild(); while (kid) { nsISVGChildFrame* SVGFrame = do_QueryFrame(kid); - if (SVGFrame) { - SVGFrame->InitialUpdate(); + if (SVGFrame && !(kid->GetStateBits() & NS_STATE_SVG_NONDISPLAY_CHILD)) { + SVGFrame->UpdateBounds(); } kid = kid->GetNextSibling(); } - - UnsuspendRedraw(); // For the SuspendRedraw in InitSVG - } else { - // Now that all viewport establishing descendants have their correct size, - // tell our foreignObject descendants to reflow their children. - if (mForeignObjectHash.IsInitialized()) { -#ifdef DEBUG - PRUint32 count = -#endif - mForeignObjectHash.EnumerateEntries(ReflowForeignObject, nsnull); - NS_ASSERTION(count == mForeignObjectHash.Count(), - "We didn't reflow all our nsSVGForeignObjectFrames!"); - } } - + +#ifdef DEBUG + mCallingUpdateBounds = false; +#endif + + if (firstReflow) { + // And now remove it again: + RemoveStateBits(NS_FRAME_FIRST_REFLOW); + } + + // Make sure elements styled by :hover get updated if script/animation moves + // them under or out from under the pointer: + PresContext()->PresShell()->SynthesizeMouseMove(false); + return rv; } @@ -686,26 +691,6 @@ nsSVGOuterSVGFrame::GetType() const //---------------------------------------------------------------------- // nsISVGSVGFrame methods: -void -nsSVGOuterSVGFrame::SuspendRedraw() -{ - if (++mRedrawSuspendCount != 1) - return; - - nsSVGUtils::NotifyRedrawSuspended(this); -} - -void -nsSVGOuterSVGFrame::UnsuspendRedraw() -{ - NS_ASSERTION(mRedrawSuspendCount >=0, "unbalanced suspend count!"); - - if (--mRedrawSuspendCount > 0) - return; - - nsSVGUtils::NotifyRedrawUnsuspended(this); -} - void nsSVGOuterSVGFrame::NotifyViewportChange() { @@ -764,36 +749,6 @@ nsSVGOuterSVGFrame::GetCanvasTM() //---------------------------------------------------------------------- // Implementation helpers -void -nsSVGOuterSVGFrame::RegisterForeignObject(nsSVGForeignObjectFrame* aFrame) -{ - NS_ASSERTION(aFrame, "Who on earth is calling us?!"); - - if (!mForeignObjectHash.IsInitialized()) { - if (!mForeignObjectHash.Init()) { - NS_ERROR("Failed to initialize foreignObject hash."); - return; - } - } - - NS_ASSERTION(!mForeignObjectHash.GetEntry(aFrame), - "nsSVGForeignObjectFrame already registered!"); - - mForeignObjectHash.PutEntry(aFrame); - - NS_ASSERTION(mForeignObjectHash.GetEntry(aFrame), - "Failed to register nsSVGForeignObjectFrame!"); -} - -void -nsSVGOuterSVGFrame::UnregisterForeignObject(nsSVGForeignObjectFrame* aFrame) -{ - NS_ASSERTION(aFrame, "Who on earth is calling us?!"); - NS_ASSERTION(mForeignObjectHash.GetEntry(aFrame), - "nsSVGForeignObjectFrame not in registry!"); - return mForeignObjectHash.RemoveEntry(aFrame); -} - bool nsSVGOuterSVGFrame::IsRootOfReplacedElementSubDoc(nsIFrame **aEmbeddingFrame) { diff --git a/layout/svg/base/src/nsSVGOuterSVGFrame.h b/layout/svg/base/src/nsSVGOuterSVGFrame.h index fdf7bf6ff2ca..9b047a9f0aee 100644 --- a/layout/svg/base/src/nsSVGOuterSVGFrame.h +++ b/layout/svg/base/src/nsSVGOuterSVGFrame.h @@ -39,13 +39,9 @@ #ifndef __NS_SVGOUTERSVGFRAME_H__ #define __NS_SVGOUTERSVGFRAME_H__ -#include "nsSVGContainerFrame.h" -#include "nsISVGSVGFrame.h" -#include "nsIDOMSVGPoint.h" -#include "nsIDOMSVGNumber.h" #include "gfxMatrix.h" - -class nsSVGForeignObjectFrame; +#include "nsISVGSVGFrame.h" +#include "nsSVGContainerFrame.h" //////////////////////////////////////////////////////////////////////// // nsSVGOuterSVGFrame class @@ -64,13 +60,6 @@ public: NS_DECL_QUERYFRAME NS_DECL_FRAMEARENA_HELPERS -#ifdef DEBUG - ~nsSVGOuterSVGFrame() { - NS_ASSERTION(mForeignObjectHash.Count() == 0, - "foreignObject(s) still registered!"); - } -#endif - // nsIFrame: virtual nscoord GetMinWidth(nsRenderingContext *aRenderingContext); virtual nscoord GetPrefWidth(nsRenderingContext *aRenderingContext); @@ -125,21 +114,11 @@ public: PRInt32 aModType); // nsISVGSVGFrame interface: - virtual void SuspendRedraw(); - virtual void UnsuspendRedraw(); virtual void NotifyViewportChange(); // nsSVGContainerFrame methods: virtual gfxMatrix GetCanvasTM(); - /* Methods to allow descendant nsSVGForeignObjectFrame frames to register and - * unregister themselves with their nearest nsSVGOuterSVGFrame ancestor so - * they can be reflowed. The methods return true on success or false on - * failure. - */ - void RegisterForeignObject(nsSVGForeignObjectFrame* aFrame); - void UnregisterForeignObject(nsSVGForeignObjectFrame* aFrame); - #ifdef XP_MACOSX bool BitmapFallbackEnabled() const { return mEnableBitmapFallback; @@ -156,8 +135,18 @@ public: */ bool VerticalScrollbarNotNeeded() const; +#ifdef DEBUG + bool IsCallingUpdateBounds() const { + return mCallingUpdateBounds; + } +#endif + protected: +#ifdef DEBUG + bool mCallingUpdateBounds; +#endif + /* Returns true if our content is the document element and our document is * embedded in an HTML 'object', 'embed' or 'applet' element. Set * aEmbeddingFrame to obtain the nsIFrame for the embedding HTML element. @@ -169,14 +158,8 @@ protected: */ bool IsRootOfImage(); - // A hash-set containing our nsSVGForeignObjectFrame descendants. Note we use - // a hash-set to avoid the O(N^2) behavior we'd get tearing down an SVG frame - // subtree if we were to use a list (see bug 381285 comment 20). - nsTHashtable mForeignObjectHash; - nsAutoPtr mCanvasTM; - PRInt32 mRedrawSuspendCount; float mFullZoom; bool mViewportInitialized; diff --git a/layout/svg/base/src/nsSVGPaintServerFrame.h b/layout/svg/base/src/nsSVGPaintServerFrame.h index 976d2dff316b..232693cd47ad 100644 --- a/layout/svg/base/src/nsSVGPaintServerFrame.h +++ b/layout/svg/base/src/nsSVGPaintServerFrame.h @@ -37,12 +37,20 @@ #ifndef __NS_SVGPAINTSERVERFRAME_H__ #define __NS_SVGPAINTSERVERFRAME_H__ +#include "nsCOMPtr.h" +#include "nsFrame.h" +#include "nsIFrame.h" +#include "nsQueryFrame.h" #include "nsSVGContainerFrame.h" #include "nsSVGUtils.h" class gfxContext; +class gfxPattern; +class nsStyleContext; class nsSVGGeometryFrame; +struct gfxRect; + typedef nsSVGContainerFrame nsSVGPaintServerFrameBase; class nsSVGPaintServerFrame : public nsSVGPaintServerFrameBase diff --git a/layout/svg/base/src/nsSVGPathGeometryFrame.cpp b/layout/svg/base/src/nsSVGPathGeometryFrame.cpp index c389a9853649..0e1378ac428b 100644 --- a/layout/svg/base/src/nsSVGPathGeometryFrame.cpp +++ b/layout/svg/base/src/nsSVGPathGeometryFrame.cpp @@ -37,7 +37,9 @@ * ***** END LICENSE BLOCK ***** */ #include "nsSVGPathGeometryFrame.h" + #include "nsGkAtoms.h" +#include "nsRenderingContext.h" #include "nsSVGMarkerFrame.h" #include "nsSVGUtils.h" #include "nsSVGEffects.h" @@ -79,7 +81,7 @@ nsSVGPathGeometryFrame::AttributeChanged(PRInt32 aNameSpaceID, (static_cast (mContent)->AttributeDefinesGeometry(aAttribute) || aAttribute == nsGkAtoms::transform)) - nsSVGUtils::UpdateGraphic(this); + nsSVGUtils::InvalidateAndScheduleBoundsUpdate(this); return NS_OK; } @@ -95,7 +97,7 @@ nsSVGPathGeometryFrame::DidSetStyleContext(nsStyleContext* aOldStyleContext) // style_hints don't map very well onto svg. Here seems to be the // best place to deal with style changes: - nsSVGUtils::UpdateGraphic(this); + nsSVGUtils::InvalidateAndScheduleBoundsUpdate(this); } nsIAtom * @@ -209,9 +211,19 @@ nsSVGPathGeometryFrame::GetCoveredRegion() return mCoveredRegion; } -NS_IMETHODIMP -nsSVGPathGeometryFrame::UpdateCoveredRegion() +void +nsSVGPathGeometryFrame::UpdateBounds() { + NS_ASSERTION(nsSVGUtils::OuterSVGIsCallingUpdateBounds(this), + "This call is probaby a wasteful mistake"); + + NS_ABORT_IF_FALSE(!(GetStateBits() & NS_STATE_SVG_NONDISPLAY_CHILD), + "UpdateBounds mechanism not designed for this"); + + if (!nsSVGUtils::NeedsUpdatedBounds(this)) { + return; + } + gfxRect extent = GetBBoxContribution(gfxMatrix(), nsSVGUtils::eBBoxIncludeFill | nsSVGUtils::eBBoxIgnoreFillIfNone | nsSVGUtils::eBBoxIncludeStroke | nsSVGUtils::eBBoxIgnoreStrokeIfNone | @@ -223,25 +235,15 @@ nsSVGPathGeometryFrame::UpdateCoveredRegion() mCoveredRegion = nsSVGUtils::TransformFrameRectToOuterSVG( mRect, GetCanvasTM(), PresContext()); - return NS_OK; -} - -NS_IMETHODIMP -nsSVGPathGeometryFrame::InitialUpdate() -{ - NS_ASSERTION(GetStateBits() & NS_FRAME_FIRST_REFLOW, - "Yikes! We've been called already! Hopefully we weren't called " - "before our nsSVGOuterSVGFrame's initial Reflow()!!!"); - - nsSVGUtils::UpdateGraphic(this); - - NS_ASSERTION(!(mState & NS_FRAME_IN_REFLOW), - "We don't actually participate in reflow"); - - // Do unset the various reflow bits, though. mState &= ~(NS_FRAME_FIRST_REFLOW | NS_FRAME_IS_DIRTY | NS_FRAME_HAS_DIRTY_CHILDREN); - return NS_OK; + + if (!(GetParent()->GetStateBits() & NS_FRAME_FIRST_REFLOW)) { + // We only invalidate if our outer- has already had its + // initial reflow (since if it hasn't, its entire area will be + // invalidated when it gets that initial reflow): + nsSVGUtils::InvalidateBounds(this, true); + } } void @@ -255,25 +257,10 @@ nsSVGPathGeometryFrame::NotifySVGChanged(PRUint32 aFlags) "Invalidation logic may need adjusting"); if (!(aFlags & DO_NOT_NOTIFY_RENDERING_OBSERVERS)) { - nsSVGUtils::UpdateGraphic(this); + nsSVGUtils::InvalidateAndScheduleBoundsUpdate(this); } } -void -nsSVGPathGeometryFrame::NotifyRedrawSuspended() -{ - AddStateBits(NS_STATE_SVG_REDRAW_SUSPENDED); -} - -void -nsSVGPathGeometryFrame::NotifyRedrawUnsuspended() -{ - RemoveStateBits(NS_STATE_SVG_REDRAW_SUSPENDED); - - if (GetStateBits() & NS_STATE_SVG_DIRTY) - nsSVGUtils::UpdateGraphic(this); -} - gfxRect nsSVGPathGeometryFrame::GetBBoxContribution(const gfxMatrix &aToBBoxUserspace, PRUint32 aFlags) diff --git a/layout/svg/base/src/nsSVGPathGeometryFrame.h b/layout/svg/base/src/nsSVGPathGeometryFrame.h index 2c8bd08ce718..f325885d9029 100644 --- a/layout/svg/base/src/nsSVGPathGeometryFrame.h +++ b/layout/svg/base/src/nsSVGPathGeometryFrame.h @@ -39,16 +39,27 @@ #ifndef __NS_SVGPATHGEOMETRYFRAME_H__ #define __NS_SVGPATHGEOMETRYFRAME_H__ +#include "gfxMatrix.h" +#include "gfxRect.h" #include "nsFrame.h" #include "nsISVGChildFrame.h" -#include "nsSVGUtils.h" -#include "nsGkAtoms.h" +#include "nsLiteralString.h" +#include "nsQueryFrame.h" +#include "nsRect.h" #include "nsSVGGeometryFrame.h" +#include "nsSVGUtils.h" +class gfxContext; +class nsIAtom; +class nsIFrame; +class nsIPresShell; class nsRenderingContext; +class nsStyleContext; class nsSVGMarkerFrame; class nsSVGMarkerProperty; +struct nsPoint; + typedef nsSVGGeometryFrame nsSVGPathGeometryFrameBase; class nsSVGPathGeometryFrame : public nsSVGPathGeometryFrameBase, @@ -94,11 +105,8 @@ protected: const nsIntRect *aDirtyRect); NS_IMETHOD_(nsIFrame*) GetFrameForPoint(const nsPoint &aPoint); NS_IMETHOD_(nsRect) GetCoveredRegion(); - NS_IMETHOD UpdateCoveredRegion(); - NS_IMETHOD InitialUpdate(); + virtual void UpdateBounds(); virtual void NotifySVGChanged(PRUint32 aFlags); - virtual void NotifyRedrawSuspended(); - virtual void NotifyRedrawUnsuspended(); virtual gfxRect GetBBoxContribution(const gfxMatrix &aToBBoxUserspace, PRUint32 aFlags); NS_IMETHOD_(bool) IsDisplayContainer() { return false; } diff --git a/layout/svg/base/src/nsSVGPatternFrame.cpp b/layout/svg/base/src/nsSVGPatternFrame.cpp index b822451dccf3..7c77ff40beff 100644 --- a/layout/svg/base/src/nsSVGPatternFrame.cpp +++ b/layout/svg/base/src/nsSVGPatternFrame.cpp @@ -40,6 +40,7 @@ #include "nsGkAtoms.h" #include "nsIDOMSVGAnimatedRect.h" +#include "nsRenderingContext.h" #include "SVGAnimatedTransformList.h" #include "nsStyleContext.h" #include "nsINameSpaceManager.h" diff --git a/layout/svg/base/src/nsSVGPatternFrame.h b/layout/svg/base/src/nsSVGPatternFrame.h index efc4934a36fa..7570d8f23f17 100644 --- a/layout/svg/base/src/nsSVGPatternFrame.h +++ b/layout/svg/base/src/nsSVGPatternFrame.h @@ -39,16 +39,15 @@ #ifndef __NS_SVGPATTERNFRAME_H__ #define __NS_SVGPATTERNFRAME_H__ -#include "nsSVGPaintServerFrame.h" #include "gfxMatrix.h" -#include "nsIDOMSVGAnimTransformList.h" +#include "nsSVGPaintServerFrame.h" -class nsIFrame; -class nsSVGLength2; -class nsSVGElement; -class nsSVGViewBox; -class gfxContext; class gfxASurface; +class gfxContext; +class nsIFrame; +class nsSVGElement; +class nsSVGLength2; +class nsSVGViewBox; namespace mozilla { class SVGAnimatedPreserveAspectRatio; diff --git a/layout/svg/base/src/nsSVGSwitchFrame.cpp b/layout/svg/base/src/nsSVGSwitchFrame.cpp index b9611b021005..52449830a2dd 100644 --- a/layout/svg/base/src/nsSVGSwitchFrame.cpp +++ b/layout/svg/base/src/nsSVGSwitchFrame.cpp @@ -36,6 +36,7 @@ * * ***** END LICENSE BLOCK ***** */ +#include "nsSVGEffects.h" #include "nsSVGGFrame.h" #include "nsSVGSwitchElement.h" #include "nsSVGUtils.h" @@ -81,9 +82,6 @@ public: NS_IMETHOD PaintSVG(nsRenderingContext* aContext, const nsIntRect *aDirtyRect); NS_IMETHODIMP_(nsIFrame*) GetFrameForPoint(const nsPoint &aPoint); NS_IMETHODIMP_(nsRect) GetCoveredRegion(); - NS_IMETHOD UpdateCoveredRegion(); - NS_IMETHOD InitialUpdate(); - virtual void NotifyRedrawUnsuspended(); virtual gfxRect GetBBoxContribution(const gfxMatrix &aToBBoxUserspace, PRUint32 aFlags); @@ -166,40 +164,6 @@ nsSVGSwitchFrame::GetCoveredRegion() return rect; } -NS_IMETHODIMP -nsSVGSwitchFrame::UpdateCoveredRegion() -{ - static_cast(mContent)->UpdateActiveChild(); - - nsIFrame *kid = GetActiveChildFrame(); - if (kid) { - nsISVGChildFrame* child = do_QueryFrame(kid); - if (child) { - child->UpdateCoveredRegion(); - } - } - return NS_OK; -} - -NS_IMETHODIMP -nsSVGSwitchFrame::InitialUpdate() -{ - nsSVGUtils::UpdateGraphic(this); - - return nsSVGSwitchFrameBase::InitialUpdate(); -} - -void -nsSVGSwitchFrame::NotifyRedrawUnsuspended() -{ - RemoveStateBits(NS_STATE_SVG_REDRAW_SUSPENDED); - - if (GetStateBits() & NS_STATE_SVG_DIRTY) - nsSVGUtils::UpdateGraphic(this); - - nsSVGSwitchFrameBase::NotifyRedrawUnsuspended(); -} - gfxRect nsSVGSwitchFrame::GetBBoxContribution(const gfxMatrix &aToBBoxUserspace, PRUint32 aFlags) diff --git a/layout/svg/base/src/nsSVGTSpanFrame.h b/layout/svg/base/src/nsSVGTSpanFrame.h index 330e3134d1a0..b5d063e45a72 100644 --- a/layout/svg/base/src/nsSVGTSpanFrame.h +++ b/layout/svg/base/src/nsSVGTSpanFrame.h @@ -39,9 +39,20 @@ #ifndef NSSVGTSPANFRAME_H #define NSSVGTSPANFRAME_H -#include "nsSVGTextContainerFrame.h" -#include "nsISVGGlyphFragmentNode.h" #include "gfxMatrix.h" +#include "nsFrame.h" +#include "nsISVGGlyphFragmentNode.h" +#include "nsLiteralString.h" +#include "nsQueryFrame.h" +#include "nsSVGTextContainerFrame.h" + +class nsIAtom; +class nsIContent; +class nsIDOMSVGPoint; +class nsIFrame; +class nsIPresShell; +class nsStyleContext; +class nsSVGGlyphFrame; typedef nsSVGTextContainerFrame nsSVGTSpanFrameBase; diff --git a/layout/svg/base/src/nsSVGTextContainerFrame.h b/layout/svg/base/src/nsSVGTextContainerFrame.h index 7f5ebab33a60..53ad3cf22f6e 100644 --- a/layout/svg/base/src/nsSVGTextContainerFrame.h +++ b/layout/svg/base/src/nsSVGTextContainerFrame.h @@ -37,13 +37,20 @@ #ifndef NS_SVGTEXTCONTAINERFRAME_H #define NS_SVGTEXTCONTAINERFRAME_H +#include "nsFrame.h" +#include "nsIFrame.h" +#include "nsISVGChildFrame.h" +#include "nsQueryFrame.h" #include "nsSVGContainerFrame.h" +#include "nsTArray.h" +class nsFrameList; class nsIDOMSVGPoint; class nsIDOMSVGRect; class nsISVGGlyphFragmentNode; -class nsSVGTextFrame; +class nsStyleContext; class nsSVGGlyphFrame; +class nsSVGTextFrame; class nsSVGTextContainerFrame : public nsSVGDisplayContainerFrame { diff --git a/layout/svg/base/src/nsSVGTextFrame.cpp b/layout/svg/base/src/nsSVGTextFrame.cpp index 1c3e3c2dfca5..e0048d218b83 100644 --- a/layout/svg/base/src/nsSVGTextFrame.cpp +++ b/layout/svg/base/src/nsSVGTextFrame.cpp @@ -216,15 +216,6 @@ nsSVGTextFrame::NotifySVGChanged(PRUint32 aFlags) } } -void -nsSVGTextFrame::NotifyRedrawUnsuspended() -{ - RemoveStateBits(NS_STATE_SVG_REDRAW_SUSPENDED); - - UpdateGlyphPositioning(false); - nsSVGTextFrameBase::NotifyRedrawUnsuspended(); -} - NS_IMETHODIMP nsSVGTextFrame::PaintSVG(nsRenderingContext* aContext, const nsIntRect *aDirtyRect) @@ -242,23 +233,34 @@ nsSVGTextFrame::GetFrameForPoint(const nsPoint &aPoint) return nsSVGTextFrameBase::GetFrameForPoint(aPoint); } -NS_IMETHODIMP -nsSVGTextFrame::UpdateCoveredRegion() +void +nsSVGTextFrame::UpdateBounds() { - UpdateGlyphPositioning(true); - - return nsSVGTextFrameBase::UpdateCoveredRegion(); -} + NS_ASSERTION(nsSVGUtils::OuterSVGIsCallingUpdateBounds(this), + "This call is probaby a wasteful mistake"); + + NS_ABORT_IF_FALSE(!(GetStateBits() & NS_STATE_SVG_NONDISPLAY_CHILD), + "UpdateBounds mechanism not designed for this"); + + if (!nsSVGUtils::NeedsUpdatedBounds(this)) { + NS_ASSERTION(!mPositioningDirty, "How did this happen?"); + return; + } + + // UpdateGlyphPositioning may have been called under DOM calls and set + // mPositioningDirty to false. We may now have better positioning, though, so + // set it to true so that UpdateGlyphPositioning will do its work. + mPositioningDirty = true; -NS_IMETHODIMP -nsSVGTextFrame::InitialUpdate() -{ - nsresult rv = nsSVGTextFrameBase::InitialUpdate(); - UpdateGlyphPositioning(false); - return rv; -} + // With glyph positions updated, our descendants can invalidate their new + // areas correctly: + nsSVGTextFrameBase::UpdateBounds(); + + // XXXsvgreflow once we store bounds on containers, call + // nsSVGUtils::InvalidateBounds(this) if not first reflow. +} gfxRect nsSVGTextFrame::GetBBoxContribution(const gfxMatrix &aToBBoxUserspace, @@ -295,8 +297,9 @@ nsSVGTextFrame::GetCanvasTM() void nsSVGTextFrame::NotifyGlyphMetricsChange() { + nsSVGUtils::InvalidateAndScheduleBoundsUpdate(this); + mPositioningDirty = true; - UpdateGlyphPositioning(false); } void @@ -344,7 +347,7 @@ nsSVGTextFrame::SetWhitespaceHandling(nsSVGGlyphFrame *aFrame) void nsSVGTextFrame::UpdateGlyphPositioning(bool aForceGlobalTransform) { - if ((GetStateBits() & NS_STATE_SVG_REDRAW_SUSPENDED) || !mPositioningDirty) + if (!mPositioningDirty) return; mPositioningDirty = false; @@ -452,5 +455,4 @@ nsSVGTextFrame::UpdateGlyphPositioning(bool aForceGlobalTransform) } firstFrame = frame; } - nsSVGUtils::UpdateGraphic(this); } diff --git a/layout/svg/base/src/nsSVGTextFrame.h b/layout/svg/base/src/nsSVGTextFrame.h index a2e08da4eeba..a6d19a7a6de4 100644 --- a/layout/svg/base/src/nsSVGTextFrame.h +++ b/layout/svg/base/src/nsSVGTextFrame.h @@ -39,9 +39,9 @@ #ifndef NS_SVGTEXTFRAME_H #define NS_SVGTEXTFRAME_H -#include "nsSVGTextContainerFrame.h" -#include "gfxRect.h" #include "gfxMatrix.h" +#include "gfxRect.h" +#include "nsSVGTextContainerFrame.h" class nsRenderingContext; @@ -86,14 +86,12 @@ public: // nsISVGChildFrame interface: virtual void NotifySVGChanged(PRUint32 aFlags); - virtual void NotifyRedrawUnsuspended(); // Override these four to ensure that UpdateGlyphPositioning is called // to bring glyph positions up to date NS_IMETHOD PaintSVG(nsRenderingContext* aContext, const nsIntRect *aDirtyRect); NS_IMETHOD_(nsIFrame*) GetFrameForPoint(const nsPoint & aPoint); - NS_IMETHOD UpdateCoveredRegion(); - NS_IMETHOD InitialUpdate(); + virtual void UpdateBounds(); virtual gfxRect GetBBoxContribution(const gfxMatrix &aToBBoxUserspace, PRUint32 aFlags); diff --git a/layout/svg/base/src/nsSVGTextPathFrame.cpp b/layout/svg/base/src/nsSVGTextPathFrame.cpp index 4b9c42895c62..5be019b80742 100644 --- a/layout/svg/base/src/nsSVGTextPathFrame.cpp +++ b/layout/svg/base/src/nsSVGTextPathFrame.cpp @@ -35,6 +35,7 @@ * ***** END LICENSE BLOCK ***** */ #include "nsSVGTextPathFrame.h" + #include "nsIDOMSVGTextPathElement.h" #include "nsSVGLength2.h" #include "nsIDOMSVGURIReference.h" @@ -42,6 +43,7 @@ #include "nsContentUtils.h" #include "nsSVGPathElement.h" #include "nsSVGTextPathElement.h" +#include "SVGLengthList.h" using namespace mozilla; diff --git a/layout/svg/base/src/nsSVGTextPathFrame.h b/layout/svg/base/src/nsSVGTextPathFrame.h index 94ce2ae51e7a..35e6c42c2429 100644 --- a/layout/svg/base/src/nsSVGTextPathFrame.h +++ b/layout/svg/base/src/nsSVGTextPathFrame.h @@ -37,8 +37,20 @@ #ifndef NSSVGTEXTPATHFRAME_H #define NSSVGTEXTPATHFRAME_H +#include "gfxTypes.h" +#include "nsCOMPtr.h" +#include "nsFrame.h" +#include "nsISVGChildFrame.h" +#include "nsLiteralString.h" +#include "nsQueryFrame.h" #include "nsSVGTSpanFrame.h" -#include "SVGLengthList.h" + +class gfxFlattenedPath; +class nsIAtom; +class nsIContent; +class nsIFrame; +class nsIPresShell; +class nsStyleContext; namespace mozilla { class SVGNumberList; @@ -48,6 +60,8 @@ typedef nsSVGTSpanFrame nsSVGTextPathFrameBase; class nsSVGTextPathFrame : public nsSVGTextPathFrameBase { + typedef mozilla::SVGNumberList SVGNumberList; + friend nsIFrame* NS_NewSVGTextPathFrame(nsIPresShell* aPresShell, nsStyleContext* aContext); protected: diff --git a/layout/svg/base/src/nsSVGUseFrame.cpp b/layout/svg/base/src/nsSVGUseFrame.cpp index 6554632c2dd6..2d22e86e4fa1 100644 --- a/layout/svg/base/src/nsSVGUseFrame.cpp +++ b/layout/svg/base/src/nsSVGUseFrame.cpp @@ -163,7 +163,7 @@ nsSVGUseFrame::AttributeChanged(PRInt32 aNameSpaceID, static_cast(mContent)->HasValidDimensions()) { mHasValidDimensions = !mHasValidDimensions; - nsSVGUtils::UpdateGraphic(this); + nsSVGUtils::InvalidateAndScheduleBoundsUpdate(this); } } } else if (aNameSpaceID == kNameSpaceID_XLink && diff --git a/layout/svg/base/src/nsSVGUtils.cpp b/layout/svg/base/src/nsSVGUtils.cpp index 9603735e899c..fe5ffffbcd0d 100644 --- a/layout/svg/base/src/nsSVGUtils.cpp +++ b/layout/svg/base/src/nsSVGUtils.cpp @@ -36,9 +36,11 @@ // include nsSVGUtils.h first to ensure definition of M_SQRT1_2 is picked up #include "nsSVGUtils.h" + #include "nsIDOMDocument.h" #include "nsIDOMSVGElement.h" #include "nsIDOMSVGSVGElement.h" +#include "nsRenderingContext.h" #include "nsStyleCoord.h" #include "nsPresContext.h" #include "nsSVGSVGElement.h" @@ -651,18 +653,53 @@ nsSVGUtils::FindFilterInvalidation(nsIFrame *aFrame, const nsRect& aRect) return r; } -void -nsSVGUtils::InvalidateCoveredRegion(nsIFrame *aFrame) +#ifdef DEBUG +bool +nsSVGUtils::OuterSVGIsCallingUpdateBounds(nsIFrame *aFrame) { - if (aFrame->GetStateBits() & NS_STATE_SVG_NONDISPLAY_CHILD) - return; + return nsSVGUtils::GetOuterSVGFrame(aFrame)->IsCallingUpdateBounds(); +} +#endif - if (aFrame->GetStateBits() & NS_STATE_SVG_REDRAW_SUSPENDED) { - aFrame->AddStateBits(NS_STATE_SVG_DIRTY); +void +nsSVGUtils::InvalidateBounds(nsIFrame *aFrame, bool aDuringUpdate) +{ + NS_ABORT_IF_FALSE(aFrame->IsFrameOfType(nsIFrame::eSVG), + "Passed bad frame!"); + + NS_ASSERTION(aDuringUpdate == OuterSVGIsCallingUpdateBounds(aFrame), + "aDuringUpdate lies!"); + + // Rendering observers must be notified about changes to the frames that they + // are observing _before_ UpdateBounds is called on the SVG frame tree, so we + // only need to notify observers if we're not under an UpdateBounds call. + // In fact, it would actually be wrong to notify observers while under + // UpdateBounds because the observers will try to mark themselves as dirty + // and, since UpdateBounds would be in the process of _removeing_ dirty bits + // from frames, that would mess things up. + if (!aDuringUpdate) { + NS_ASSERTION(!OuterSVGIsCallingUpdateBounds(aFrame), + "Must not InvalidateRenderingObservers() under " + "nsISVGChildFrame::UpdateBounds!"); + + nsSVGEffects::InvalidateRenderingObservers(aFrame); + } + + // Must come after InvalidateRenderingObservers + if (aFrame->GetStateBits() & NS_STATE_SVG_NONDISPLAY_CHILD) { return; } - aFrame->RemoveStateBits(NS_STATE_SVG_DIRTY); + // XXXjwatt: can this come before InvalidateRenderingObservers? + if (aFrame->GetStateBits() & + (NS_FRAME_IS_DIRTY | NS_FRAME_FIRST_REFLOW)) { + // Nothing to do if we're already dirty, or if the outer- + // hasn't yet had its initial reflow. + return; + } + + // XXXsvgreflow we want to reduce the bounds when passing through inner- + // and , etc. nsSVGOuterSVGFrame* outerSVGFrame = GetOuterSVGFrame(aFrame); NS_ASSERTION(outerSVGFrame, "no outer svg frame"); @@ -671,55 +708,130 @@ nsSVGUtils::InvalidateCoveredRegion(nsIFrame *aFrame) if (!svgFrame) return; - // Make sure elements styled by :hover get updated if script/animation moves - // them under or out from under the pointer: - aFrame->PresContext()->PresShell()->SynthesizeMouseMove(false); - + // Note that filters can paint even if the element being filtered has empty + // bounds, so we don't return early for that. Specifically, filters can be + // given an explicit size that doesn't depend on the bbox of the element + // being filtered, and then feFlood can be used to fill that area with paint. nsRect rect = FindFilterInvalidation(aFrame, svgFrame->GetCoveredRegion()); outerSVGFrame->Invalidate(rect); } } -void -nsSVGUtils::UpdateGraphic(nsIFrame *aFrame) +static void +MarkDirtyBitsOnDescendants(nsIFrame *aFrame) { - nsSVGEffects::InvalidateRenderingObservers(aFrame); + NS_ABORT_IF_FALSE(aFrame->IsFrameOfType(nsIFrame::eSVG), + "Passed bad frame!"); - if (aFrame->GetStateBits() & NS_STATE_SVG_NONDISPLAY_CHILD) - return; + nsIFrame* kid = aFrame->GetFirstPrincipalChild(); + while (kid) { + nsISVGChildFrame* svgkid = do_QueryFrame(kid); + if (svgkid && + !(kid->GetStateBits() & + (NS_STATE_SVG_NONDISPLAY_CHILD | NS_FRAME_IS_DIRTY))) { + MarkDirtyBitsOnDescendants(kid); + kid->AddStateBits(NS_FRAME_IS_DIRTY); + } + kid = kid->GetNextSibling(); + } +} - if (aFrame->GetStateBits() & NS_STATE_SVG_REDRAW_SUSPENDED) { - aFrame->AddStateBits(NS_STATE_SVG_DIRTY); +void +nsSVGUtils::ScheduleBoundsUpdate(nsIFrame *aFrame) +{ + NS_ABORT_IF_FALSE(aFrame->IsFrameOfType(nsIFrame::eSVG), + "Passed bad frame!"); + + // If this is triggered, the callers should be fixed to call us before + // UpdateBounds is called. If we try to mark dirty bits on frames while we're + // in the process of removing them, things will get messed up. + NS_ASSERTION(!OuterSVGIsCallingUpdateBounds(aFrame), + "Do not call under nsISVGChildFrame::UpdateBounds!"); + + // We don't call nsSVGEffects::InvalidateRenderingObservers here because + // we should only be called under InvalidateAndScheduleBoundsUpdate (which + // calls InvalidateBounds) or nsSVGDisplayContainerFrame::InsertFrames + // (at which point the frame has no observers). + + if (aFrame->GetStateBits() & NS_STATE_SVG_NONDISPLAY_CHILD) { return; } - aFrame->RemoveStateBits(NS_STATE_SVG_DIRTY); - - nsISVGChildFrame *svgFrame = do_QueryFrame(aFrame); - if (!svgFrame) - return; - - nsSVGOuterSVGFrame *outerSVGFrame = GetOuterSVGFrame(aFrame); - if (!outerSVGFrame) { - NS_ERROR("null outerSVGFrame"); + if (aFrame->GetStateBits() & + (NS_FRAME_IS_DIRTY | NS_FRAME_FIRST_REFLOW)) { + // Nothing to do if we're already dirty, or if the outer- + // hasn't yet had its initial reflow. return; } - // Make sure elements styled by :hover get updated if script/animation moves - // them under or out from under the pointer: - aFrame->PresContext()->PresShell()->SynthesizeMouseMove(false); + // XXXsvgreflow once we store bounds on containers, we will not need to + // mark our descendants dirty. + MarkDirtyBitsOnDescendants(aFrame); - nsRect oldRegion = svgFrame->GetCoveredRegion(); - outerSVGFrame->Invalidate(FindFilterInvalidation(aFrame, oldRegion)); - svgFrame->UpdateCoveredRegion(); - nsRect newRegion = svgFrame->GetCoveredRegion(); - if (oldRegion.IsEqualInterior(newRegion)) - return; + nsSVGOuterSVGFrame *outerSVGFrame = nsnull; - outerSVGFrame->Invalidate(FindFilterInvalidation(aFrame, newRegion)); - if (!(aFrame->GetStateBits() & NS_STATE_IS_OUTER_SVG)) { - NotifyAncestorsOfFilterRegionChange(aFrame); + // We must not add dirty bits to the nsSVGOuterSVGFrame or else + // PresShell::FrameNeedsReflow won't work when we pass it in below. + if (aFrame->GetStateBits() & NS_STATE_IS_OUTER_SVG) { + outerSVGFrame = static_cast(aFrame); + } else { + aFrame->AddStateBits(NS_FRAME_IS_DIRTY); + + nsIFrame *f = aFrame->GetParent(); + while (f && !(f->GetStateBits() & NS_STATE_IS_OUTER_SVG)) { + if (f->GetStateBits() & + (NS_FRAME_IS_DIRTY | NS_FRAME_HAS_DIRTY_CHILDREN)) { + return; + } + f->AddStateBits(NS_FRAME_HAS_DIRTY_CHILDREN); + f = f->GetParent(); + NS_ABORT_IF_FALSE(f->IsFrameOfType(nsIFrame::eSVG), + "NS_STATE_IS_OUTER_SVG check above not valid!"); + } + + outerSVGFrame = static_cast(f); + + NS_ABORT_IF_FALSE(outerSVGFrame && + outerSVGFrame->GetType() == nsGkAtoms::svgOuterSVGFrame, + "Did not find nsSVGOuterSVGFrame!"); } + + if (outerSVGFrame->GetStateBits() & NS_FRAME_IN_REFLOW) { + // We're currently under an nsSVGOuterSVGFrame::Reflow call so there is no + // need to call PresShell::FrameNeedsReflow, since we have an + // nsSVGOuterSVGFrame::DidReflow call pending. + return; + } + + nsFrameState dirtyBit = + (outerSVGFrame == aFrame ? NS_FRAME_IS_DIRTY : NS_FRAME_HAS_DIRTY_CHILDREN); + + aFrame->PresContext()->PresShell()->FrameNeedsReflow( + outerSVGFrame, nsIPresShell::eResize, dirtyBit); +} + +void +nsSVGUtils::InvalidateAndScheduleBoundsUpdate(nsIFrame *aFrame) +{ + // If this is triggered, the callers should be fixed to call us much + // earlier. If we try to mark dirty bits on frames while we're in the + // process of removing them, things will get messed up. + NS_ASSERTION(!OuterSVGIsCallingUpdateBounds(aFrame), + "Must not call under nsISVGChildFrame::UpdateBounds!"); + + InvalidateBounds(aFrame, false); + ScheduleBoundsUpdate(aFrame); +} + +bool +nsSVGUtils::NeedsUpdatedBounds(nsIFrame *aFrame) +{ + NS_ABORT_IF_FALSE(aFrame->IsFrameOfType(nsIFrame::eSVG), + "SVG uses bits differently!"); + + // The flags we test here may change, hence why we have this separate + // function. + return NS_SUBTREE_DIRTY(aFrame); } void @@ -973,38 +1085,6 @@ nsSVGUtils::NotifyChildrenOfSVGChange(nsIFrame *aFrame, PRUint32 aFlags) } } -void -nsSVGUtils::NotifyRedrawSuspended(nsIFrame *aFrame) -{ - aFrame->AddStateBits(NS_STATE_SVG_REDRAW_SUSPENDED); - - nsIFrame *kid = aFrame->GetFirstPrincipalChild(); - - while (kid) { - nsISVGChildFrame* SVGFrame = do_QueryFrame(kid); - if (SVGFrame) { - SVGFrame->NotifyRedrawSuspended(); - } - kid = kid->GetNextSibling(); - } -} - -void -nsSVGUtils::NotifyRedrawUnsuspended(nsIFrame *aFrame) -{ - aFrame->RemoveStateBits(NS_STATE_SVG_REDRAW_SUSPENDED); - - nsIFrame *kid = aFrame->GetFirstPrincipalChild(); - - while (kid) { - nsISVGChildFrame* SVGFrame = do_QueryFrame(kid); - if (SVGFrame) { - SVGFrame->NotifyRedrawUnsuspended(); - } - kid = kid->GetNextSibling(); - } -} - // ************************************************************ class SVGPaintCallback : public nsSVGFilterPaintCallback diff --git a/layout/svg/base/src/nsSVGUtils.h b/layout/svg/base/src/nsSVGUtils.h index ada73571f51e..216492b95a07 100644 --- a/layout/svg/base/src/nsSVGUtils.h +++ b/layout/svg/base/src/nsSVGUtils.h @@ -41,43 +41,42 @@ #define _USE_MATH_DEFINES #include -#include "nscore.h" -#include "nsCOMPtr.h" -#include "nsRect.h" -#include "gfxContext.h" -#include "nsRenderingContext.h" -#include "gfxRect.h" #include "gfxMatrix.h" -#include "nsStyleStruct.h" +#include "gfxPoint.h" +#include "gfxRect.h" +#include "nsAlgorithm.h" +#include "nsColor.h" +#include "nsCOMPtr.h" +#include "nsID.h" +#include "nsISupportsBase.h" +#include "nsMathUtils.h" +#include "nsPoint.h" +#include "nsRect.h" -class nsIDocument; -class nsPresContext; +class gfxASurface; +class gfxContext; +class gfxImageSurface; +class gfxPattern; +class nsFrameList; class nsIContent; +class nsIDocument; +class nsIDOMSVGElement; +class nsIFrame; +class nsPresContext; +class nsRenderingContext; class nsStyleContext; class nsStyleCoord; -class nsFrameList; -class nsIFrame; -struct nsStyleSVGPaint; -class nsIDOMSVGElement; -class nsIDOMSVGLength; -class nsIURI; -class nsSVGOuterSVGFrame; -class nsIAtom; -class nsSVGLength2; -class nsSVGElement; -class nsSVGSVGElement; -class nsAttrValue; -class gfxContext; -class gfxASurface; -class gfxPattern; -class gfxImageSurface; -struct gfxSize; -struct nsStyleFont; -class nsSVGEnum; -class nsISVGChildFrame; -class nsSVGGeometryFrame; -class nsSVGPathGeometryFrame; class nsSVGDisplayContainerFrame; +class nsSVGElement; +class nsSVGEnum; +class nsSVGGeometryFrame; +class nsSVGLength2; +class nsSVGOuterSVGFrame; +class nsSVGPathGeometryFrame; +class nsSVGSVGElement; + +struct nsStyleSVG; +struct nsStyleSVGPaint; namespace mozilla { class SVGAnimatedPreserveAspectRatio; @@ -94,17 +93,12 @@ class Element; // SVG Frame state bits #define NS_STATE_IS_OUTER_SVG NS_FRAME_STATE_BIT(20) -#define NS_STATE_SVG_DIRTY NS_FRAME_STATE_BIT(21) - /* are we the child of a non-display container? */ #define NS_STATE_SVG_NONDISPLAY_CHILD NS_FRAME_STATE_BIT(22) // If this bit is set, we are a element or descendant. #define NS_STATE_SVG_CLIPPATH_CHILD NS_FRAME_STATE_BIT(23) -// If this bit is set, redraw is suspended. -#define NS_STATE_SVG_REDRAW_SUSPENDED NS_FRAME_STATE_BIT(24) - /** * Byte offsets of channels in a native packed gfxColor or cairo image surface. */ @@ -296,15 +290,56 @@ public: static nsRect FindFilterInvalidation(nsIFrame *aFrame, const nsRect& aRect); /** - * Invalidates the area covered by the frame + * Invalidates the area that is painted by the frame without updating its + * bounds. + * + * This is similar to InvalidateOverflowRect(). It will go away when we + * support display list based invalidation of SVG. */ - static void InvalidateCoveredRegion(nsIFrame *aFrame); + static void InvalidateBounds(nsIFrame *aFrame, bool aDuringUpdate = false); - /* - * Update the area covered by the frame allowing for the frame to - * have moved. + /** + * Schedules an update of the frame's bounds (which will in turn invalidate + * the new area that the frame should paint to). + * + * This does nothing when passed an NS_STATE_SVG_NONDISPLAY_CHILD frame. + * In future we may want to allow UpdateBounds to be called on such frames, + * but that would be better implemented as a ForceUpdateBounds function to + * be called synchronously while painting them without marking or paying + * attention to dirty bits like this function. + * + * This is very similar to PresShell::FrameNeedsReflow. The main reason that + * we have this function instead of using FrameNeedsReflow is because we need + * to be able to call it under nsSVGOuterSVGFrame::NotifyViewportChange when + * that function is called by nsSVGOuterSVGFrame::Reflow. FrameNeedsReflow + * is not suitable for calling during reflow though, and it asserts as much. + * The reason that we want to be callable under NotifyViewportChange is + * because we want to synchronously notify and dirty the nsSVGOuterSVGFrame's + * children so that when nsSVGOuterSVGFrame::DidReflow is called its children + * will be updated for the new size as appropriate. Otherwise we'd have to + * post an event to the event loop to mark dirty flags and request an update. + * + * Another reason that we don't currently want to call + * PresShell::FrameNeedsReflow is because passing eRestyle to it to get it to + * mark descendants dirty would cause it to descend through + * nsSVGForeignObjectFrame frames to mark their children dirty, but we want to + * handle nsSVGForeignObjectFrame specially. It would also do unnecessary work + * descending into NS_STATE_SVG_NONDISPLAY_CHILD frames. */ - static void UpdateGraphic(nsIFrame *aFrame); + static void ScheduleBoundsUpdate(nsIFrame *aFrame); + + /** + * Invalidates the area that the frame last painted to, then schedules an + * update of the frame's bounds (which will in turn invalidate the new area + * that the frame should paint to). + */ + static void InvalidateAndScheduleBoundsUpdate(nsIFrame *aFrame); + + /** + * Returns true if the frame or any of its children need UpdateBounds + * to be called on them. + */ + static bool NeedsUpdatedBounds(nsIFrame *aFrame); /* * Update the filter invalidation region for ancestor frames, if relevant. @@ -399,19 +434,6 @@ public: static void NotifyChildrenOfSVGChange(nsIFrame *aFrame, PRUint32 aFlags); - /* - * Tells child frames that redraw is suspended - */ - static void - NotifyRedrawSuspended(nsIFrame *aFrame); - - /* - * Tells child frames that redraw is no longer suspended - * @return true if any of the child frames are dirty - */ - static void - NotifyRedrawUnsuspended(nsIFrame *aFrame); - /* * Get frame's covered region by walking the children and doing union. */ @@ -541,6 +563,8 @@ public: #ifdef DEBUG static void WritePPM(const char *fname, gfxImageSurface *aSurface); + + static bool OuterSVGIsCallingUpdateBounds(nsIFrame *aFrame); #endif /** diff --git a/memory/jemalloc/jemalloc.c b/memory/jemalloc/jemalloc.c index be7f9a3e804f..1bfd00e0019d 100644 --- a/memory/jemalloc/jemalloc.c +++ b/memory/jemalloc/jemalloc.c @@ -425,7 +425,7 @@ void *_mmap(void *addr, size_t length, int prot, int flags, #endif #ifdef MOZ_MEMORY_DARWIN -static const bool __isthreaded = true; +static const bool isthreaded = true; #endif #if defined(MOZ_MEMORY_SOLARIS) && defined(MAP_ALIGN) && !defined(JEMALLOC_NEVER_USES_MAP_ALIGN) @@ -461,7 +461,7 @@ static const bool __isthreaded = true; #endif #define PIC #ifndef MOZ_MEMORY_DARWIN -static const bool __isthreaded = true; +static const bool isthreaded = true; #else # define NO_TLS #endif @@ -1566,7 +1566,7 @@ static bool malloc_mutex_init(malloc_mutex_t *mutex) { #if defined(MOZ_MEMORY_WINDOWS) - if (__isthreaded) + if (isthreaded) if (! __crtInitCritSecAndSpinCount(mutex, _CRT_SPINCOUNT)) return (true); #elif defined(MOZ_MEMORY_DARWIN) @@ -1603,7 +1603,7 @@ malloc_mutex_lock(malloc_mutex_t *mutex) #elif defined(MOZ_MEMORY) pthread_mutex_lock(mutex); #else - if (__isthreaded) + if (isthreaded) _SPINLOCK(&mutex->lock); #endif } @@ -1619,7 +1619,7 @@ malloc_mutex_unlock(malloc_mutex_t *mutex) #elif defined(MOZ_MEMORY) pthread_mutex_unlock(mutex); #else - if (__isthreaded) + if (isthreaded) _SPINUNLOCK(&mutex->lock); #endif } @@ -1628,7 +1628,7 @@ static bool malloc_spin_init(malloc_spinlock_t *lock) { #if defined(MOZ_MEMORY_WINDOWS) - if (__isthreaded) + if (isthreaded) if (! __crtInitCritSecAndSpinCount(lock, _CRT_SPINCOUNT)) return (true); #elif defined(MOZ_MEMORY_DARWIN) @@ -1663,7 +1663,7 @@ malloc_spin_lock(malloc_spinlock_t *lock) #elif defined(MOZ_MEMORY) pthread_mutex_lock(lock); #else - if (__isthreaded) + if (isthreaded) _SPINLOCK(&lock->lock); #endif } @@ -1678,7 +1678,7 @@ malloc_spin_unlock(malloc_spinlock_t *lock) #elif defined(MOZ_MEMORY) pthread_mutex_unlock(lock); #else - if (__isthreaded) + if (isthreaded) _SPINUNLOCK(&lock->lock); #endif } @@ -1733,7 +1733,7 @@ malloc_spin_lock(pthread_mutex_t *lock) { unsigned ret = 0; - if (__isthreaded) { + if (isthreaded) { if (_pthread_mutex_trylock(lock) != 0) { unsigned i; volatile unsigned j; @@ -1766,7 +1766,7 @@ static inline void malloc_spin_unlock(pthread_mutex_t *lock) { - if (__isthreaded) + if (isthreaded) _pthread_mutex_unlock(lock); } #endif @@ -2963,7 +2963,7 @@ choose_arena(void) * introduces a bootstrapping issue. */ #ifndef NO_TLS - if (__isthreaded == false) { + if (isthreaded == false) { /* Avoid the overhead of TLS for single-threaded operation. */ return (arenas[0]); } @@ -2979,7 +2979,7 @@ choose_arena(void) assert(ret != NULL); } #else - if (__isthreaded && narenas > 1) { + if (isthreaded && narenas > 1) { unsigned long ind; /* @@ -3036,7 +3036,7 @@ choose_arena_hard(void) { arena_t *ret; - assert(__isthreaded); + assert(isthreaded); #ifdef MALLOC_BALANCE /* Seed the PRNG used for arena load balancing. */ diff --git a/mobile/android/base/AwesomeBar.java b/mobile/android/base/AwesomeBar.java index ff77d61c54d2..d35fd8716398 100644 --- a/mobile/android/base/AwesomeBar.java +++ b/mobile/android/base/AwesomeBar.java @@ -497,7 +497,8 @@ public class AwesomeBar extends Activity implements GeckoEventListener { Cursor cursor = (Cursor) selectedItem; // Don't show the context menu for folders - if (!(list == findViewById(R.id.bookmarks_list) && cursor.getInt(cursor.getColumnIndexOrThrow(Bookmarks.IS_FOLDER)) == 1)) { + if (!(list == findViewById(R.id.bookmarks_list) && + cursor.getInt(cursor.getColumnIndexOrThrow(Bookmarks.TYPE)) == Bookmarks.TYPE_FOLDER)) { String keyword = null; int keywordCol = cursor.getColumnIndex(URLColumns.KEYWORD); if (keywordCol != -1) diff --git a/mobile/android/base/AwesomeBarTabs.java b/mobile/android/base/AwesomeBarTabs.java index ae3546ddb89c..1355d0049aa3 100644 --- a/mobile/android/base/AwesomeBarTabs.java +++ b/mobile/android/base/AwesomeBarTabs.java @@ -253,7 +253,7 @@ public class AwesomeBarTabs extends TabHost { Cursor c = getCursor(); if (c.moveToPosition(position) && - c.getInt(c.getColumnIndexOrThrow(Bookmarks.IS_FOLDER)) == 1) + c.getInt(c.getColumnIndexOrThrow(Bookmarks.TYPE)) == Bookmarks.TYPE_FOLDER) return VIEW_TYPE_FOLDER; // Default to retuning normal item type @@ -872,8 +872,8 @@ public class AwesomeBarTabs extends TabHost { // The header view takes up a spot in the list cursor.moveToPosition(position - 1); - int isFolder = cursor.getInt(cursor.getColumnIndexOrThrow(Bookmarks.IS_FOLDER)); - if (isFolder == 1) { + int type = cursor.getInt(cursor.getColumnIndexOrThrow(Bookmarks.TYPE)); + if (type == Bookmarks.TYPE_FOLDER) { // If we're clicking on a folder, update mBookmarksAdapter to move to that folder int folderId = cursor.getInt(cursor.getColumnIndexOrThrow(Bookmarks._ID)); String folderTitle = mBookmarksAdapter.getFolderTitle(position - 1); diff --git a/mobile/android/base/GeckoApp.java b/mobile/android/base/GeckoApp.java index 4c1d1b0abd5f..d55ec290bbc3 100644 --- a/mobile/android/base/GeckoApp.java +++ b/mobile/android/base/GeckoApp.java @@ -2049,6 +2049,7 @@ abstract public class GeckoApp unregisterReceiver(mConnectivityReceiver); GeckoNetworkManager.getInstance().stop(); + GeckoScreenOrientationListener.getInstance().stop(); } @Override @@ -2080,8 +2081,13 @@ abstract public class GeckoApp refreshActionBar(); } - registerReceiver(mConnectivityReceiver, mConnectivityFilter); - GeckoNetworkManager.getInstance().start(); + mMainHandler.post(new Runnable() { + public void run() { + registerReceiver(mConnectivityReceiver, mConnectivityFilter); + GeckoNetworkManager.getInstance().start(); + GeckoScreenOrientationListener.getInstance().start(); + } + }); if (mOwnActivityDepth > 0) mOwnActivityDepth--; @@ -2168,6 +2174,7 @@ abstract public class GeckoApp } GeckoNetworkManager.getInstance().stop(); + GeckoScreenOrientationListener.getInstance().stop(); super.onDestroy(); diff --git a/mobile/android/base/GeckoAppShell.java b/mobile/android/base/GeckoAppShell.java index ebd509a8dd7e..57b70382bdec 100644 --- a/mobile/android/base/GeckoAppShell.java +++ b/mobile/android/base/GeckoAppShell.java @@ -1994,4 +1994,16 @@ public class GeckoAppShell public static byte[] decodeBase64(String s, int flags) { return decodeBase64(s.getBytes(), flags); } + + public static short getScreenOrientation() { + return GeckoScreenOrientationListener.getInstance().getScreenOrientation(); + } + + public static void enableScreenOrientationNotifications() { + GeckoScreenOrientationListener.getInstance().enableNotifications(); + } + + public static void disableScreenOrientationNotifications() { + GeckoScreenOrientationListener.getInstance().disableNotifications(); + } } diff --git a/mobile/android/base/GeckoEvent.java b/mobile/android/base/GeckoEvent.java index 532ef04ace49..57f79997d0bd 100644 --- a/mobile/android/base/GeckoEvent.java +++ b/mobile/android/base/GeckoEvent.java @@ -92,6 +92,7 @@ public class GeckoEvent { private static final int ACTIVITY_RESUMING = 24; private static final int SCREENSHOT = 25; private static final int SENSOR_ACCURACY = 26; + private static final int SCREENORIENTATION_CHANGED = 27; public static final int IME_COMPOSITION_END = 0; public static final int IME_COMPOSITION_BEGIN = 1; @@ -139,6 +140,8 @@ public class GeckoEvent { public int mNativeWindow; + public short mScreenOrientation; + private GeckoEvent(int evType) { mType = evType; } @@ -443,4 +446,10 @@ public class GeckoEvent { event.mFlags = accuracy; return event; } + + public static GeckoEvent createScreenOrientationEvent(short aScreenOrientation) { + GeckoEvent event = new GeckoEvent(SCREENORIENTATION_CHANGED); + event.mScreenOrientation = aScreenOrientation; + return event; + } } diff --git a/mobile/android/base/GeckoScreenOrientationListener.java b/mobile/android/base/GeckoScreenOrientationListener.java new file mode 100644 index 000000000000..64738fb861ab --- /dev/null +++ b/mobile/android/base/GeckoScreenOrientationListener.java @@ -0,0 +1,122 @@ +/* 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/. */ + +package org.mozilla.gecko; + +import android.content.Context; +import android.util.Log; +import android.view.OrientationEventListener; +import android.view.Surface; + +public class GeckoScreenOrientationListener +{ + static class OrientationEventListenerImpl extends OrientationEventListener { + public OrientationEventListenerImpl(Context c) { + super(c); + } + + @Override + public void onOrientationChanged(int aOrientation) { + GeckoScreenOrientationListener.getInstance().updateScreenOrientation(); + } + } + + static private GeckoScreenOrientationListener sInstance = null; + + // Make sure that any change in dom/base/ScreenOrientation.h happens here too. + static public final short eScreenOrientation_PortraitPrimary = 1; + static public final short eScreenOrientation_PortraitSecondary = 2; + static public final short eScreenOrientation_LandscapePrimary = 4; + static public final short eScreenOrientation_LandscapeSecondary = 8; + + private short mOrientation; + private OrientationEventListenerImpl mListener = null; + + // Whether the listener should be listening to changes. + private boolean mShouldBeListening = false; + // Whether the listener should notify Gecko that a change happened. + private boolean mShouldNotify = false; + + private GeckoScreenOrientationListener() { + mListener = new OrientationEventListenerImpl(GeckoApp.mAppContext); + } + + public static GeckoScreenOrientationListener getInstance() { + if (sInstance == null) { + sInstance = new GeckoScreenOrientationListener(); + } + + return sInstance; + } + + public void start() { + mShouldBeListening = true; + updateScreenOrientation(); + + if (mShouldNotify) { + startListening(); + } + } + + public void stop() { + mShouldBeListening = false; + + if (mShouldNotify) { + stopListening(); + } + } + + public void enableNotifications() { + updateScreenOrientation(); + mShouldNotify = true; + + if (mShouldBeListening) { + startListening(); + } + } + + public void disableNotifications() { + mShouldNotify = false; + + if (mShouldBeListening) { + stopListening(); + } + } + + private void startListening() { + mListener.enable(); + } + + private void stopListening() { + mListener.disable(); + } + + // NOTE: this is public so OrientationEventListenerImpl can access it. + // Unfortunately, Java doesn't know about friendship. + public void updateScreenOrientation() { + int rotation = GeckoApp.mAppContext.getWindowManager().getDefaultDisplay().getRotation(); + short previousOrientation = mOrientation; + + if (rotation == Surface.ROTATION_0) { + mOrientation = eScreenOrientation_PortraitPrimary; + } else if (rotation == Surface.ROTATION_180) { + mOrientation = eScreenOrientation_PortraitSecondary; + } else if (rotation == Surface.ROTATION_270) { + mOrientation = eScreenOrientation_LandscapeSecondary; + } else if (rotation == Surface.ROTATION_90) { + mOrientation = eScreenOrientation_LandscapePrimary; + } else { + Log.e("GeckoScreenOrientationListener", "Unexpected value received! (" + rotation + ")"); + return; + } + + if (mShouldNotify && mOrientation != previousOrientation) { + GeckoAppShell.sendEventToGecko(GeckoEvent.createScreenOrientationEvent(mOrientation)); + } + } + + public short getScreenOrientation() { + return mOrientation; + } +} diff --git a/mobile/android/base/Makefile.in b/mobile/android/base/Makefile.in index 90f506afbff1..969a9ebcddf7 100644 --- a/mobile/android/base/Makefile.in +++ b/mobile/android/base/Makefile.in @@ -150,6 +150,7 @@ FENNEC_JAVA_FILES = \ ui/SimpleScaleGestureDetector.java \ ui/SubdocumentScrollHelper.java \ GeckoNetworkManager.java \ + GeckoScreenOrientationListener.java \ $(NULL) ifdef MOZ_WEBSMS_BACKEND diff --git a/mobile/android/base/ProfileMigrator.java b/mobile/android/base/ProfileMigrator.java index 121f2c6dac31..4b7420c6dbe3 100644 --- a/mobile/android/base/ProfileMigrator.java +++ b/mobile/android/base/ProfileMigrator.java @@ -531,7 +531,7 @@ public class ProfileMigrator { parent = mRerootMap.get(parent); } values.put(Bookmarks.PARENT, parent); - values.put(Bookmarks.IS_FOLDER, (folder ? 1 : 0)); + values.put(Bookmarks.TYPE, (folder ? Bookmarks.TYPE_FOLDER : Bookmarks.TYPE_BOOKMARK)); Cursor cursor = null; ContentProviderOperation.Builder builder = null; diff --git a/mobile/android/base/db/BrowserContract.java.in b/mobile/android/base/db/BrowserContract.java.in index 60e170fef984..9efb8700903b 100644 --- a/mobile/android/base/db/BrowserContract.java.in +++ b/mobile/android/base/db/BrowserContract.java.in @@ -108,6 +108,12 @@ public class BrowserContract { public static final String TOOLBAR_FOLDER_GUID = "toolbar"; public static final String UNFILED_FOLDER_GUID = "unfiled"; + public static final int TYPE_FOLDER = 0; + public static final int TYPE_BOOKMARK = 1; + public static final int TYPE_SEPARATOR = 2; + public static final int TYPE_LIVEMARK = 3; + public static final int TYPE_QUERY = 4; + public static final Uri CONTENT_URI = Uri.withAppendedPath(AUTHORITY_URI, "bookmarks"); public static final Uri PARENTS_CONTENT_URI = Uri.withAppendedPath(CONTENT_URI, "parents"); // Hacky API for bulk-updating positions. Bug 728783. @@ -115,7 +121,7 @@ public class BrowserContract { public static final String CONTENT_TYPE = "vnd.android.cursor.dir/bookmark"; public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/bookmark"; - public static final String IS_FOLDER = "folder"; + public static final String TYPE = "type"; public static final String PARENT = "parent"; public static final String POSITION = "position"; public static final String TAGS = "tags"; diff --git a/mobile/android/base/db/BrowserProvider.java.in b/mobile/android/base/db/BrowserProvider.java.in index 409bedf1a5c7..3c17dc0774f3 100644 --- a/mobile/android/base/db/BrowserProvider.java.in +++ b/mobile/android/base/db/BrowserProvider.java.in @@ -55,7 +55,7 @@ public class BrowserProvider extends ContentProvider { static final String DATABASE_NAME = "browser.db"; - static final int DATABASE_VERSION = 3; + static final int DATABASE_VERSION = 4; // Maximum age of deleted records to be cleaned up (20 days in ms) static final long MAX_AGE_OF_DELETED_RECORDS = 86400000 * 20; @@ -90,8 +90,8 @@ public class BrowserProvider extends ContentProvider { // Schema matches static final int SCHEMA = 400; - static final String DEFAULT_BOOKMARKS_SORT_ORDER = Bookmarks.IS_FOLDER - + " DESC, " + Bookmarks.POSITION + " ASC, " + Bookmarks._ID + static final String DEFAULT_BOOKMARKS_SORT_ORDER = Bookmarks.TYPE + + " ASC, " + Bookmarks.POSITION + " ASC, " + Bookmarks._ID + " ASC"; static final String DEFAULT_HISTORY_SORT_ORDER = History.DATE_LAST_VISITED + " DESC"; @@ -128,7 +128,7 @@ public class BrowserProvider extends ContentProvider { map.put(Bookmarks.URL, Bookmarks.URL); map.put(Bookmarks.FAVICON, Bookmarks.FAVICON); map.put(Bookmarks.THUMBNAIL, Bookmarks.THUMBNAIL); - map.put(Bookmarks.IS_FOLDER, Bookmarks.IS_FOLDER); + map.put(Bookmarks.TYPE, Bookmarks.TYPE); map.put(Bookmarks.PARENT, Bookmarks.PARENT); map.put(Bookmarks.POSITION, Bookmarks.POSITION); map.put(Bookmarks.TAGS, Bookmarks.TAGS); @@ -184,6 +184,23 @@ public class BrowserProvider extends ContentProvider { private HashMap mDatabasePerProfile; + private interface BookmarkMigrator { + public void updateForNewTable(ContentValues bookmark); + } + + private class BookmarkMigrator3to4 implements BookmarkMigrator { + public void updateForNewTable(ContentValues bookmark) { + Integer isFolder = bookmark.getAsInteger("folder"); + if (isFolder == null || isFolder != 1) { + bookmark.put(Bookmarks.TYPE, Bookmarks.TYPE_BOOKMARK); + } else { + bookmark.put(Bookmarks.TYPE, Bookmarks.TYPE_FOLDER); + } + + bookmark.remove("folder"); + } + } + static final String qualifyColumn(String table, String column) { return table + "." + column; } @@ -235,7 +252,7 @@ public class BrowserProvider extends ContentProvider { Bookmarks._ID + " INTEGER PRIMARY KEY AUTOINCREMENT," + Bookmarks.TITLE + " TEXT," + Bookmarks.URL + " TEXT," + - Bookmarks.IS_FOLDER + " INTEGER NOT NULL DEFAULT 0," + + Bookmarks.TYPE + " INTEGER NOT NULL DEFAULT " + Bookmarks.TYPE_BOOKMARK + "," + Bookmarks.PARENT + " INTEGER," + Bookmarks.POSITION + " INTEGER NOT NULL," + Bookmarks.KEYWORD + " TEXT," + @@ -356,7 +373,7 @@ public class BrowserProvider extends ContentProvider { String guid, int titleId, int position) { ContentValues values = new ContentValues(); values.put(Bookmarks.GUID, guid); - values.put(Bookmarks.IS_FOLDER, 1); + values.put(Bookmarks.TYPE, Bookmarks.TYPE_FOLDER); values.put(Bookmarks.POSITION, position); if (guid.equals(Bookmarks.PLACES_FOLDER_GUID)) @@ -396,7 +413,8 @@ public class BrowserProvider extends ContentProvider { guid.equals(Bookmarks.TAGS_FOLDER_GUID); } - private void migrateBookmarkFolder(SQLiteDatabase db, int folderId) { + private void migrateBookmarkFolder(SQLiteDatabase db, int folderId, + BookmarkMigrator migrator) { Cursor c = null; debug("Migrating bookmark folder with id = " + folderId); @@ -450,11 +468,14 @@ public class BrowserProvider extends ContentProvider { continue; } + if (migrator != null) + migrator.updateForNewTable(values); + debug("Migrating bookmark: " + values.getAsString(Bookmarks.TITLE)); db.insert(TABLE_BOOKMARKS, Bookmarks.URL, values); - Integer isFolder = values.getAsInteger(Bookmarks.IS_FOLDER); - if (isFolder != null && isFolder == 1) + Integer type = values.getAsInteger(Bookmarks.TYPE); + if (type != null && type == Bookmarks.TYPE_FOLDER) subFolders.add(values.getAsInteger(Bookmarks._ID)); } } finally { @@ -481,11 +502,15 @@ public class BrowserProvider extends ContentProvider { final int nSubFolders = subFolders.size(); for (int i = 0; i < nSubFolders; i++) { int subFolderId = subFolders.get(i); - migrateBookmarkFolder(db, subFolderId); + migrateBookmarkFolder(db, subFolderId, migrator); } } - private void upgradeDatabaseFrom1to2(SQLiteDatabase db) { + private void migrateBookmarksTable(SQLiteDatabase db) { + migrateBookmarksTable(db, null); + } + + private void migrateBookmarksTable(SQLiteDatabase db, BookmarkMigrator migrator) { debug("Renaming bookmarks table to " + TABLE_BOOKMARKS_TMP); db.execSQL("ALTER TABLE " + TABLE_BOOKMARKS + " RENAME TO " + TABLE_BOOKMARKS_TMP); @@ -503,7 +528,7 @@ public class BrowserProvider extends ContentProvider { createOrUpdateSpecialFolder(db, Bookmarks.PLACES_FOLDER_GUID, R.string.bookmarks_folder_places, 0); - migrateBookmarkFolder(db, Bookmarks.FIXED_ROOT_ID); + migrateBookmarkFolder(db, Bookmarks.FIXED_ROOT_ID, migrator); // Ensure all special folders exist and have the // right folder hierarchy. @@ -513,6 +538,10 @@ public class BrowserProvider extends ContentProvider { db.execSQL("DROP TABLE IF EXISTS " + TABLE_BOOKMARKS_TMP); } + private void upgradeDatabaseFrom1to2(SQLiteDatabase db) { + migrateBookmarksTable(db); + } + private void upgradeDatabaseFrom2to3(SQLiteDatabase db) { debug("Dropping view: " + VIEW_BOOKMARKS_WITH_IMAGES); db.execSQL("DROP VIEW IF EXISTS " + VIEW_BOOKMARKS_WITH_IMAGES); @@ -525,6 +554,10 @@ public class BrowserProvider extends ContentProvider { createHistoryWithImagesView(db); } + private void upgradeDatabaseFrom3to4(SQLiteDatabase db) { + migrateBookmarksTable(db, new BookmarkMigrator3to4()); + } + @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { debug("Upgrading browser.db: " + db.getPath() + " from " + @@ -543,6 +576,10 @@ public class BrowserProvider extends ContentProvider { case 3: upgradeDatabaseFrom2to3(db); break; + + case 4: + upgradeDatabaseFrom3to4(db); + break; } } @@ -934,10 +971,10 @@ public class BrowserProvider extends ContentProvider { String url = values.getAsString(Bookmarks.URL); ContentValues imageValues = extractImageValues(values, url); - Integer isFolder = values.getAsInteger(Bookmarks.IS_FOLDER); + Integer type = values.getAsInteger(Bookmarks.TYPE); - if ((isFolder == null || isFolder != 1) && imageValues != null - && !TextUtils.isEmpty(url)) { + if ((type == null || type != Bookmarks.TYPE_FOLDER) + && imageValues != null && !TextUtils.isEmpty(url)) { debug("Inserting bookmark image for URL: " + url); updateOrInsertImage(uri, imageValues, Images.URL + " = ?", new String[] { url }); diff --git a/mobile/android/base/db/LocalBrowserDB.java b/mobile/android/base/db/LocalBrowserDB.java index c2407164decc..6d44e12a0a6b 100644 --- a/mobile/android/base/db/LocalBrowserDB.java +++ b/mobile/android/base/db/LocalBrowserDB.java @@ -95,7 +95,7 @@ public class LocalBrowserDB implements BrowserDB.BrowserDBIface { Bookmarks.GUID, Bookmarks.URL, Bookmarks.TITLE, - Bookmarks.IS_FOLDER, + Bookmarks.TYPE, Bookmarks.PARENT, Bookmarks.FAVICON }; @@ -366,10 +366,15 @@ public class LocalBrowserDB implements BrowserDB.BrowserDBIface { Bookmarks.UNFILED_FOLDER_GUID }, null); } else { + // Right now, we only support showing folder and bookmark type of + // entries. We should add support for other types though (bug 737024) c = cr.query(mBookmarksUriWithProfile, DEFAULT_BOOKMARK_COLUMNS, - Bookmarks.PARENT + " = ? ", - new String[] { String.valueOf(folderId) }, + Bookmarks.PARENT + " = ? AND " + + "(" + Bookmarks.TYPE + " = ? OR " + Bookmarks.TYPE + " = ?)", + new String[] { String.valueOf(folderId), + String.valueOf(Bookmarks.TYPE_BOOKMARK), + String.valueOf(Bookmarks.TYPE_FOLDER) }, null); } diff --git a/mobile/android/base/gfx/LayerRenderer.java b/mobile/android/base/gfx/LayerRenderer.java index ed63d55715c0..3d6249d74e24 100644 --- a/mobile/android/base/gfx/LayerRenderer.java +++ b/mobile/android/base/gfx/LayerRenderer.java @@ -543,24 +543,6 @@ public class LayerRenderer implements GLSurfaceView.Renderer { mUpdated &= layer.update(mPageContext); // called on compositor thread GLES20.glDisable(GLES20.GL_SCISSOR_TEST); - - // If a layer update requires further work, schedule another redraw - if (!mUpdated) - mView.requestRender(); - - PanningPerfAPI.recordFrameTime(); - - /* Used by robocop for testing purposes */ - IntBuffer pixelBuffer = mPixelBuffer; - if (mUpdated && pixelBuffer != null) { - synchronized (pixelBuffer) { - pixelBuffer.position(0); - GLES20.glReadPixels(0, 0, (int)mScreenContext.viewport.width(), - (int)mScreenContext.viewport.height(), GLES20.GL_RGBA, - GLES20.GL_UNSIGNED_BYTE, pixelBuffer); - pixelBuffer.notify(); - } - } } /** This function is invoked via JNI; be careful when modifying signature. */ diff --git a/mobile/android/base/sync/delegates/GlobalSessionCallback.java b/mobile/android/base/sync/delegates/GlobalSessionCallback.java index 8d7a37276fb5..754b19f47a1d 100644 --- a/mobile/android/base/sync/delegates/GlobalSessionCallback.java +++ b/mobile/android/base/sync/delegates/GlobalSessionCallback.java @@ -46,7 +46,7 @@ public interface GlobalSessionCallback { * error. * * @param globalSession - * @param newClusterURL + * @param failedClusterURL * The new node/weave cluster URL. */ void informNodeAuthenticationFailed(GlobalSession globalSession, URI failedClusterURL); diff --git a/mobile/android/base/sync/net/SyncStorageCollectionRequest.java b/mobile/android/base/sync/net/SyncStorageCollectionRequest.java index 020b2892bf44..3a1f8c86f435 100644 --- a/mobile/android/base/sync/net/SyncStorageCollectionRequest.java +++ b/mobile/android/base/sync/net/SyncStorageCollectionRequest.java @@ -10,6 +10,8 @@ import java.io.InputStream; import java.io.InputStreamReader; import java.net.URI; +import org.mozilla.gecko.sync.Logger; + import ch.boye.httpclientandroidlib.Header; import ch.boye.httpclientandroidlib.HttpEntity; import ch.boye.httpclientandroidlib.HttpResponse; @@ -25,10 +27,28 @@ import ch.boye.httpclientandroidlib.impl.client.DefaultHttpClient; * */ public class SyncStorageCollectionRequest extends SyncStorageRequest { + private static final String LOG_TAG = "CollectionRequest"; + public SyncStorageCollectionRequest(URI uri) { super(uri); } + protected volatile boolean aborting = false; + + /** + * Instruct the request that it should process no more records, + * and decline to notify any more delegate callbacks. + */ + public void abort() { + aborting = true; + try { + this.resource.request.abort(); + } catch (Exception e) { + // Just in case. + Logger.warn(LOG_TAG, "Got exception in abort: " + e); + } + } + @Override protected SyncResourceDelegate makeResourceDelegate(SyncStorageRequest request) { return new SyncCollectionResourceDelegate((SyncStorageCollectionRequest) request); @@ -38,6 +58,9 @@ public class SyncStorageCollectionRequest extends SyncStorageRequest { public class SyncCollectionResourceDelegate extends SyncStorageResourceDelegate { + private static final String CONTENT_TYPE_INCREMENTAL = "application/newlines"; + private static final int FETCH_BUFFER_SIZE = 16 * 1024; // 16K chars. + SyncCollectionResourceDelegate(SyncStorageCollectionRequest request) { super(request); } @@ -45,12 +68,16 @@ public class SyncStorageCollectionRequest extends SyncStorageRequest { @Override public void addHeaders(HttpRequestBase request, DefaultHttpClient client) { super.addHeaders(request, client); - request.setHeader("Accept", "application/newlines"); + request.setHeader("Accept", CONTENT_TYPE_INCREMENTAL); // Caller is responsible for setting full=1. } @Override public void handleHttpResponse(HttpResponse response) { + if (aborting) { + return; + } + if (response.getStatusLine().getStatusCode() != 200) { super.handleHttpResponse(response); return; @@ -58,7 +85,7 @@ public class SyncStorageCollectionRequest extends SyncStorageRequest { HttpEntity entity = response.getEntity(); Header contentType = entity.getContentType(); - if (!contentType.getValue().startsWith("application/newlines")) { + if (!contentType.getValue().startsWith(CONTENT_TYPE_INCREMENTAL)) { // Not incremental! super.handleHttpResponse(response); return; @@ -76,12 +103,12 @@ public class SyncStorageCollectionRequest extends SyncStorageRequest { BufferedReader br = null; try { content = entity.getContent(); - int bufSize = 1024 * 1024; // 1MB. TODO: lift and consider. - br = new BufferedReader(new InputStreamReader(content), bufSize); + br = new BufferedReader(new InputStreamReader(content), FETCH_BUFFER_SIZE); String line; // This relies on connection timeouts at the HTTP layer. - while (null != (line = br.readLine())) { + while (!aborting && + null != (line = br.readLine())) { try { delegate.handleRequestProgress(line); } catch (Exception ex) { @@ -90,8 +117,14 @@ public class SyncStorageCollectionRequest extends SyncStorageRequest { return; } } + if (aborting) { + // So we don't hit the success case below. + return; + } } catch (IOException ex) { - delegate.handleRequestError(ex); + if (!aborting) { + delegate.handleRequestError(ex); + } BaseResource.consumeEntity(entity); return; } finally { diff --git a/mobile/android/base/sync/repositories/RepositorySession.java b/mobile/android/base/sync/repositories/RepositorySession.java index 743fe11019d3..6bf2bb3d8749 100644 --- a/mobile/android/base/sync/repositories/RepositorySession.java +++ b/mobile/android/base/sync/repositories/RepositorySession.java @@ -215,7 +215,7 @@ public abstract class RepositorySession { // TODO: do something here. this.setStatus(SessionStatus.ABORTED); try { - storeWorkQueue.shutdown(); + storeWorkQueue.shutdownNow(); } catch (Exception e) { Logger.error(LOG_TAG, "Caught exception shutting down store work queue.", e); } diff --git a/mobile/android/base/sync/repositories/Server11RepositorySession.java b/mobile/android/base/sync/repositories/Server11RepositorySession.java index 111f954589b7..93b3da1c3ec4 100644 --- a/mobile/android/base/sync/repositories/Server11RepositorySession.java +++ b/mobile/android/base/sync/repositories/Server11RepositorySession.java @@ -10,7 +10,9 @@ import java.io.UnsupportedEncodingException; import java.net.URI; import java.net.URISyntaxException; import java.util.ArrayList; -import java.util.Date; +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; import java.util.concurrent.atomic.AtomicLong; import org.json.simple.JSONArray; @@ -86,6 +88,20 @@ public class Server11RepositorySession extends RepositorySession { return normalizedTimestamp; } + /** + * Used to track outstanding requests, so that we can abort them as needed. + */ + private Set pending = Collections.synchronizedSet(new HashSet()); + + @Override + public void abort() { + super.abort(); + for (SyncStorageCollectionRequest request : pending) { + request.abort(); + } + pending.clear(); + } + /** * Convert HTTP request delegate callbacks into fetch callbacks within the * context of this RepositorySession. @@ -97,6 +113,20 @@ public class Server11RepositorySession extends RepositorySession { RepositorySessionFetchRecordsDelegate delegate; private DelayedWorkTracker workTracker = new DelayedWorkTracker(); + // So that we can clean up. + private SyncStorageCollectionRequest request; + + public void setRequest(SyncStorageCollectionRequest request) { + this.request = request; + } + private void removeRequestFromPending() { + if (this.request == null) { + return; + } + pending.remove(this.request); + this.request = null; + } + public RequestFetchDelegateAdapter(RepositorySessionFetchRecordsDelegate delegate) { this.delegate = delegate; } @@ -114,6 +144,7 @@ public class Server11RepositorySession extends RepositorySession { @Override public void handleRequestSuccess(SyncStorageResponse response) { Logger.debug(LOG_TAG, "Fetch done."); + removeRequestFromPending(); final long normalizedTimestamp = getNormalizedTimestamp(response); Logger.debug(LOG_TAG, "Fetch completed. Timestamp is " + normalizedTimestamp); @@ -137,6 +168,7 @@ public class Server11RepositorySession extends RepositorySession { @Override public void handleRequestError(final Exception ex) { + removeRequestFromPending(); Logger.warn(LOG_TAG, "Got request error.", ex); // When we're done processing other events, finish. workTracker.delayWorkItem(new Runnable() { @@ -217,12 +249,16 @@ public class Server11RepositorySession extends RepositorySession { boolean full, String sort, String ids, - SyncStorageRequestDelegate delegate) + RequestFetchDelegateAdapter delegate) throws URISyntaxException { URI collectionURI = serverRepository.collectionURI(full, newer, limit, sort, ids); SyncStorageCollectionRequest request = new SyncStorageCollectionRequest(collectionURI); request.delegate = delegate; + + // So it can clean up. + delegate.setRequest(request); + pending.add(request); request.get(); } diff --git a/mobile/android/base/sync/repositories/android/AndroidBrowserBookmarksDataAccessor.java b/mobile/android/base/sync/repositories/android/AndroidBrowserBookmarksDataAccessor.java index e9b623ab1bb6..341f7a21c665 100644 --- a/mobile/android/base/sync/repositories/android/AndroidBrowserBookmarksDataAccessor.java +++ b/mobile/android/base/sync/repositories/android/AndroidBrowserBookmarksDataAccessor.java @@ -26,7 +26,8 @@ public class AndroidBrowserBookmarksDataAccessor extends AndroidBrowserRepositor /* * Fragments of SQL to make our lives easier. */ - private static final String BOOKMARK_IS_FOLDER = BrowserContract.Bookmarks.IS_FOLDER + " = 1"; + private static final String BOOKMARK_IS_FOLDER = BrowserContract.Bookmarks.TYPE + " = " + + BrowserContract.Bookmarks.TYPE_FOLDER; private static final String GUID_NOT_TAGS_OR_PLACES = BrowserContract.SyncColumns.GUID + " NOT IN ('" + BrowserContract.Bookmarks.TAGS_FOLDER_GUID + "', '" + BrowserContract.Bookmarks.PLACES_FOLDER_GUID + "')"; @@ -127,8 +128,7 @@ public class AndroidBrowserBookmarksDataAccessor extends AndroidBrowserRepositor public void checkAndBuildSpecialGuids() throws NullCursorException { final String[] specialGUIDs = AndroidBrowserBookmarksRepositorySession.SPECIAL_GUIDS; Cursor cur = fetch(specialGUIDs); - long mobileRoot = 0; - long desktopRoot = 0; + long placesRoot = 0; // Map from GUID to whether deleted. Non-presence implies just that. HashMap statuses = new HashMap(specialGUIDs.length); @@ -136,11 +136,8 @@ public class AndroidBrowserBookmarksDataAccessor extends AndroidBrowserRepositor if (cur.moveToFirst()) { while (!cur.isAfterLast()) { String guid = RepoUtils.getStringFromCursor(cur, BrowserContract.SyncColumns.GUID); - if (guid.equals("mobile")) { - mobileRoot = RepoUtils.getLongFromCursor(cur, BrowserContract.CommonColumns._ID); - } - if (guid.equals("desktop")) { - desktopRoot = RepoUtils.getLongFromCursor(cur, BrowserContract.CommonColumns._ID); + if ("places".equals(guid)) { + placesRoot = RepoUtils.getLongFromCursor(cur, BrowserContract.CommonColumns._ID); } // Make sure none of these folders are marked as deleted. boolean deleted = RepoUtils.getLongFromCursor(cur, BrowserContract.SyncColumns.IS_DELETED) == 1; @@ -164,17 +161,17 @@ public class AndroidBrowserBookmarksDataAccessor extends AndroidBrowserRepositor } } else { // Insert. - if (guid.equals("mobile")) { - Logger.info(LOG_TAG, "No mobile folder. Inserting one."); - mobileRoot = insertSpecialFolder("mobile", 0); - } else if (guid.equals("places")) { + if (guid.equals("places")) { // This is awkward. - Logger.info(LOG_TAG, "No places root. Inserting one under mobile (" + mobileRoot + ")."); - desktopRoot = insertSpecialFolder("places", mobileRoot); + Logger.info(LOG_TAG, "No places root. Inserting one."); + placesRoot = insertSpecialFolder("places", 0); + } else if (guid.equals("mobile")) { + Logger.info(LOG_TAG, "No mobile folder. Inserting one under the places root."); + insertSpecialFolder("mobile", placesRoot); } else { // unfiled, menu, toolbar. - Logger.info(LOG_TAG, "No " + guid + " root. Inserting one under places (" + desktopRoot + ")."); - insertSpecialFolder(guid, desktopRoot); + Logger.info(LOG_TAG, "No " + guid + " root. Inserting one under places (" + placesRoot + ")."); + insertSpecialFolder(guid, placesRoot); } } } @@ -206,7 +203,9 @@ public class AndroidBrowserBookmarksDataAccessor extends AndroidBrowserRepositor // Only bookmark and folder types should make it this far. // Other types should be filtered out and dropped. - cv.put(BrowserContract.Bookmarks.IS_FOLDER, rec.type.equalsIgnoreCase(TYPE_FOLDER) ? 1 : 0); + cv.put(BrowserContract.Bookmarks.TYPE, rec.type.equalsIgnoreCase(TYPE_FOLDER) ? + BrowserContract.Bookmarks.TYPE_FOLDER : + BrowserContract.Bookmarks.TYPE_BOOKMARK); // Note that we don't set the modified timestamp: we allow the // content provider to do that for us. diff --git a/mobile/android/base/sync/repositories/android/AndroidBrowserBookmarksRepositorySession.java b/mobile/android/base/sync/repositories/android/AndroidBrowserBookmarksRepositorySession.java index 226b6eb9c70f..563206495aa2 100644 --- a/mobile/android/base/sync/repositories/android/AndroidBrowserBookmarksRepositorySession.java +++ b/mobile/android/base/sync/repositories/android/AndroidBrowserBookmarksRepositorySession.java @@ -102,8 +102,8 @@ public class AndroidBrowserBookmarksRepositorySession extends AndroidBrowserRepo */ public static String[] SPECIAL_GUIDS = new String[] { // Mobile and desktop places roots have to come first. - "mobile", "places", + "mobile", "toolbar", "menu", "unfiled" @@ -196,8 +196,12 @@ public class AndroidBrowserBookmarksRepositorySession extends AndroidBrowserRepo dataAccessor = (AndroidBrowserBookmarksDataAccessor) dbHelper; } - private boolean rowIsFolder(Cursor cur) { - return RepoUtils.getLongFromCursor(cur, BrowserContract.Bookmarks.IS_FOLDER) == 1; + private static long getTypeFromCursor(Cursor cur) { + return RepoUtils.getLongFromCursor(cur, BrowserContract.Bookmarks.TYPE); + } + + private static boolean rowIsFolder(Cursor cur) { + return getTypeFromCursor(cur) == BrowserContract.Bookmarks.TYPE_FOLDER; } private String getGUIDForID(long androidID) { @@ -837,7 +841,7 @@ public class AndroidBrowserBookmarksRepositorySession extends AndroidBrowserRepo return logBookmark(rec); } - boolean isFolder = RepoUtils.getIntFromCursor(cur, BrowserContract.Bookmarks.IS_FOLDER) == 1; + boolean isFolder = rowIsFolder(cur); rec.title = RepoUtils.getStringFromCursor(cur, BrowserContract.Bookmarks.TITLE); rec.bookmarkURI = RepoUtils.getStringFromCursor(cur, BrowserContract.Bookmarks.URL); diff --git a/mobile/android/base/sync/repositories/android/BrowserContractHelpers.java b/mobile/android/base/sync/repositories/android/BrowserContractHelpers.java index 01c2098cd8f6..3254735eebce 100644 --- a/mobile/android/base/sync/repositories/android/BrowserContractHelpers.java +++ b/mobile/android/base/sync/repositories/android/BrowserContractHelpers.java @@ -70,7 +70,7 @@ public class BrowserContractHelpers extends BrowserContract { SyncColumns.IS_DELETED, Bookmarks.TITLE, Bookmarks.URL, - Bookmarks.IS_FOLDER, + Bookmarks.TYPE, Bookmarks.PARENT, Bookmarks.POSITION, Bookmarks.TAGS, diff --git a/mobile/android/base/sync/repositories/android/FennecTabsRepository.java b/mobile/android/base/sync/repositories/android/FennecTabsRepository.java index 446221ad4f06..7f948bd66340 100644 --- a/mobile/android/base/sync/repositories/android/FennecTabsRepository.java +++ b/mobile/android/base/sync/repositories/android/FennecTabsRepository.java @@ -32,7 +32,7 @@ public class FennecTabsRepository extends Repository { * and only store tabs from other clients. * * It will never retrieve tabs from other clients, or store tabs for Fennec, - * unless you use {@link fetch(String[], RepositorySessionFetchRecordsDelegate)} + * unless you use {@link #fetch(String[], RepositorySessionFetchRecordsDelegate)} * and specify an explicit GUID. */ public static class FennecTabsRepositorySession extends RepositorySession { diff --git a/mobile/android/base/sync/synchronizer/RecordConsumer.java b/mobile/android/base/sync/synchronizer/RecordConsumer.java index 22e4af6d5a85..9d1331302ddb 100644 --- a/mobile/android/base/sync/synchronizer/RecordConsumer.java +++ b/mobile/android/base/sync/synchronizer/RecordConsumer.java @@ -1,39 +1,6 @@ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is Android Sync Client. - * - * The Initial Developer of the Original Code is - * the Mozilla Foundation. - * Portions created by the Initial Developer are Copyright (C) 2011 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Richard Newman - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ +/* 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/. */ package org.mozilla.gecko.sync.synchronizer; @@ -56,5 +23,4 @@ public abstract class RecordConsumer implements Runnable { public RecordConsumer() { super(); } - } \ No newline at end of file diff --git a/mobile/android/base/sync/synchronizer/RecordsChannel.java b/mobile/android/base/sync/synchronizer/RecordsChannel.java index 647496e3777c..1be5d3d3a839 100644 --- a/mobile/android/base/sync/synchronizer/RecordsChannel.java +++ b/mobile/android/base/sync/synchronizer/RecordsChannel.java @@ -102,7 +102,8 @@ class RecordsChannel implements } /** - * Attempt to abort an outstanding fetch. Finish both sessions. + * Attempt to abort an outstanding fetch. Finish both sessions, and + * halt the consumer if it exists. */ public void abort() { if (source.isActive()) { @@ -111,6 +112,12 @@ class RecordsChannel implements if (sink.isActive()) { sink.abort(); } + + toProcess.clear(); + if (consumer == null) { + return; + } + consumer.halt(); } /** diff --git a/mobile/android/base/sync/synchronizer/SynchronizerSession.java b/mobile/android/base/sync/synchronizer/SynchronizerSession.java index 69b1d798636f..98f0553b4dd8 100644 --- a/mobile/android/base/sync/synchronizer/SynchronizerSession.java +++ b/mobile/android/base/sync/synchronizer/SynchronizerSession.java @@ -98,15 +98,29 @@ implements RecordsChannelDelegate, this.getSynchronizer().repositoryA.createSession(this, context); } - // TODO: implement aborting. - public void abort() { + // These are accessed by `abort` and `synchronize`, both of which are synchronized. + // Guarded by `this`. + protected RecordsChannel channelAToB; + protected RecordsChannel channelBToA; + + public synchronized void abort() { + // Guaranteed to have been begun by the time we get to run. + if (channelAToB != null) { + channelAToB.abort(); + } + + // Not guaranteed. It's possible for the second flow to begin after we've aborted. + // TODO: stop this from happening! + if (channelBToA != null) { + channelBToA.abort(); + } this.delegate.onSynchronizeAborted(this); } /** * Please don't call this until you've been notified with onInitialized. */ - public void synchronize() { + public synchronized void synchronize() { // First thing: decide whether we should. if (!sessionA.dataAvailable() && !sessionB.dataAvailable()) { @@ -123,7 +137,7 @@ implements RecordsChannelDelegate, // This is the *second* record channel to flow. // I, SynchronizerSession, am the delegate for the *second* flow. - final RecordsChannel channelBToA = new RecordsChannel(this.sessionB, this.sessionA, this); + channelBToA = new RecordsChannel(this.sessionB, this.sessionA, this); // This is the delegate for the *first* flow. RecordsChannelDelegate channelAToBDelegate = new RecordsChannelDelegate() { @@ -164,7 +178,7 @@ implements RecordsChannelDelegate, }; // This is the *first* channel to flow. - final RecordsChannel channelAToB = new RecordsChannel(this.sessionA, this.sessionB, channelAToBDelegate); + channelAToB = new RecordsChannel(this.sessionA, this.sessionB, channelAToBDelegate); Logger.info(LOG_TAG, "Starting A to B flow. Channel is " + channelAToB); try { diff --git a/mobile/android/base/tests/testBookmark.java.in b/mobile/android/base/tests/testBookmark.java.in index 4b02a766a486..6cacaa8ce8b2 100644 --- a/mobile/android/base/tests/testBookmark.java.in +++ b/mobile/android/base/tests/testBookmark.java.in @@ -12,6 +12,7 @@ public class testBookmark extends BaseTest { private static final int MAX_WAIT_MS = 3000; private static final String ABOUT_HOME_URL = "about:home"; private static final String BOOKMARK_URL = "/robocop/robocop_blank_01.html"; + private static final String BOOKMARK_TITLE = "Browser Blank Page 01"; public void testBookmark() { setTestType("mochitest"); @@ -21,6 +22,10 @@ public class testBookmark extends BaseTest { // Open the bookmark list and check the root folder view ListView bookmarksList = openBookmarksList(); + + // Wait for bookmark to appear in list + mSolo.waitForText(BOOKMARK_TITLE); + mAsserter.ok(bookmarksList != null, "checking that bookmarks list exists", "bookmarks list exists"); // No folders should be visible if no desktop bookmarks exist diff --git a/mobile/android/base/tests/testBrowserProvider.java.in b/mobile/android/base/tests/testBrowserProvider.java.in index ae80defdc0a3..f189d144862f 100644 --- a/mobile/android/base/tests/testBrowserProvider.java.in +++ b/mobile/android/base/tests/testBrowserProvider.java.in @@ -38,7 +38,7 @@ public class testBrowserProvider extends ContentProviderTest { private String mBookmarksFaviconCol; private String mBookmarksThumbnailCol; private String mBookmarksParentCol; - private String mBookmarksIsFolderCol; + private String mBookmarksTypeCol; private String mBookmarksPositionCol; private String mBookmarksTagsCol; private String mBookmarksDescriptionCol; @@ -47,6 +47,8 @@ public class testBrowserProvider extends ContentProviderTest { private String mBookmarksIsDeletedCol; private String mBookmarksDateCreatedCol; private String mBookmarksDateModifiedCol; + private int mBookmarksTypeFolder; + private int mBookmarksTypeBookmark; private long mMobileFolderId; private String mHistoryIdCol; @@ -83,7 +85,7 @@ public class testBrowserProvider extends ContentProviderTest { mBookmarksFaviconCol = getStringColumn("Bookmarks", "FAVICON"); mBookmarksThumbnailCol = getStringColumn("Bookmarks", "THUMBNAIL"); mBookmarksParentCol = getStringColumn("Bookmarks", "PARENT"); - mBookmarksIsFolderCol = getStringColumn("Bookmarks", "IS_FOLDER"); + mBookmarksTypeCol = getStringColumn("Bookmarks", "TYPE"); mBookmarksPositionCol = getStringColumn("Bookmarks", "POSITION"); mBookmarksTagsCol = getStringColumn("Bookmarks", "TAGS"); mBookmarksDescriptionCol = getStringColumn("Bookmarks", "DESCRIPTION"); @@ -93,6 +95,9 @@ public class testBrowserProvider extends ContentProviderTest { mBookmarksDateCreatedCol = getStringColumn("Bookmarks", "DATE_CREATED"); mBookmarksDateModifiedCol = getStringColumn("Bookmarks", "DATE_MODIFIED"); + mBookmarksTypeFolder = getIntColumn("Bookmarks", "TYPE_FOLDER"); + mBookmarksTypeBookmark = getIntColumn("Bookmarks", "TYPE_BOOKMARK"); + mHistoryIdCol = getStringColumn("History", "_ID"); mHistoryTitleCol = getStringColumn("History", "TITLE"); mHistoryUrlCol = getStringColumn("History", "URL"); @@ -149,14 +154,13 @@ public class testBrowserProvider extends ContentProviderTest { } private ContentValues createBookmark(String title, String url, long parentId, - int isFolder, int position, String tags, String description, - String keyword) throws Exception { + int type, int position, String tags, String description, String keyword) throws Exception { ContentValues bookmark = new ContentValues(); bookmark.put(mBookmarksTitleCol, title); bookmark.put(mBookmarksUrlCol, url); bookmark.put(mBookmarksParentCol, parentId); - bookmark.put(mBookmarksIsFolderCol, isFolder); + bookmark.put(mBookmarksTypeCol, type); bookmark.put(mBookmarksPositionCol, position); bookmark.put(mBookmarksTagsCol, tags); bookmark.put(mBookmarksDescriptionCol, description); @@ -167,7 +171,7 @@ public class testBrowserProvider extends ContentProviderTest { private ContentValues createOneBookmark() throws Exception { return createBookmark("Example", "http://example.com", mMobileFolderId, - 0, 0, "tags", "description", "keyword"); + mBookmarksTypeBookmark, 0, "tags", "description", "keyword"); } private Cursor getBookmarkByGuid(String guid) throws Exception { @@ -360,8 +364,8 @@ public class testBrowserProvider extends ContentProviderTest { "Inserted bookmark has correct description"); mAsserter.is(c.getString(c.getColumnIndex(mBookmarksPositionCol)), b.getAsString(mBookmarksPositionCol), "Inserted bookmark has correct position"); - mAsserter.is(c.getString(c.getColumnIndex(mBookmarksIsFolderCol)), b.getAsString(mBookmarksIsFolderCol), - "Inserted bookmark has correct is-folder flag"); + mAsserter.is(c.getString(c.getColumnIndex(mBookmarksTypeCol)), b.getAsString(mBookmarksTypeCol), + "Inserted bookmark has correct type"); mAsserter.is(c.getString(c.getColumnIndex(mBookmarksParentCol)), b.getAsString(mBookmarksParentCol), "Inserted bookmark has correct parent ID"); mAsserter.is(c.getString(c.getColumnIndex(mBookmarksIsDeletedCol)), String.valueOf(0), @@ -371,9 +375,9 @@ public class testBrowserProvider extends ContentProviderTest { mAsserter.is(new Long(id), new Long(-1), "Should not be able to insert bookmark with null position"); - id = insertWithNullCol(mBookmarksIsFolderCol); + id = insertWithNullCol(mBookmarksTypeCol); mAsserter.is(new Long(id), new Long(-1), - "Should not be able to insert bookmark with null is-folder flag"); + "Should not be able to insert bookmark with null type"); b = createOneBookmark(); b.put(mBookmarksParentCol, -1); @@ -387,6 +391,16 @@ public class testBrowserProvider extends ContentProviderTest { mAsserter.is(new Long(id), new Long(-1), "Should not be able to insert bookmark with invalid parent"); } + + b = createOneBookmark(); + b.remove(mBookmarksTypeCol); + id = ContentUris.parseId(mProvider.insert(mBookmarksUri, b)); + c = getBookmarkById(id); + + mAsserter.is(c.moveToFirst(), true, "Inserted bookmark found"); + + mAsserter.is(c.getString(c.getColumnIndex(mBookmarksTypeCol)), String.valueOf(mBookmarksTypeBookmark), + "Inserted bookmark has correct default type"); } } @@ -464,14 +478,14 @@ public class testBrowserProvider extends ContentProviderTest { if (Build.VERSION.SDK_INT >= 8) { ContentValues b = createBookmark("Folder", null, mMobileFolderId, - 1 /* is folder */, 0, "folderTags", "folderDescription", "folderKeyword"); + mBookmarksTypeFolder, 0, "folderTags", "folderDescription", "folderKeyword"); long parentId = ContentUris.parseId(mProvider.insert(mBookmarksUri, b)); c = getBookmarkById(parentId); mAsserter.is(c.moveToFirst(), true, "Inserted bookmarks folder found"); - b = createBookmark("Example", "http://example.com", parentId, 0, 0, "tags", - "description", "keyword"); + b = createBookmark("Example", "http://example.com", parentId, + mBookmarksTypeBookmark, 0, "tags", "description", "keyword"); id = ContentUris.parseId(mProvider.insert(mBookmarksUri, b)); c = getBookmarkById(id); @@ -538,7 +552,7 @@ public class testBrowserProvider extends ContentProviderTest { u.put(mBookmarksTagsCol, b.getAsString(mBookmarksTagsCol) + "CHANGED"); u.put(mBookmarksDescriptionCol, b.getAsString(mBookmarksDescriptionCol) + "CHANGED"); u.put(mBookmarksKeywordCol, b.getAsString(mBookmarksKeywordCol) + "CHANGED"); - u.put(mBookmarksIsFolderCol, 1); + u.put(mBookmarksTypeCol, mBookmarksTypeFolder); u.put(mBookmarksPositionCol, 10); int updated = mProvider.update(mBookmarksUri, u, @@ -562,8 +576,8 @@ public class testBrowserProvider extends ContentProviderTest { "Inserted bookmark has correct description"); mAsserter.is(c.getString(c.getColumnIndex(mBookmarksPositionCol)), u.getAsString(mBookmarksPositionCol), "Inserted bookmark has correct position"); - mAsserter.is(c.getString(c.getColumnIndex(mBookmarksIsFolderCol)), u.getAsString(mBookmarksIsFolderCol), - "Inserted bookmark has correct is-folder flag"); + mAsserter.is(c.getString(c.getColumnIndex(mBookmarksTypeCol)), u.getAsString(mBookmarksTypeCol), + "Inserted bookmark has correct type"); mAsserter.is(new Long(c.getLong(c.getColumnIndex(mBookmarksDateCreatedCol))), new Long(dateCreated), @@ -577,9 +591,9 @@ public class testBrowserProvider extends ContentProviderTest { mAsserter.is((updated > 0), false, "Should not be able to update bookmark with null position"); - updated = updateWithNullCol(id, mBookmarksIsFolderCol); + updated = updateWithNullCol(id, mBookmarksTypeCol); mAsserter.is((updated > 0), false, - "Should not be able to update bookmark with null is-folder flag"); + "Should not be able to update bookmark with null type"); u = new ContentValues(); u.put(mBookmarksUrlCol, "http://examples2.com"); diff --git a/mobile/android/components/HelperAppDialog.js b/mobile/android/components/HelperAppDialog.js index c9f1ef0303ac..7f305ea52b13 100644 --- a/mobile/android/components/HelperAppDialog.js +++ b/mobile/android/components/HelperAppDialog.js @@ -40,11 +40,7 @@ const Cu = Components.utils; const Cr = Components.results; const PREF_BD_USEDOWNLOADDIR = "browser.download.useDownloadDir"; -#ifdef ANDROID const URI_GENERIC_ICON_DOWNLOAD = "drawable://alertdownloads"; -#else -const URI_GENERIC_ICON_DOWNLOAD = "chrome://browser/skin/images/alert-downloads-30.png"; -#endif Cu.import("resource://gre/modules/XPCOMUtils.jsm"); Cu.import("resource://gre/modules/Services.jsm"); diff --git a/mobile/android/installer/package-manifest.in b/mobile/android/installer/package-manifest.in index b12c2a1fe063..83ecf4d465bb 100644 --- a/mobile/android/installer/package-manifest.in +++ b/mobile/android/installer/package-manifest.in @@ -620,6 +620,5 @@ bin/components/@DLL_PREFIX@nkgnomevfs@DLL_SUFFIX@ @BINPATH@/components/UpdatePrompt.js #endif @BINPATH@/components/XPIDialogService.js -@BINPATH@/components/CapturePicker.js @BINPATH@/components/browsercomps.xpt @BINPATH@/extensions/feedback@mobile.mozilla.org.xpi diff --git a/mobile/android/installer/removed-files.in b/mobile/android/installer/removed-files.in index af21a79cba10..4fcbc4e45e90 100644 --- a/mobile/android/installer/removed-files.in +++ b/mobile/android/installer/removed-files.in @@ -1,6 +1,7 @@ update.locale README.txt components/nsTryToClose.js +components/CapturePicker.js #if MOZ_UPDATE_CHANNEL != beta extensions/feedback@mobile.mozilla.org.xpi #endif diff --git a/mobile/android/themes/core/content.css b/mobile/android/themes/core/content.css index 978f9cc8dbb8..73b1cb50fa99 100644 --- a/mobile/android/themes/core/content.css +++ b/mobile/android/themes/core/content.css @@ -44,7 +44,7 @@ /* make clicking on links stand out a bit (bug 532206) */ * > *:not(embed):focus, * > *:focus > font { - outline: 2px solid #8db8d8 !important; + outline: 2px solid @color_background_highlight@ !important; /* XXX How do I preserve mac focusring without blowing focus color on other platforms? outline-color: -moz-mac-focusring !important; @@ -55,6 +55,11 @@ outline-offset: -2px; } +::-moz-selection { + background-color: @color_background_highlight@; + color: @color_text_highlight@; +} + /* Style the scrollbars */ html xul|scrollbar { display: none; @@ -123,7 +128,7 @@ xul|scrollbarbutton[sbattr="scrollbar-bottom-top"] { } xul|scrollbar xul|thumb { - background-color: rgba(0, 0, 0, 0.4) !important; + background-color: @color_background_scroller@ !important; -moz-border-top-colors: none !important; -moz-border-bottom-colors: none !important; -moz-border-right-colors: none !important; @@ -347,7 +352,7 @@ option:active, select:active, label:active, textarea:active { - background-color: rgba(141, 184, 216, 0.5) !important; + background-color: @color_background_highlight_overlay@ !important; } /* diff --git a/mobile/android/themes/core/defines.inc b/mobile/android/themes/core/defines.inc index 9b707fa873b1..186aa0a2675b 100644 --- a/mobile/android/themes/core/defines.inc +++ b/mobile/android/themes/core/defines.inc @@ -1,5 +1,31 @@ %filter substitution +%define color_background_active #525252 +%define color_background_default #000 +%define color_text_default #fff +%define color_divider_border #333333 +%define color_button_border #5a5a5a +%define color_dialog_border #5a5a5a +%define color_background_dlgbuttons #9a9a9a +%define color_background_panel #d6d6d6 +%define color_text_panel #000 +%define color_background_header #292929 +%define color_text_header #999999 +%define color_background_scroller #9a9a9a +%define color_background_inverse #fff +%define color_text_inverse #000 +%define color_text_button #000 +%define color_text_disabled #808080 +%define color_text_placeholder #808080 +%define color_text_as_link #febc2b + +%define color_background_highlight #febc2b +%define color_background_highlight_overlay rgba(254, 188, 43, 0.8) +%define color_text_highlight #000 + +%define color_subtext_default lightgray +%define color_subtext_inverse #414141 + %define font_xlarge 5.08mozmm %define font_xnormal 2.75mozmm %define font_normal 2.54mozmm @@ -14,6 +40,7 @@ %define touch_button_xlarge 7.62mozmm %define touch_button_large 6.77mozmm %define touch_button_small 5.93mozmm +%define touch_button_minwidth 11.86mozmm %define touch_action_minwidth 21.17mozmm %define touch_normal 6.77mozmm @@ -68,7 +95,7 @@ %define sidebar_width_minimum 8.47mozmm %define sidebar_button_height 7.41mozmm -%define documenttab_margin_bottom 0.53mozmm +%define documenttab_margin_bottom 0.85mozmm %define placelabel_padding 8.47mozmm %define placeitem_padding 4.23mozmm diff --git a/mobile/android/themes/core/gingerbread/browser.css b/mobile/android/themes/core/gingerbread/browser.css deleted file mode 100644 index 44afd509da3a..000000000000 --- a/mobile/android/themes/core/gingerbread/browser.css +++ /dev/null @@ -1,67 +0,0 @@ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is Mozilla Mobile Browser. - * - * The Initial Developer of the Original Code is - * Mozilla Corporation. - * Portions created by the Initial Developer are Copyright (C) 2008 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Mark Finkle - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -%filter substitution -%include defines.inc - -/* content scrollbars */ -.scroller { - opacity: 0; - background-color: rgba(0, 0, 0, 0.4) !important; - -moz-border-top-colors: none !important; - -moz-border-bottom-colors: none !important; - -moz-border-right-colors: none !important; - -moz-border-left-colors: none !important; - border-radius: @border_radius_tiny@; - border: @border_width_tiny@ solid rgba(255, 255, 255, 0.4) !important; -} - -.scroller[panning="true"] { - opacity: 1; -} - -.scroller[orient="vertical"] { - min-width: @scroller_thickness@; - width: @scroller_thickness@; - min-height: @scroller_minimum@; -} - -.scroller[orient="horizontal"] { - min-height: @scroller_thickness@; - height: @scroller_thickness@; - min-width: @scroller_minimum@; -} diff --git a/mobile/android/themes/core/gingerbread/content.css b/mobile/android/themes/core/gingerbread/content.css deleted file mode 100644 index d16cf9ad65d0..000000000000 --- a/mobile/android/themes/core/gingerbread/content.css +++ /dev/null @@ -1,368 +0,0 @@ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is Mozilla Mobile Browser. - * - * The Initial Developer of the Original Code is - * Mozilla Corporation. - * Portions created by the Initial Developer are Copyright (C) 2008 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Mark Finkle - * Doug Turner - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -%filter substitution -%include defines.inc - -@namespace url("http://www.w3.org/1999/xhtml"); -@namespace xul url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"); - -/* make clicking on links stand out a bit (bug 532206) */ -* > *:not(embed):focus, * > *:focus > font { - outline: 2px solid @color_background_highlight@ !important; - /* - XXX How do I preserve mac focusring without blowing focus color on other platforms? - outline-color: -moz-mac-focusring !important; - */ -} - -*:-moz-any-link:focus { - outline-offset: -2px; -} - -::-moz-selection { - background-color: @color_background_highlight@; - color: @color_text_highlight@; -} - -/* Style the scrollbars */ -html xul|scrollbar { - display: none; -} - -xul|window xul|scrollbar { - display: block; -} - -xul|scrollbar[orient="vertical"] { - -moz-appearance: none !important; - opacity: 0; - position: relative; - margin-left: -8px; - min-width: 8px; - background-color: transparent !important; - background-image: none !important; - border: 0px solid transparent !important; -} - -xul|scrollbar[orient="vertical"]:-moz-locale-dir(rtl) { - margin-left: 2px; - margin-right: -10px; -} - -xul|scrollbar[orient="vertical"] xul|thumb { - max-width: 6px !important; - min-width: 6px !important; -} - -xul|scrollbar[orient="horizontal"] { - -moz-appearance: none !important; - opacity: 0; - position: relative; - min-height: 8px; - margin-top: -8px; - background-color: transparent !important; - background-image: none !important; - border: 0px solid transparent !important; -} - -xul|scrollbar[orient="horizontal"] xul|thumb { - max-height: 6px !important; - min-height: 6px !important; -} - -xul|*[panning="true"] xul|scrollbar { - opacity: 1; -} - -xul|scrollbox { - overflow-y: scroll; - overflow-x: scroll; -} - -xul|scrollbarbutton { - min-height: 8px !important; - min-width: 8px !important; - -moz-appearance: none !important; - visibility: hidden; -} - -xul|scrollbarbutton[sbattr="scrollbar-up-top"], -xul|scrollbarbutton[sbattr="scrollbar-bottom-top"] { - display: none; -} - -xul|scrollbar xul|thumb { - background-color: @color_background_scroller@ !important; - -moz-border-top-colors: none !important; - -moz-border-bottom-colors: none !important; - -moz-border-right-colors: none !important; - -moz-border-left-colors: none !important; - border: 1px solid rgba(255, 255, 255, 0.4) !important; - border-radius: 3px; -} - -select:not([size]):not([multiple]) > xul|scrollbar, -select[size="1"] > xul|scrollbar, -select:not([size]):not([multiple]) xul|scrollbarbutton, -select[size="1"] xul|scrollbarbutton { - display: block; - margin-left: 0; - min-width: 16px; -} - -/* Override inverse OS themes */ -select, -textarea, -button, -xul|button, -* > input:not([type="image"]) { - -moz-appearance: none !important; /* See bug 598421 for fixing the platform */ - border-radius: 3px; -} - -select[size], -select[multiple], -select[size][multiple], -textarea, -* > input:not([type="image"]) { - border-style: solid; - border-color: #7d7d7d; - color: #414141; - background: white -moz-linear-gradient(top, rgba(115,115,115,0.5) 0, rgba(215,215,215,0.5) 3px, rgba(255,255,255,0.2) 16px); -} - -input:-moz-placeholder, -textarea:-moz-placeholder { - color: GrayText; -} - -select:not([size]):not([multiple]), -select[size="0"], -select[size="1"], -* > input[type="button"], -* > input[type="submit"], -* > input[type="reset"], -button { - border-style: solid; - border-color: #7d7d7d; - color: #414141; - background: white -moz-linear-gradient(top, rgba(255,255,255,0.2) 0, rgba(215,215,215,0.5) 18px, rgba(115,115,115,0.5) 100%); -} - -input[type="checkbox"] { - background: white -moz-linear-gradient(top, rgba(115,115,115,0.5) 0, rgba(215,215,215,0.5) 2px, rgba(255,255,255,0.2) 6px); -} - -input[type="radio"] { - background: -moz-radial-gradient(6px 6px, cover, rgba(255,255,255,0.2) 3px, rgba(195,195,195,0.5) 5px, rgba(115,115,115,0.5) 100%); -} - -select { - border-width: 1px; - padding: 1px; -} - -select:not([size]):not([multiple]), -select[size="0"], -select[size="1"] { - padding: 0 1px 0 1px; -} - -* > input:not([type="image"]) { - border-width: 1px; - padding: 1px; -} - -textarea { - resize: none; - border-width: 1px; - padding: 2px 1px 2px 1px; -} - -input[type="button"], -input[type="submit"], -input[type="reset"], -button { - border-width: 1px; - padding: 0 7px 0 7px; -} - -input[type="radio"], -input[type="checkbox"] { - max-width: 14px; - max-height: 14px; - border: 1px solid #a7a7a7 !important; - padding: 2px 1px 2px 1px; -} - -select > button { - border-width: 0px !important; - margin: 0px !important; - padding: 0px !important; - border-radius: 0; - color: #414141; - - background-size: auto auto, 100% 90%; - background-color: transparent; - background-image: url("chrome://browser/skin/images/dropmarker.svg"), - -moz-radial-gradient(bottom left, #bbbbbb 40%, #f5f5f5) !important; - background-position: -moz-calc(50% + 1px) center, -15px center !important; - background-repeat: no-repeat !important; - - font-size: inherit; -} - -select[size]:focus, -select[multiple]:focus, -select[size][multiple]:focus, -textarea:focus, -input[type="file"]:focus > input[type="text"], -* > input:not([type="image"]):focus { - outline: 0px !important; - border-style: solid; - border-color: rgb(94,128,153); - background: white -moz-linear-gradient(top, rgba(27,113,177,0.5) 0, rgba(198,225,246,0.2) 3px, rgba(255,255,255,0.2) 16px); -} - -select:not([size]):not([multiple]):focus, -select[size="0"]:focus, -select[size="1"]:focus, -input[type="button"]:focus, -input[type="submit"]:focus, -input[type="reset"]:focus, -button:focus { - outline: 0px !important; - border-style: solid; - border-color: rgb(94,128,153); - background: white -moz-linear-gradient(top, rgba(255,255,255,0.2) 0, rgba(198,225,256,0.2) 18px, rgba(27,113,177,0.5) 100%); -} - -input[type="checkbox"]:focus, -input[type="radio"]:focus { - border-color: #99c6e0 !important; -} - -input[type="checkbox"]:focus { - background: white -moz-linear-gradient(top, rgba(27,113,177,0.5) 0, rgba(198,225,246,0.2) 2px, rgba(255,255,255,0.2) 6px); -} - -input[type="radio"]:focus { - background: -moz-radial-gradient(6px 6px, cover, rgba(255,255,255,0.2) 3px, rgba(198,225,246,0.2) 5px, rgba(27,113,177,0.5) 100%); -} - -/* we need to be specific for selects because the above rules are specific too */ -textarea[disabled], -select[size][disabled], -select[multiple][disabled], -select[size][multiple][disabled], -select:not([size]):not([multiple])[disabled], -select[size="0"][disabled], -select[size="1"][disabled], -button[disabled], -* > input:not([type="image"])[disabled] { - color: rgba(0,0,0,0.3); - border-color: rgba(125,125,125,0.4); - border-style: solid; - border-width: 1px; - background: transparent -moz-linear-gradient(top, rgba(185,185,185,0.4) 0, rgba(235,235,235,0.4) 3px, rgba(255,255,255,0.4) 100%); -} - -select:not([size]):not([multiple])[disabled], -select[size="0"][disabled], -select[size="1"][disabled] { - background: transparent -moz-linear-gradient(top, rgba(255,255,255,0.4) 0, rgba(235,235,235,0.4) 3px, rgba(185,185,185,0.4) 100%); -} - -input[type="button"][disabled], -input[type="submit"][disabled], -input[type="reset"][disabled], -button[disabled="true"] { - padding: 0 7px 0 7px; - background: transparent -moz-linear-gradient(top, rgba(255,255,255,0.4) 0, rgba(235,235,235,0.4) 3px, rgba(185,185,185,0.4) 100%); -} - -input[type="radio"][disabled], -input[type="radio"][disabled]:active, -input[type="radio"][disabled]:hover, -input[type="radio"][disabled]:hover:active, -input[type="checkbox"][disabled], -input[type="checkbox"][disabled]:active, -input[type="checkbox"][disabled]:hover, -input[type="checkbox"][disabled]:hover:active { - border:1px solid rgba(125,125,125,0.4) !important; -} - -select[disabled] > button { - opacity: 0.6; - padding: 1px 7px 1px 7px; -} - -/* -moz-touch-enabled? media elements */ -video > xul|videocontrols, -audio > xul|videocontrols { - -moz-binding: url("chrome://global/content/bindings/videocontrols.xml#touchControls"); -} - -*:-moz-any-link:active, -*[role=button]:active, -button:active, -input:active, -option:active, -select:active, -label:active, -textarea:active { - background-color: @color_background_highlight_overlay@ !important; -} - -/* - * Generate an additional space after the anonymous div to make it easier to - * to position the caret at the end of the text - */ -input > .anonymous-div:after { - content: ""; - margin: 16px; -} - -/* - * Enforce nearest scaling for video in order not to lose too much performance - * after fixing bug 598736 ("Use higher-quality imageinterpolation on mobile") - */ -video { - image-rendering: -moz-crisp-edges; -} diff --git a/mobile/android/themes/core/gingerbread/defines.inc b/mobile/android/themes/core/gingerbread/defines.inc deleted file mode 100644 index 186aa0a2675b..000000000000 --- a/mobile/android/themes/core/gingerbread/defines.inc +++ /dev/null @@ -1,128 +0,0 @@ -%filter substitution - -%define color_background_active #525252 -%define color_background_default #000 -%define color_text_default #fff -%define color_divider_border #333333 -%define color_button_border #5a5a5a -%define color_dialog_border #5a5a5a -%define color_background_dlgbuttons #9a9a9a -%define color_background_panel #d6d6d6 -%define color_text_panel #000 -%define color_background_header #292929 -%define color_text_header #999999 -%define color_background_scroller #9a9a9a -%define color_background_inverse #fff -%define color_text_inverse #000 -%define color_text_button #000 -%define color_text_disabled #808080 -%define color_text_placeholder #808080 -%define color_text_as_link #febc2b - -%define color_background_highlight #febc2b -%define color_background_highlight_overlay rgba(254, 188, 43, 0.8) -%define color_text_highlight #000 - -%define color_subtext_default lightgray -%define color_subtext_inverse #414141 - -%define font_xlarge 5.08mozmm -%define font_xnormal 2.75mozmm -%define font_normal 2.54mozmm -%define font_snormal 2.33mozmm -%define font_small 1.91mozmm -%define font_xsmall 1.69mozmm -%define font_tiny 1.48mozmm -%define font_xtiny 1.27mozmm -%define font_xxtiny 1.08mozmm - -%define touch_row 7.41mozmm -%define touch_button_xlarge 7.62mozmm -%define touch_button_large 6.77mozmm -%define touch_button_small 5.93mozmm -%define touch_button_minwidth 11.86mozmm -%define touch_action_minwidth 21.17mozmm -%define touch_normal 6.77mozmm - -%define margin_context_popup 3.39mozmm -%define margin_large 2.54mozmm -%define margin_xxxnormal 1.69mozmm -%define margin_xnormal 1.06mozmm -%define margin_normal 0.85mozmm -%define margin_snormal 0.64mozmm -%define margin_small 0.42mozmm -%define margin_tiny 0.21mozmm -%define margin_xtiny 0.15mozmm - -%define padding_xlarge 3.39mozmm -%define padding_large 2.54mozmm -%define padding_xxxnormal 1.69mozmm -%define padding_xxnormal 1.27mozmm -%define padding_xnormal 1.06mozmm -%define padding_normal 0.85mozmm -%define padding_snormal 0.64mozmm -%define padding_small 0.42mozmm -%define padding_xsmall 0.21mozmm -%define padding_tiny 0.11mozmm - -%define border_width_xxlarge 0.64mozmm -%define border_width_xlarge 0.42mozmm -%define border_width_large 0.32mozmm -%define border_width_small 0.21mozmm -%define border_width_tiny 0.11mozmm - -%define border_radius_normal 0.85mozmm -%define border_radius_small 0.64mozmm -%define border_radius_xsmall 0.31mozmm -%define border_radius_tiny 0.21mozmm - -%define shadow_width_xlarge 1.06mozmm -%define shadow_width_large 0.64mozmm -%define shadow_width_small 0.21mozmm - -%define textbox_height 5.08mozmm - -%define dropmarker_padding 0.53mozmm - -%define progressmeter_height 3.39mozmm - -%define urlbar_edit_height 6.35mozmm -%define urlbar_edit_indent 0.85mozmm -%define identity_popup_tablet_width 72mozmm - -%define scroller_thickness 0.64mozmm -%define scroller_minimum 1.27mozmm - -%define sidebar_width_minimum 8.47mozmm -%define sidebar_button_height 7.41mozmm -%define documenttab_margin_bottom 0.85mozmm - -%define placelabel_padding 8.47mozmm -%define placeitem_padding 4.23mozmm - -%define autocomplete_item_container_image_padding 0.53mozmm -%define autocomplete_item_container_position 0.21mozmm -%define autocomplete_item_container_size 2.75mozmm -%define autocomplete_item_container_padding 5.08mozmm - -%define autocomplete_item_subtitle_margin 2.75mozmm -%define autocomplete_item_label_margin 3.18mozmm -%define autocomplete_item_tags_margin 3.39mozmm - -%define autocompleteresult_padding 0.53mozmm - -%define dialog_width 76.2mozmm - -%define appmenu_portrait_height 21.17mozmm -%define appmenu_button_height 10.48mozmm - -%define tablet_panel_controls 40mozmm -%define tablet_panel_minwidth 124mozmm - -%ifdef MOZ_PLATFORM_MAEMO -%define orientation -moz-device-orientation -%elifdef ANDROID -%define orientation -moz-device-orientation -%else -%define orientation orientation -%endif diff --git a/mobile/android/themes/core/gingerbread/images/alert-addons-30.png b/mobile/android/themes/core/gingerbread/images/alert-addons-30.png deleted file mode 100644 index c8c1a8d3a0c2..000000000000 Binary files a/mobile/android/themes/core/gingerbread/images/alert-addons-30.png and /dev/null differ diff --git a/mobile/android/themes/core/gingerbread/images/alert-downloads-30.png b/mobile/android/themes/core/gingerbread/images/alert-downloads-30.png deleted file mode 100644 index 8279c3c92c16..000000000000 Binary files a/mobile/android/themes/core/gingerbread/images/alert-downloads-30.png and /dev/null differ diff --git a/mobile/android/themes/core/gingerbread/images/arrowdown-16.png b/mobile/android/themes/core/gingerbread/images/arrowdown-16.png deleted file mode 100644 index c982426f2ade..000000000000 Binary files a/mobile/android/themes/core/gingerbread/images/arrowdown-16.png and /dev/null differ diff --git a/mobile/android/themes/core/gingerbread/images/arrowleft-16.png b/mobile/android/themes/core/gingerbread/images/arrowleft-16.png deleted file mode 100644 index 464a4a866cd9..000000000000 Binary files a/mobile/android/themes/core/gingerbread/images/arrowleft-16.png and /dev/null differ diff --git a/mobile/android/themes/core/gingerbread/images/arrowright-16.png b/mobile/android/themes/core/gingerbread/images/arrowright-16.png deleted file mode 100644 index 859e98ba64b6..000000000000 Binary files a/mobile/android/themes/core/gingerbread/images/arrowright-16.png and /dev/null differ diff --git a/mobile/android/themes/core/gingerbread/images/errorpage-larry-black.png b/mobile/android/themes/core/gingerbread/images/errorpage-larry-black.png deleted file mode 100644 index 9f2e4a6e7366..000000000000 Binary files a/mobile/android/themes/core/gingerbread/images/errorpage-larry-black.png and /dev/null differ diff --git a/mobile/android/themes/core/gingerbread/images/errorpage-larry-white.png b/mobile/android/themes/core/gingerbread/images/errorpage-larry-white.png deleted file mode 100644 index fc153c7314e8..000000000000 Binary files a/mobile/android/themes/core/gingerbread/images/errorpage-larry-white.png and /dev/null differ diff --git a/mobile/android/themes/core/gingerbread/images/errorpage-warning.png b/mobile/android/themes/core/gingerbread/images/errorpage-warning.png deleted file mode 100644 index 8bf9d8e7decc..000000000000 Binary files a/mobile/android/themes/core/gingerbread/images/errorpage-warning.png and /dev/null differ diff --git a/mobile/android/themes/core/gingerbread/images/forward-default-hdpi.png b/mobile/android/themes/core/gingerbread/images/forward-default-hdpi.png deleted file mode 100644 index 1bfa8012f6d1..000000000000 Binary files a/mobile/android/themes/core/gingerbread/images/forward-default-hdpi.png and /dev/null differ diff --git a/mobile/android/themes/core/gingerbread/images/mute-hdpi.png b/mobile/android/themes/core/gingerbread/images/mute-hdpi.png deleted file mode 100644 index c716ef35cd50..000000000000 Binary files a/mobile/android/themes/core/gingerbread/images/mute-hdpi.png and /dev/null differ diff --git a/mobile/android/themes/core/gingerbread/images/pause-hdpi.png b/mobile/android/themes/core/gingerbread/images/pause-hdpi.png deleted file mode 100644 index 42b36576978b..000000000000 Binary files a/mobile/android/themes/core/gingerbread/images/pause-hdpi.png and /dev/null differ diff --git a/mobile/android/themes/core/gingerbread/images/play-hdpi.png b/mobile/android/themes/core/gingerbread/images/play-hdpi.png deleted file mode 100644 index 7410c99cd5d4..000000000000 Binary files a/mobile/android/themes/core/gingerbread/images/play-hdpi.png and /dev/null differ diff --git a/mobile/android/themes/core/gingerbread/images/popup-selected-item-hdpi.png b/mobile/android/themes/core/gingerbread/images/popup-selected-item-hdpi.png deleted file mode 100644 index a11bd508f685..000000000000 Binary files a/mobile/android/themes/core/gingerbread/images/popup-selected-item-hdpi.png and /dev/null differ diff --git a/mobile/android/themes/core/gingerbread/images/remotetabs-32.png b/mobile/android/themes/core/gingerbread/images/remotetabs-32.png deleted file mode 100644 index 80f59a022c34..000000000000 Binary files a/mobile/android/themes/core/gingerbread/images/remotetabs-32.png and /dev/null differ diff --git a/mobile/android/themes/core/gingerbread/images/scrubber-hdpi.png b/mobile/android/themes/core/gingerbread/images/scrubber-hdpi.png deleted file mode 100644 index 0a2fdd3c7fe3..000000000000 Binary files a/mobile/android/themes/core/gingerbread/images/scrubber-hdpi.png and /dev/null differ diff --git a/mobile/android/themes/core/gingerbread/images/search-clear-30.png b/mobile/android/themes/core/gingerbread/images/search-clear-30.png deleted file mode 100644 index 8bab39a08d35..000000000000 Binary files a/mobile/android/themes/core/gingerbread/images/search-clear-30.png and /dev/null differ diff --git a/mobile/android/themes/core/gingerbread/images/throbber.png b/mobile/android/themes/core/gingerbread/images/throbber.png deleted file mode 100644 index c601ec80ba7c..000000000000 Binary files a/mobile/android/themes/core/gingerbread/images/throbber.png and /dev/null differ diff --git a/mobile/android/themes/core/gingerbread/images/unmute-hdpi.png b/mobile/android/themes/core/gingerbread/images/unmute-hdpi.png deleted file mode 100644 index cf2fb7bfb666..000000000000 Binary files a/mobile/android/themes/core/gingerbread/images/unmute-hdpi.png and /dev/null differ diff --git a/mobile/android/themes/core/gingerbread/images/urlbar-bg.png b/mobile/android/themes/core/gingerbread/images/urlbar-bg.png deleted file mode 100644 index 9dddc7e7363a..000000000000 Binary files a/mobile/android/themes/core/gingerbread/images/urlbar-bg.png and /dev/null differ diff --git a/mobile/android/themes/core/honeycomb/browser.css b/mobile/android/themes/core/honeycomb/browser.css deleted file mode 100644 index 186f23e84457..000000000000 --- a/mobile/android/themes/core/honeycomb/browser.css +++ /dev/null @@ -1,68 +0,0 @@ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is Mozilla Mobile Browser. - * - * The Initial Developer of the Original Code is - * Mozilla Corporation. - * Portions created by the Initial Developer are Copyright (C) 2008 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Mark Finkle - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -%filter substitution -%include defines.inc -%define honeycomb 1 - -/* content scrollbars */ -.scroller { - opacity: 0; - background-color: rgba(0, 0, 0, 0.4) !important; - -moz-border-top-colors: none !important; - -moz-border-bottom-colors: none !important; - -moz-border-right-colors: none !important; - -moz-border-left-colors: none !important; - border-radius: @border_radius_tiny@; - border: @border_width_tiny@ solid rgba(255, 255, 255, 0.4) !important; -} - -.scroller[panning="true"] { - opacity: 1; -} - -.scroller[orient="vertical"] { - min-width: @scroller_thickness@; - width: @scroller_thickness@; - min-height: @scroller_minimum@; -} - -.scroller[orient="horizontal"] { - min-height: @scroller_thickness@; - height: @scroller_thickness@; - min-width: @scroller_minimum@; -} diff --git a/mobile/android/themes/core/honeycomb/defines.inc b/mobile/android/themes/core/honeycomb/defines.inc deleted file mode 100644 index 309a6c824804..000000000000 --- a/mobile/android/themes/core/honeycomb/defines.inc +++ /dev/null @@ -1,165 +0,0 @@ -%filter substitution - -%define color_background_active #fff -%define color_text_active #222222 -%define color_background_default_window #fff -%define color_background_default rgba(255,255,255,0.95) -%define color_text_default #222222 -%define color_toolbar_background #eaeaea -%define color_toolbar_border #d9d9d9 -%define color_divider_border #6699ff -%define color_url_border #737373 -%define color_background_button #d9d9d9 -%define color_background_button_disabled #e3e3e3 -%define color_background_button_overlay rgba(217, 217, 217, 0.8) -%define color_button_border rgb(207,207,207) -%define color_background_dialog #fff -%define color_text_dialog #000 -%define color_dialog_border #5a5a5a -%define color_background_dlgbuttons #9a9a9a -%define color_background_panel #d6d6d6 -%define color_text_panel #000 -%define color_background_header #6699ff -%define color_text_header #fff -%define color_background_scroller #9a9a9a -%define color_background_textbox #fff -%define color_text_textbox #000 -%define color_text_disabled #808080 -%define color_text_button #222 -%define color_text_button_disabled #999 -%define color_text_placeholder #808080 -%define color_text_as_link #69f -%define color_background_panelrow #c8c8c8 -%define color_text_panelrow #222222 -%define color_text_toolbutton_inverse #666666 -%define color_background_settings #efefef -%define color_text_panel_header #999 -%define color_text_panel_subheader #333 -%define color_background_toaster #000 - -%define color_background_highlight #a7c5f4 -%define color_background_highlight_overlay rgba(167, 197, 244, 0.8) -%define color_text_highlight #000 -%define color_selection #c0e49a -%define color_shadow #6699ff -%define color_shadow_light rgba(102,153,255, 0.2) -%define color_shadow_green rgba(137,251,21, 0.2) -%define color_shadow_grey rgba(200,200,200, 0.5) - -%define color_subtext_default #aaaaaa -%define color_subtext_settings #666666 - -%define font_xlarge 6.08mozmm -%define font_xnormal 3.75mozmm -%define font_normal 3.54mozmm -%define font_snormal 3mozmm -%define font_small 2.91mozmm -%define font_xsmall 2.69mozmm -%define font_tiny 2.48mozmm -%define font_xtiny 2.27mozmm -%define font_xxtiny 1.93mozmm - -%define touch_row 10.478mozmm -%define touch_button_xlarge 10.62mozmm -%define touch_button_large 9.77mozmm -%define touch_button_small 8.93mozmm -%define touch_button_minwidth 11.86mozmm -%define touch_action_minwidth 21.17mozmm -%define touch_button_tiny 3.75mozmm -%define touch_button_minwidth 16.30mozmm -%define touch_button_minwidth 11.86mozmm -%define touch_normal 6.77mozmm - -%define margin_toaster 15.24mozmm -%define margin_context_popup 3.39mozmm -%define margin_xlarge 3.39mozmm -%define margin_large 2.54mozmm -%define margin_xxxnormal 1.69mozmm -%define margin_xxnormal 1.27mozmm -%define margin_xnormal 1.06mozmm -%define margin_normal 0.85mozmm -%define margin_snormal 0.64mozmm -%define margin_small 0.42mozmm -%define margin_tiny 0.21mozmm -%define margin_xtiny 0.15mozmm - -%define padding_xxxlarge 13.35mozmm -%define padding_xxlarge 7.938mozmm -%define padding_xlarge 3.39mozmm -%define padding_large 2.54mozmm -%define padding_xxxnormal 1.69mozmm -%define padding_xxnormal 1.27mozmm -%define padding_xnormal 1.06mozmm -%define padding_normal 0.85mozmm -%define padding_snormal 0.64mozmm -%define padding_small 0.42mozmm -%define padding_xsmall 0.21mozmm -%define padding_tiny 0.11mozmm - -%define border_width_xxlarge 0.64mozmm -%define border_width_xlarge 0.42mozmm -%define border_width_large 0.32mozmm -%define border_width_small 0.21mozmm -%define border_width_tiny 0.11mozmm - -%define border_radius_normal 0.85mozmm -%define border_radius_small 0.64mozmm -%define border_radius_xsmall 0.31mozmm -%define border_radius_tiny 0.21mozmm - -%define shadow_width_xlarge 3.06mozmm -%define shadow_width_large 2.64mozmm -%define shadow_width_medium 0.75mozmm -%define shadow_width_small 0.21mozmm -%define shadow_width_tiny 0.1mozmm - -%define textbox_height 5.08mozmm - -%define dropmarker_padding 0.53mozmm - -%define progressmeter_height 3.39mozmm - -%define urlbar_edit_height 5.25mozmm -%define urlbar_edit_indent 0.85mozmm -%define identity_popup_tablet_width 72mozmm - -%define scroller_thickness 0.64mozmm -%define scroller_minimum 1.27mozmm - -%define sidebar_width_minimum 8.47mozmm -%define sidebar_button_height 7.41mozmm -%define documenttab_margin_bottom 0.85mozmm - -%define placelabel_padding 8.47mozmm -%define placeitem_padding 4.23mozmm - -%define awesome_header_maxwidth 25mozmm -%define autocomplete_item_container_image_padding 0.53mozmm -%define autocomplete_item_container_position 0.21mozmm -%define autocomplete_item_container_size 4mozmm -%define autocomplete_item_container_padding 5.08mozmm - -%define autocomplete_item_subtitle_margin 2.75mozmm -%define autocomplete_item_label_margin 3.18mozmm -%define autocomplete_item_tags_margin 3.39mozmm - -%define autocompleteresult_padding 0.53mozmm - -%define dialog_width 76.2mozmm - -%define appmenu_portrait_height 21.17mozmm -%define appmenu_button_height 10.48mozmm - -%define tablet_panel_controls 40mozmm -%define tablet_panel_controls_wide 55mozmm -%define tablet_panel_minwidth 124mozmm -%define tablet_panel_item_width 69mozmm -%define tablet_panel_item_width_wide 90mozmm - -%ifdef MOZ_PLATFORM_MAEMO -%define orientation -moz-device-orientation -%elifdef ANDROID -%define orientation -moz-device-orientation -%else -%define orientation orientation -%endif diff --git a/mobile/android/themes/core/honeycomb/images/alert-addons-30.png b/mobile/android/themes/core/honeycomb/images/alert-addons-30.png deleted file mode 100644 index 18744ad85224..000000000000 Binary files a/mobile/android/themes/core/honeycomb/images/alert-addons-30.png and /dev/null differ diff --git a/mobile/android/themes/core/honeycomb/images/alert-downloads-30.png b/mobile/android/themes/core/honeycomb/images/alert-downloads-30.png deleted file mode 100644 index 2546352d28f4..000000000000 Binary files a/mobile/android/themes/core/honeycomb/images/alert-downloads-30.png and /dev/null differ diff --git a/mobile/android/themes/core/honeycomb/images/arrowdown-16.png b/mobile/android/themes/core/honeycomb/images/arrowdown-16.png deleted file mode 100644 index c982426f2ade..000000000000 Binary files a/mobile/android/themes/core/honeycomb/images/arrowdown-16.png and /dev/null differ diff --git a/mobile/android/themes/core/honeycomb/images/arrowleft-16.png b/mobile/android/themes/core/honeycomb/images/arrowleft-16.png deleted file mode 100644 index 464a4a866cd9..000000000000 Binary files a/mobile/android/themes/core/honeycomb/images/arrowleft-16.png and /dev/null differ diff --git a/mobile/android/themes/core/honeycomb/images/arrowright-16.png b/mobile/android/themes/core/honeycomb/images/arrowright-16.png deleted file mode 100644 index 859e98ba64b6..000000000000 Binary files a/mobile/android/themes/core/honeycomb/images/arrowright-16.png and /dev/null differ diff --git a/mobile/android/themes/core/honeycomb/images/errorpage-larry-black.png b/mobile/android/themes/core/honeycomb/images/errorpage-larry-black.png deleted file mode 100644 index 9f2e4a6e7366..000000000000 Binary files a/mobile/android/themes/core/honeycomb/images/errorpage-larry-black.png and /dev/null differ diff --git a/mobile/android/themes/core/honeycomb/images/errorpage-larry-white.png b/mobile/android/themes/core/honeycomb/images/errorpage-larry-white.png deleted file mode 100644 index fc153c7314e8..000000000000 Binary files a/mobile/android/themes/core/honeycomb/images/errorpage-larry-white.png and /dev/null differ diff --git a/mobile/android/themes/core/honeycomb/images/errorpage-warning.png b/mobile/android/themes/core/honeycomb/images/errorpage-warning.png deleted file mode 100644 index 8bf9d8e7decc..000000000000 Binary files a/mobile/android/themes/core/honeycomb/images/errorpage-warning.png and /dev/null differ diff --git a/mobile/android/themes/core/honeycomb/images/forward-default-hdpi.png b/mobile/android/themes/core/honeycomb/images/forward-default-hdpi.png deleted file mode 100644 index 57611d4dc202..000000000000 Binary files a/mobile/android/themes/core/honeycomb/images/forward-default-hdpi.png and /dev/null differ diff --git a/mobile/android/themes/core/honeycomb/images/mute-hdpi.png b/mobile/android/themes/core/honeycomb/images/mute-hdpi.png deleted file mode 100644 index 0bd1e60e6a3e..000000000000 Binary files a/mobile/android/themes/core/honeycomb/images/mute-hdpi.png and /dev/null differ diff --git a/mobile/android/themes/core/honeycomb/images/pause-hdpi.png b/mobile/android/themes/core/honeycomb/images/pause-hdpi.png deleted file mode 100644 index e377d321ce03..000000000000 Binary files a/mobile/android/themes/core/honeycomb/images/pause-hdpi.png and /dev/null differ diff --git a/mobile/android/themes/core/honeycomb/images/play-hdpi.png b/mobile/android/themes/core/honeycomb/images/play-hdpi.png deleted file mode 100644 index a8482eb4dd7e..000000000000 Binary files a/mobile/android/themes/core/honeycomb/images/play-hdpi.png and /dev/null differ diff --git a/mobile/android/themes/core/honeycomb/images/popup-selected-item-hdpi.png b/mobile/android/themes/core/honeycomb/images/popup-selected-item-hdpi.png deleted file mode 100644 index dd511023c1fa..000000000000 Binary files a/mobile/android/themes/core/honeycomb/images/popup-selected-item-hdpi.png and /dev/null differ diff --git a/mobile/android/themes/core/honeycomb/images/remotetabs-32.png b/mobile/android/themes/core/honeycomb/images/remotetabs-32.png deleted file mode 100644 index 80f59a022c34..000000000000 Binary files a/mobile/android/themes/core/honeycomb/images/remotetabs-32.png and /dev/null differ diff --git a/mobile/android/themes/core/honeycomb/images/scrubber-hdpi.png b/mobile/android/themes/core/honeycomb/images/scrubber-hdpi.png deleted file mode 100644 index 49c60505f465..000000000000 Binary files a/mobile/android/themes/core/honeycomb/images/scrubber-hdpi.png and /dev/null differ diff --git a/mobile/android/themes/core/honeycomb/images/search-clear-30.png b/mobile/android/themes/core/honeycomb/images/search-clear-30.png deleted file mode 100644 index 8bab39a08d35..000000000000 Binary files a/mobile/android/themes/core/honeycomb/images/search-clear-30.png and /dev/null differ diff --git a/mobile/android/themes/core/honeycomb/images/sidebarbutton-active-hdpi.png b/mobile/android/themes/core/honeycomb/images/sidebarbutton-active-hdpi.png deleted file mode 100644 index 30f1d2017bc6..000000000000 Binary files a/mobile/android/themes/core/honeycomb/images/sidebarbutton-active-hdpi.png and /dev/null differ diff --git a/mobile/android/themes/core/honeycomb/images/throbber.png b/mobile/android/themes/core/honeycomb/images/throbber.png deleted file mode 100644 index c601ec80ba7c..000000000000 Binary files a/mobile/android/themes/core/honeycomb/images/throbber.png and /dev/null differ diff --git a/mobile/android/themes/core/honeycomb/images/unmute-hdpi.png b/mobile/android/themes/core/honeycomb/images/unmute-hdpi.png deleted file mode 100644 index 4dbb94f98f0a..000000000000 Binary files a/mobile/android/themes/core/honeycomb/images/unmute-hdpi.png and /dev/null differ diff --git a/mobile/android/themes/core/images/alert-addons-30.png b/mobile/android/themes/core/images/alert-addons-30.png deleted file mode 100644 index 18744ad85224..000000000000 Binary files a/mobile/android/themes/core/images/alert-addons-30.png and /dev/null differ diff --git a/mobile/android/themes/core/images/alert-downloads-30.png b/mobile/android/themes/core/images/alert-downloads-30.png deleted file mode 100644 index 2546352d28f4..000000000000 Binary files a/mobile/android/themes/core/images/alert-downloads-30.png and /dev/null differ diff --git a/mobile/android/themes/core/images/forward-default-hdpi.png b/mobile/android/themes/core/images/forward-default-hdpi.png deleted file mode 100644 index 4bcf5010976b..000000000000 Binary files a/mobile/android/themes/core/images/forward-default-hdpi.png and /dev/null differ diff --git a/mobile/android/themes/core/images/popup-selected-item-hdpi.png b/mobile/android/themes/core/images/popup-selected-item-hdpi.png deleted file mode 100644 index dd511023c1fa..000000000000 Binary files a/mobile/android/themes/core/images/popup-selected-item-hdpi.png and /dev/null differ diff --git a/mobile/android/themes/core/images/remotetabs-32.png b/mobile/android/themes/core/images/remotetabs-32.png deleted file mode 100644 index 80f59a022c34..000000000000 Binary files a/mobile/android/themes/core/images/remotetabs-32.png and /dev/null differ diff --git a/mobile/android/themes/core/images/sidebarbutton-active-hdpi.png b/mobile/android/themes/core/images/sidebarbutton-active-hdpi.png deleted file mode 100644 index 30f1d2017bc6..000000000000 Binary files a/mobile/android/themes/core/images/sidebarbutton-active-hdpi.png and /dev/null differ diff --git a/mobile/android/themes/core/jar.mn b/mobile/android/themes/core/jar.mn index e8cac0857dfa..4b308be2c87b 100644 --- a/mobile/android/themes/core/jar.mn +++ b/mobile/android/themes/core/jar.mn @@ -1,11 +1,7 @@ #filter substitution chrome.jar: -% skin browser classic/1.0 %skin/ os!=Android -% skin browser classic/1.0 %skin/ os=Android osversion<2.3 -% skin browser froyo/1.0 %skin/ -# NOTE: If you add a new file here, you'll need to add it to the gingerbread -# and honeycomb sections at the bottom of this file +% skin browser classic/1.0 %skin/ skin/aboutPage.css (aboutPage.css) skin/about.css (about.css) skin/aboutAddons.css (aboutAddons.css) @@ -29,17 +25,11 @@ chrome.jar: skin/images/checkbox_unchecked_disabled.png (images/checkbox_unchecked_disabled.png) skin/images/checkbox_unchecked_pressed.png (images/checkbox_unchecked_pressed.png) skin/images/dropmarker.svg (images/dropmarker.svg) - skin/images/popup-selected-item-hdpi.png (images/popup-selected-item-hdpi.png) skin/images/errorpage-warning.png (images/errorpage-warning.png) skin/images/errorpage-warning.png (images/errorpage-warning.png) skin/images/errorpage-larry-white.png (images/errorpage-larry-white.png) skin/images/errorpage-larry-black.png (images/errorpage-larry-black.png) skin/images/throbber.png (images/throbber.png) - skin/images/alert-addons-30.png (images/alert-addons-30.png) - skin/images/alert-downloads-30.png (images/alert-downloads-30.png) - skin/images/forward-default-hdpi.png (images/forward-default-hdpi.png) - skin/images/remotetabs-32.png (images/remotetabs-32.png) - skin/images/sidebarbutton-active-hdpi.png (images/sidebarbutton-active-hdpi.png) skin/images/search-clear-30.png (images/search-clear-30.png) skin/images/play-hdpi.png (images/play-hdpi.png) skin/images/pause-hdpi.png (images/pause-hdpi.png) @@ -54,105 +44,3 @@ chrome.jar: skin/images/row-bg-light.png (images/row-bg-light.png) skin/images/row-bg-normal.png (images/row-bg-normal.png) skin/images/addons-amo-hdpi.png (images/addons-amo-hdpi.png) - -chrome.jar: -% skin browser classic/1.0 %skin/gingerbread/ os=Android osversion=2.3 osversion=2.3.3 osversion=2.3.4 osversion=2.3.5 osversion=2.3.6 osversion=2.3.7 -% skin browser gingerbread/1.0 %skin/gingerbread/ - skin/gingerbread/aboutPage.css (aboutPage.css) - skin/gingerbread/about.css (about.css) - skin/gingerbread/aboutAddons.css (aboutAddons.css) -* skin/gingerbread/browser.css (gingerbread/browser.css) -* skin/gingerbread/content.css (gingerbread/content.css) - skin/gingerbread/config.css (config.css) - skin/gingerbread/touchcontrols.css (touchcontrols.css) - skin/gingerbread/netError.css (netError.css) -% override chrome://global/skin/about.css chrome://browser/skin/about.css -% override chrome://global/skin/media/videocontrols.css chrome://browser/skin/touchcontrols.css -% override chrome://global/skin/netError.css chrome://browser/skin/netError.css - - skin/gingerbread/images/urlbar-bg.png (gingerbread/images/urlbar-bg.png) - skin/gingerbread/images/addons-32.png (images/addons-32.png) - skin/gingerbread/images/arrowleft-16.png (gingerbread/images/arrowleft-16.png) - skin/gingerbread/images/arrowright-16.png (gingerbread/images/arrowright-16.png) - skin/gingerbread/images/arrowdown-16.png (gingerbread/images/arrowdown-16.png) - skin/gingerbread/images/checkbox_checked.png (images/checkbox_checked.png) - skin/gingerbread/images/checkbox_checked_disabled.png (images/checkbox_checked_disabled.png) - skin/gingerbread/images/checkbox_checked_pressed.png (images/checkbox_checked_pressed.png) - skin/gingerbread/images/checkbox_unchecked.png (images/checkbox_unchecked.png) - skin/gingerbread/images/checkbox_unchecked_disabled.png (images/checkbox_unchecked_disabled.png) - skin/gingerbread/images/checkbox_unchecked_pressed.png (images/checkbox_unchecked_pressed.png) - skin/gingerbread/images/dropmarker.svg (images/dropmarker.svg) - skin/gingerbread/images/popup-selected-item-hdpi.png (gingerbread/images/popup-selected-item-hdpi.png) - skin/gingerbread/images/throbber.png (gingerbread/images/throbber.png) - skin/gingerbread/images/alert-addons-30.png (gingerbread/images/alert-addons-30.png) - skin/gingerbread/images/alert-downloads-30.png (gingerbread/images/alert-downloads-30.png) - skin/gingerbread/images/forward-default-hdpi.png (gingerbread/images/forward-default-hdpi.png) - skin/gingerbread/images/remotetabs-32.png (gingerbread/images/remotetabs-32.png) - skin/gingerbread/images/search-clear-30.png (gingerbread/images/search-clear-30.png) - skin/gingerbread/images/play-hdpi.png (gingerbread/images/play-hdpi.png) - skin/gingerbread/images/pause-hdpi.png (gingerbread/images/pause-hdpi.png) - skin/gingerbread/images/mute-hdpi.png (gingerbread/images/mute-hdpi.png) - skin/gingerbread/images/unmute-hdpi.png (gingerbread/images/unmute-hdpi.png) - skin/gingerbread/images/scrubber-hdpi.png (gingerbread/images/scrubber-hdpi.png) - skin/gingerbread/images/errorpage-warning.png (images/errorpage-warning.png) - skin/gingerbread/images/errorpage-larry-white.png (images/errorpage-larry-white.png) - skin/gingerbread/images/errorpage-larry-black.png (images/errorpage-larry-black.png) - skin/gingerbread/images/about-bg-lightblue.png (images/about-bg-lightblue.png) - skin/gingerbread/images/about-bg-darkblue.png (images/about-bg-darkblue.png) - skin/gingerbread/images/about-btn-darkgrey.png (images/about-btn-darkgrey.png) - skin/gingerbread/images/logo-hdpi.png (images/logo-hdpi.png) - skin/gingerbread/images/wordmark-hdpi.png (images/wordmark-hdpi.png) - skin/gingerbread/images/row-bg-light.png (images/row-bg-light.png) - skin/gingerbread/images/row-bg-normal.png (images/row-bg-normal.png) - skin/gingerbread/images/addons-amo-hdpi.png (images/addons-amo-hdpi.png) - -chrome.jar: -% skin browser classic/1.0 %skin/honeycomb/ os=Android osversion>=3.0 -% skin browser honeycomb/1.0 %skin/honeycomb/ - skin/honeycomb/aboutPage.css (aboutPage.css) - skin/honeycomb/about.css (about.css) - skin/honeycomb/aboutAddons.css (aboutAddons.css) -* skin/honeycomb/browser.css (honeycomb/browser.css) -* skin/honeycomb/content.css (content.css) - skin/honeycomb/config.css (config.css) - skin/honeycomb/touchcontrols.css (touchcontrols.css) - skin/honeycomb/netError.css (netError.css) -% override chrome://global/skin/about.css chrome://browser/skin/about.css -% override chrome://global/skin/media/videocontrols.css chrome://browser/skin/touchcontrols.css -% override chrome://global/skin/netError.css chrome://browser/skin/netError.css - - skin/honeycomb/images/addons-32.png (images/addons-32.png) - skin/honeycomb/images/arrowleft-16.png (honeycomb/images/arrowleft-16.png) - skin/honeycomb/images/arrowright-16.png (honeycomb/images/arrowright-16.png) - skin/honeycomb/images/arrowdown-16.png (honeycomb/images/arrowdown-16.png) - skin/honeycomb/images/checkbox_checked.png (images/checkbox_checked.png) - skin/honeycomb/images/checkbox_checked_disabled.png (images/checkbox_checked_disabled.png) - skin/honeycomb/images/checkbox_checked_pressed.png (images/checkbox_checked_pressed.png) - skin/honeycomb/images/checkbox_unchecked.png (images/checkbox_unchecked.png) - skin/honeycomb/images/checkbox_unchecked_disabled.png (images/checkbox_unchecked_disabled.png) - skin/honeycomb/images/checkbox_unchecked_pressed.png (images/checkbox_unchecked_pressed.png) - skin/honeycomb/images/dropmarker.svg (images/dropmarker.svg) - skin/honeycomb/images/popup-selected-item-hdpi.png (honeycomb/images/popup-selected-item-hdpi.png) - skin/honeycomb/images/throbber.png (honeycomb/images/throbber.png) - skin/honeycomb/images/alert-addons-30.png (honeycomb/images/alert-addons-30.png) - skin/honeycomb/images/alert-downloads-30.png (honeycomb/images/alert-downloads-30.png) - skin/honeycomb/images/forward-default-hdpi.png (honeycomb/images/forward-default-hdpi.png) - skin/honeycomb/images/remotetabs-32.png (honeycomb/images/remotetabs-32.png) - skin/honeycomb/images/sidebarbutton-active-hdpi.png (honeycomb/images/sidebarbutton-active-hdpi.png) - skin/honeycomb/images/search-clear-30.png (honeycomb/images/search-clear-30.png) - skin/honeycomb/images/play-hdpi.png (honeycomb/images/play-hdpi.png) - skin/honeycomb/images/pause-hdpi.png (honeycomb/images/pause-hdpi.png) - skin/honeycomb/images/mute-hdpi.png (honeycomb/images/mute-hdpi.png) - skin/honeycomb/images/unmute-hdpi.png (honeycomb/images/unmute-hdpi.png) - skin/honeycomb/images/scrubber-hdpi.png (honeycomb/images/scrubber-hdpi.png) - skin/honeycomb/images/errorpage-warning.png (images/errorpage-warning.png) - skin/honeycomb/images/errorpage-larry-white.png (images/errorpage-larry-white.png) - skin/honeycomb/images/errorpage-larry-black.png (images/errorpage-larry-black.png) - skin/honeycomb/images/about-bg-lightblue.png (images/about-bg-lightblue.png) - skin/honeycomb/images/about-bg-darkblue.png (images/about-bg-darkblue.png) - skin/honeycomb/images/about-btn-darkgrey.png (images/about-btn-darkgrey.png) - skin/honeycomb/images/logo-hdpi.png (images/logo-hdpi.png) - skin/honeycomb/images/wordmark-hdpi.png (images/wordmark-hdpi.png) - skin/honeycomb/images/row-bg-light.png (images/row-bg-light.png) - skin/honeycomb/images/row-bg-normal.png (images/row-bg-normal.png) - skin/honeycomb/images/addons-amo-hdpi.png (images/addons-amo-hdpi.png) diff --git a/netwerk/dns/effective_tld_names.dat b/netwerk/dns/effective_tld_names.dat index 7fbce465e982..0df8800db08a 100644 --- a/netwerk/dns/effective_tld_names.dat +++ b/netwerk/dns/effective_tld_names.dat @@ -3703,6 +3703,9 @@ poznan.pl wroc.pl zakopane.pl +// pm : http://www.afnic.fr/medias/documents/AFNIC-naming-policy2012.pdf +pm + // pn : http://www.government.pn/PnRegistry/policies.htm pn gov.pn @@ -4682,6 +4685,9 @@ health.vn // list of 2nd level tlds ? vu +// wf : http://www.afnic.fr/medias/documents/AFNIC-naming-policy2012.pdf +wf + // ws : http://en.wikipedia.org/wiki/.ws // http://samoanic.ws/index.dhtml ws @@ -4691,6 +4697,9 @@ org.ws gov.ws edu.ws +// yt : http://www.afnic.fr/medias/documents/AFNIC-naming-policy2012.pdf +yt + // IDN ccTLDs // Please sort by ISO 3166 ccTLD, then punicode string // when submitting patches and follow this format: diff --git a/netwerk/mime/nsMIMEHeaderParamImpl.cpp b/netwerk/mime/nsMIMEHeaderParamImpl.cpp index 78d560b78e09..2ea2e40e26e5 100644 --- a/netwerk/mime/nsMIMEHeaderParamImpl.cpp +++ b/netwerk/mime/nsMIMEHeaderParamImpl.cpp @@ -169,6 +169,136 @@ void RemoveQuotedStringEscapes(char *src) *dst = 0; } +// Support for continuations (RFC 2231, Section 3) + +// only a sane number supported +#define MAX_CONTINUATIONS 999 + +// part of a continuation + +class Continuation { + public: + Continuation(const char *aValue, PRUint32 aLength, + bool aNeedsPercentDecoding) { + value = aValue; + length = aLength; + needsPercentDecoding = aNeedsPercentDecoding; + } + Continuation() { + // empty constructor needed for nsTArray + value = 0L; + length = 0; + needsPercentDecoding = false; + } + ~Continuation() {} + + const char *value; + PRUint32 length; + bool needsPercentDecoding; +}; + +// combine segments into a single string, returning the allocated string +// (or NULL) while emptying the list +char *combineContinuations(nsTArray& aArray) +{ + // Sanity check + if (aArray.Length() == 0) + return NULL; + + // Get an upper bound for the length + PRUint32 length = 0; + for (PRUint32 i = 0; i < aArray.Length(); i++) { + length += aArray[i].length; + } + + // Allocate + char *result = (char *) nsMemory::Alloc(length + 1); + + // Concatenate + if (result) { + *result = '\0'; + + for (PRUint32 i = 0; i < aArray.Length(); i++) { + Continuation cont = aArray[i]; + if (! cont.value) break; + + char *c = result + strlen(result); + strncat(result, cont.value, cont.length); + if (cont.needsPercentDecoding) { + nsUnescape(c); + } + } + + // return null if empty value + if (*result == '\0') { + nsMemory::Free(result); + result = NULL; + } + } else { + // Handle OOM + NS_WARNING("Out of memory\n"); + } + + return result; +} + +// add a continuation, return false on error if segment already has been seen +bool addContinuation(nsTArray& aArray, PRUint32 aIndex, + const char *aValue, PRUint32 aLength, + bool aNeedsPercentDecoding) +{ + if (aIndex < aArray.Length() && aArray[aIndex].value) { + NS_WARNING("duplicate RC2231 continuation segment #\n"); + return false; + } + + if (aIndex > MAX_CONTINUATIONS) { + NS_WARNING("RC2231 continuation segment # exceeds limit\n"); + return false; + } + + Continuation cont (aValue, aLength, aNeedsPercentDecoding); + + if (aArray.Length() <= aIndex) { + aArray.SetLength(aIndex + 1); + } + aArray[aIndex] = cont; + + return true; +} + +// parse a segment number; return -1 on error +PRInt32 parseSegmentNumber(const char *aValue, PRInt32 aLen) +{ + if (aLen < 1) { + NS_WARNING("segment number missing\n"); + return -1; + } + + if (aLen > 1 && aValue[0] == '0') { + NS_WARNING("leading '0' not allowed in segment number\n"); + return -1; + } + + PRInt32 segmentNumber = 0; + + for (PRInt32 i = 0; i < aLen; i++) { + if (! (aValue[i] >= '0' && aValue[i] <= '9')) { + NS_WARNING("invalid characters in segment number\n"); + return -1; + } + + segmentNumber *= 10; + segmentNumber += aValue[i] - '0'; + if (segmentNumber > MAX_CONTINUATIONS) { + NS_WARNING("Segment number exceeds sane size\n"); + return -1; + } + } + + return segmentNumber; +} + // moved almost verbatim from mimehdrs.cpp // char * // MimeHeaders_get_parameter (const char *header_value, const char *parm_name, @@ -205,6 +335,10 @@ nsMIMEHeaderParamImpl::DoParameterInternal(const char *aHeaderValue, if (aCharset) *aCharset = nsnull; if (aLang) *aLang = nsnull; + nsCAutoString charset; + + bool acceptContinuations = (aDecoding != RFC_5987_DECODING); + const char *str = aHeaderValue; // skip leading white space. @@ -255,37 +389,55 @@ nsMIMEHeaderParamImpl::DoParameterInternal(const char *aHeaderValue, // title*1="There is no charset and lang info." // RFC5987: only A and B + // collect results for the different algorithms (plain filename, + // RFC5987/2231-encoded filename, + continuations) separately and decide + // which to use at the end + char *caseAResult = NULL; + char *caseBResult = NULL; + char *caseCDResult = NULL; + + // collect continuation segments + nsTArray segments; + + + // our copies of the charset parameter, kept separately as they might + // differ for the two formats + nsDependentCSubstring charsetB, charsetCD; + + nsDependentCSubstring lang; + PRInt32 paramLen = strlen(aParamName); - bool haveCaseAValue = false; - PRInt32 nextContinuation = 0; // next value in series, or -1 if error - while (*str) { - const char *tokenStart = str; - const char *tokenEnd = 0; + // find name/value + + const char *nameStart = str; + const char *nameEnd = NULL; const char *valueStart = str; - const char *valueEnd = 0; - bool seenEquals = false; + const char *valueEnd = NULL; + bool isQuotedString = false; NS_ASSERTION(!nsCRT::IsAsciiSpace(*str), "should be after whitespace."); // Skip forward to the end of this token. for (; *str && !nsCRT::IsAsciiSpace(*str) && *str != '=' && *str != ';'; str++) ; - tokenEnd = str; + nameEnd = str; + + PRInt32 nameLen = nameEnd - nameStart; // Skip over whitespace, '=', and whitespace while (nsCRT::IsAsciiSpace(*str)) ++str; - if (*str == '=') { - ++str; - seenEquals = true; + if (!*str) { + break; + } + if (*str++ != '=') { + // don't accept parameters without "=" + goto increment_str; } while (nsCRT::IsAsciiSpace(*str)) ++str; - bool needUnquote = false; - - if (*str != '"') - { + if (*str != '"') { // The value is a token, not a quoted string. valueStart = str; for (valueEnd = str; @@ -293,16 +445,12 @@ nsMIMEHeaderParamImpl::DoParameterInternal(const char *aHeaderValue, valueEnd++) ; str = valueEnd; - } - else - { - // The value is a quoted string. - needUnquote = true; + } else { + isQuotedString = true; ++str; valueStart = str; - for (valueEnd = str; *valueEnd; ++valueEnd) - { + for (valueEnd = str; *valueEnd; ++valueEnd) { if (*valueEnd == '\\') ++valueEnd; else if (*valueEnd == '"') @@ -317,16 +465,14 @@ nsMIMEHeaderParamImpl::DoParameterInternal(const char *aHeaderValue, // See if this is the simplest case (case A above), // a 'single' line value with no charset and lang. // If so, copy it and return. - if (tokenEnd - tokenStart == paramLen && - seenEquals && - !nsCRT::strncasecmp(tokenStart, aParamName, paramLen)) - { - if (*aResult) - { - // either seen earlier caseA value already--we prefer first--or caseA - // came after a continuation: either way, prefer other value + if (nameLen == paramLen && + !nsCRT::strncasecmp(nameStart, aParamName, paramLen)) { + + if (caseAResult) { + // we already have one caseA result, ignore subsequent ones goto increment_str; } + // if the parameter spans across multiple lines we have to strip out the // line continuation -- jht 4/29/98 nsCAutoString tempStr(valueStart, valueEnd - valueStart); @@ -334,144 +480,131 @@ nsMIMEHeaderParamImpl::DoParameterInternal(const char *aHeaderValue, char *res = ToNewCString(tempStr); NS_ENSURE_TRUE(res, NS_ERROR_OUT_OF_MEMORY); - if (needUnquote) + if (isQuotedString) RemoveQuotedStringEscapes(res); - - *aResult = res; - - haveCaseAValue = true; + + caseAResult = res; // keep going, we may find a RFC 2231/5987 encoded alternative } // case B, C, and D - else if (tokenEnd - tokenStart > paramLen && - !nsCRT::strncasecmp(tokenStart, aParamName, paramLen) && - seenEquals && - *(tokenStart + paramLen) == '*') - { - const char *cp = tokenStart + paramLen + 1; // 1st char past '*' - bool needUnescape = *(tokenEnd - 1) == '*'; + else if (nameLen > paramLen && + !nsCRT::strncasecmp(nameStart, aParamName, paramLen) && + *(nameStart + paramLen) == '*') { + + // 1st char past '*' + const char *cp = nameStart + paramLen + 1; + + // if param name ends in "*" we need do to RFC5987 "ext-value" decoding + bool needExtDecoding = *(nameEnd - 1) == '*'; + + bool caseB = nameLen == paramLen + 1; + bool caseCStart = (*cp == '0') && needExtDecoding; + + // parse the segment number + PRInt32 segmentNumber = -1; + if (!caseB) { + PRInt32 segLen = (nameEnd - cp) - (needExtDecoding ? 1 : 0); + segmentNumber = parseSegmentNumber(cp, segLen); + + if (segmentNumber == -1) { + acceptContinuations = false; + goto increment_str; + } + } - bool caseB = (tokenEnd - tokenStart) == paramLen + 1; - bool caseCorDStart = (*cp == '0') && needUnescape; - bool acceptContinuations = (aDecoding != RFC_5987_DECODING); - // CaseB and start of CaseC: requires charset and optional language // in quotes (quotes required even if lang is blank) - if (caseB || (caseCorDStart && acceptContinuations)) - { - if (caseCorDStart) { - if (nextContinuation++ != 0) - { - // error: already started a continuation. Skip future - // continuations and return whatever initial parts were in order. - nextContinuation = -1; - goto increment_str; - } - } + if (caseB || (caseCStart && acceptContinuations)) { // look for single quotation mark(') const char *sQuote1 = PL_strchr(valueStart, 0x27); - const char *sQuote2 = (char *) (sQuote1 ? PL_strchr(sQuote1 + 1, 0x27) : nsnull); + const char *sQuote2 = sQuote1 ? PL_strchr(sQuote1 + 1, 0x27) : nsnull; // Two single quotation marks must be present even in // absence of charset and lang. - if (!sQuote1 || !sQuote2) + if (!sQuote1 || !sQuote2) { NS_WARNING("Mandatory two single quotes are missing in header parameter\n"); - if (aCharset && sQuote1 > valueStart && sQuote1 < valueEnd) - { - *aCharset = (char *) nsMemory::Clone(valueStart, sQuote1 - valueStart + 1); - if (*aCharset) - *(*aCharset + (sQuote1 - valueStart)) = 0; - } - if (aLang && sQuote1 && sQuote2 && sQuote2 > sQuote1 + 1 && - sQuote2 < valueEnd) - { - *aLang = (char *) nsMemory::Clone(sQuote1 + 1, sQuote2 - (sQuote1 + 1) + 1); - if (*aLang) - *(*aLang + (sQuote2 - (sQuote1 + 1))) = 0; } - // Be generous and handle gracefully when required - // single quotes are absent. - if (sQuote1) - { - if(!sQuote2) - sQuote2 = sQuote1; - } - else - sQuote2 = valueStart - 1; + const char *charsetStart = NULL; + PRInt32 charsetLength = 0; + const char *langStart = NULL; + PRInt32 langLength = 0; + const char *rawValStart = NULL; + PRInt32 rawValLength = 0; - if (sQuote2 && sQuote2 + 1 < valueEnd) - { - if (*aResult) - { - // caseA value already read, or caseC/D value already read - // but we're now reading caseB: either way, drop old value - nsMemory::Free(*aResult); - haveCaseAValue = false; - } - *aResult = (char *) nsMemory::Alloc(valueEnd - (sQuote2 + 1) + 1); - if (*aResult) - { - memcpy(*aResult, sQuote2 + 1, valueEnd - (sQuote2 + 1)); - *(*aResult + (valueEnd - (sQuote2 + 1))) = 0; - if (needUnescape) - { - nsUnescape(*aResult); - if (caseB) - return NS_OK; // caseB wins over everything else + if (sQuote2 && sQuote1) { + // both delimiters present: charSet'lang'rawVal + rawValStart = sQuote2 + 1; + rawValLength = valueEnd - rawValStart; + + langStart = sQuote1 + 1; + langLength = sQuote2 - langStart; + + charsetStart = valueStart; + charsetLength = sQuote1 - charsetStart; + } + else if (sQuote1) { + // one delimiter; assume charset'rawVal + rawValStart = sQuote1 + 1; + rawValLength = valueEnd - rawValStart; + + charsetStart = valueStart; + charsetLength = sQuote1 - valueStart; + } + else { + // no delimiter: just rawVal + rawValStart = valueStart; + rawValLength = valueEnd - valueStart; + } + + if (langLength != 0) { + lang.Assign(langStart, langLength); + } + + // keep the charset for later + if (caseB) { + charsetB.Assign(charsetStart, charsetLength); + } else { + // if caseCorD + charsetCD.Assign(charsetStart, charsetLength); + } + + // non-empty value part + if (rawValLength > 0) { + if (!caseBResult && caseB) { + // allocate buffer for the raw value + char *tmpResult = (char *) nsMemory::Clone(rawValStart, rawValLength + 1); + if (!tmpResult) { + goto increment_str; + } + *(tmpResult + rawValLength) = 0; + + nsUnescape(tmpResult); + caseBResult = tmpResult; + } else { + // caseC + bool added = addContinuation(segments, 0, rawValStart, + rawValLength, needExtDecoding); + + if (!added) { + // continuation not added, stop processing them + acceptContinuations = false; } } } } // end of if-block : title*0*= or title*= // caseD: a line of multiline param with no need for unescaping : title*[0-9]= // or 2nd or later lines of a caseC param : title*[1-9]*= - else if (acceptContinuations && nsCRT::IsAsciiDigit(PRUnichar(*cp))) - { - PRInt32 nextSegment = atoi(cp); - // no leading zeros allowed except for ... position 0 - bool broken = nextSegment > 0 && *cp == '0'; - - if (broken || nextSegment != nextContinuation++) - { - // error: gap in continuation or unneccessary leading 0. - // Skip future continuations and return whatever initial parts were - // in order. - nextContinuation = -1; - goto increment_str; + else if (acceptContinuations && segmentNumber != -1) { + PRUint32 valueLength = valueEnd - valueStart; + + bool added = addContinuation(segments, segmentNumber, valueStart, + valueLength, needExtDecoding); + + if (!added) { + // continuation not added, stop processing them + acceptContinuations = false; } - if (haveCaseAValue && *aResult) - { - // drop caseA value - nsMemory::Free(*aResult); - *aResult = 0; - haveCaseAValue = false; - } - PRInt32 len = 0; - if (*aResult) // 2nd or later lines of multiline parameter - { - len = strlen(*aResult); - char *ns = (char *) nsMemory::Realloc(*aResult, len + (valueEnd - valueStart) + 1); - if (!ns) - { - nsMemory::Free(*aResult); - } - *aResult = ns; - } - else - { - NS_ASSERTION(*cp == '0', "Not first value in continuation"); // must be; 1st line : title*0= - *aResult = (char *) nsMemory::Alloc(valueEnd - valueStart + 1); - } - if (*aResult) - { - // append a partial value - memcpy(*aResult + len, valueStart, valueEnd - valueStart); - *(*aResult + len + (valueEnd - valueStart)) = 0; - if (needUnescape) - nsUnescape(*aResult + len); - } - else - return NS_ERROR_OUT_OF_MEMORY; } // end of if-block : title*[0-9]= or title*[1-9]*= } @@ -483,10 +616,50 @@ increment_str: while (nsCRT::IsAsciiSpace(*str)) ++str; } - if (*aResult) - return NS_OK; - else - return NS_ERROR_INVALID_ARG; // aParameter not found !! + caseCDResult = combineContinuations(segments); + + if (caseBResult) { + // prefer simple 5987 format over 2231 with continuations + *aResult = caseBResult; + caseBResult = NULL; + charset.Assign(charsetB); + } + else if (caseCDResult) { + // prefer 2231/5987 with or without continuations over plain format + *aResult = caseCDResult; + caseCDResult = NULL; + charset.Assign(charsetCD); + } + else if (caseAResult) { + *aResult = caseAResult; + caseAResult = NULL; + } + + // free unused stuff + nsMemory::Free(caseAResult); + nsMemory::Free(caseBResult); + nsMemory::Free(caseCDResult); + + // if we have a result + if (*aResult) { + // then return charset and lang as well + if (aLang && !lang.IsEmpty()) { + PRUint32 len = lang.Length(); + *aLang = (char *) nsMemory::Clone(lang.BeginReading(), len + 1); + if (*aLang) { + *(*aLang + len) = 0; + } + } + if (aCharset && !charset.IsEmpty()) { + PRUint32 len = charset.Length(); + *aCharset = (char *) nsMemory::Clone(charset.BeginReading(), len + 1); + if (*aCharset) { + *(*aCharset + len) = 0; + } + } + } + + return *aResult ? NS_OK : NS_ERROR_INVALID_ARG; } diff --git a/netwerk/test/unit/test_MIME_params.js b/netwerk/test/unit/test_MIME_params.js index e30fe290f4d4..165aa5dd2395 100644 --- a/netwerk/test/unit/test_MIME_params.js +++ b/netwerk/test/unit/test_MIME_params.js @@ -96,16 +96,16 @@ var tests = [ "attachment", Cr.NS_ERROR_INVALID_ARG], // continuations should prevail over non-extended (unless RFC 5987) - ["attachment; filename=basic; filename*0*=UTF-8''multi\r\n" - + " filename*1=line\r\n" + ["attachment; filename=basic; filename*0*=UTF-8''multi;\r\n" + + " filename*1=line;\r\n" + " filename*2*=%20extended", "attachment", "multiline extended", "attachment", "basic"], // Gaps should result in returning only value until gap hit // (invalid; error recovery) - ["attachment; filename=basic; filename*0*=UTF-8''multi\r\n" - + " filename*1=line\r\n" + ["attachment; filename=basic; filename*0*=UTF-8''multi;\r\n" + + " filename*1=line;\r\n" + " filename*3*=%20extended", "attachment", "multiline", "attachment", "basic"], @@ -113,68 +113,60 @@ var tests = [ // First series, only please, and don't slurp up higher elements (*2 in this // case) from later series into earlier one (invalid; error recovery) ["attachment; filename=basic; filename*0*=UTF-8''multi\r\n" - + " filename*1=line\r\n" - + " filename*0*=UTF-8''wrong\r\n" - + " filename*1=bad\r\n" + + " filename*1=line;\r\n" + + " filename*0*=UTF-8''wrong;\r\n" + + " filename*1=bad;\r\n" + " filename*2=evil", "attachment", "multiline", "attachment", "basic"], // RFC 2231 not clear on correct outcome: we prefer non-continued extended // (invalid; error recovery) - ["attachment; filename=basic; filename*0=UTF-8''multi\r\n" - + " filename*=UTF-8''extended\r\n" - + " filename*1=line\r\n" + ["attachment; filename=basic; filename*0=UTF-8''multi\r\n;" + + " filename*=UTF-8''extended;\r\n" + + " filename*1=line;\r\n" + " filename*2*=%20extended", "attachment", "extended"], // sneaky: if unescaped, make sure we leave UTF-8'' in value - ["attachment; filename*0=UTF-8''unescaped\r\n" + ["attachment; filename*0=UTF-8''unescaped;\r\n" + " filename*1*=%20so%20includes%20UTF-8''%20in%20value", "attachment", "UTF-8''unescaped so includes UTF-8'' in value", "attachment", Cr.NS_ERROR_INVALID_ARG], // sneaky: if unescaped, make sure we leave UTF-8'' in value - ["attachment; filename=basic; filename*0=UTF-8''unescaped\r\n" + ["attachment; filename=basic; filename*0=UTF-8''unescaped;\r\n" + " filename*1*=%20so%20includes%20UTF-8''%20in%20value", "attachment", "UTF-8''unescaped so includes UTF-8'' in value", "attachment", "basic"], // Prefer basic over invalid continuation // (invalid; error recovery) - ["attachment; filename=basic; filename*1=multi\r\n" - + " filename*2=line\r\n" + ["attachment; filename=basic; filename*1=multi;\r\n" + + " filename*2=line;\r\n" + " filename*3*=%20extended", "attachment", "basic"], // support digits over 10 - ["attachment; filename=basic; filename*0*=UTF-8''0\r\n" - + " filename*1=1; filename*2=2;filename*3=3;filename*4=4;filename*5=5\r\n" - + " filename*6=6; filename*7=7;filename*8=8;filename*9=9;filename*10=a\r\n" + ["attachment; filename=basic; filename*0*=UTF-8''0;\r\n" + + " filename*1=1; filename*2=2;filename*3=3;filename*4=4;filename*5=5;\r\n" + + " filename*6=6; filename*7=7;filename*8=8;filename*9=9;filename*10=a;\r\n" + " filename*11=b; filename*12=c;filename*13=d;filename*14=e;filename*15=f\r\n", "attachment", "0123456789abcdef", "attachment", "basic"], - // support digits over 10 (check ordering) - ["attachment; filename=basic; filename*0*=UTF-8''0\r\n" - + " filename*1=1; filename*2=2;filename*3=3;filename*4=4;filename*5=5\r\n" - + " filename*6=6; filename*7=7;filename*8=8;filename*9=9;filename*10=a\r\n" - + " filename*11=b; filename*12=c;filename*13=d;filename*15=f;filename*14=e\r\n", - "attachment", "0123456789abcd" /* should see the 'f', see bug 588414 */, - "attachment", "basic"], - // support digits over 10 (detect gaps) - ["attachment; filename=basic; filename*0*=UTF-8''0\r\n" - + " filename*1=1; filename*2=2;filename*3=3;filename*4=4;filename*5=5\r\n" - + " filename*6=6; filename*7=7;filename*8=8;filename*9=9;filename*10=a\r\n" + ["attachment; filename=basic; filename*0*=UTF-8''0;\r\n" + + " filename*1=1; filename*2=2;filename*3=3;filename*4=4;filename*5=5;\r\n" + + " filename*6=6; filename*7=7;filename*8=8;filename*9=9;filename*10=a;\r\n" + " filename*11=b; filename*12=c;filename*14=e\r\n", "attachment", "0123456789abc", "attachment", "basic"], // return nothing: invalid // (invalid; error recovery) - ["attachment; filename*1=multi\r\n" - + " filename*2=line\r\n" + ["attachment; filename*1=multi;\r\n" + + " filename*2=line;\r\n" + " filename*3*=%20extended", "attachment", Cr.NS_ERROR_INVALID_ARG], @@ -195,6 +187,53 @@ var tests = [ "filename=foo.html", "foo.html", "filename=foo.html", "foo.html"], + // Bug 384571: RFC 2231 parameters not decoded when appearing in reversed order + + // check ordering + ["attachment; filename=basic; filename*0*=UTF-8''0;\r\n" + + " filename*1=1; filename*2=2;filename*3=3;filename*4=4;filename*5=5;\r\n" + + " filename*6=6; filename*7=7;filename*8=8;filename*9=9;filename*10=a;\r\n" + + " filename*11=b; filename*12=c;filename*13=d;filename*15=f;filename*14=e;\r\n", + "attachment", "0123456789abcdef", + "attachment", "basic"], + + // check non-digits in sequence numbers + ["attachment; filename=basic; filename*0*=UTF-8''0;\r\n" + + " filename*1a=1\r\n", + "attachment", "0", + "attachment", "basic"], + + // check duplicate sequence numbers + ["attachment; filename=basic; filename*0*=UTF-8''0;\r\n" + + " filename*0=bad; filename*1=1;\r\n", + "attachment", "0", + "attachment", "basic"], + + // check overflow + ["attachment; filename=basic; filename*0*=UTF-8''0;\r\n" + + " filename*11111111111111111111111111111111111111111111111111111111111=1", + "attachment", "0", + "attachment", "basic"], + + // check underflow + ["attachment; filename=basic; filename*0*=UTF-8''0;\r\n" + + " filename*-1=1", + "attachment", "0", + "attachment", "basic"], + + // check mixed token/quoted-string + ["attachment; filename=basic; filename*0=\"0\";\r\n" + + " filename*1=1;\r\n" + + " filename*2*=%32", + "attachment", "012", + "attachment", "basic"], + + // check empty sequence number + ["attachment; filename=basic; filename**=UTF-8''0\r\n", + "attachment", "basic", + "attachment", "basic"], + + // Bug 419157: ensure that a MIME parameter with no charset information // fallbacks to Latin-1 @@ -301,6 +340,23 @@ var tests = [ ["attachment; filename=\"", "attachment", ""], + + // We used to read past string if last param w/o = and ; + // Note: was only detected on windows PGO builds + ["attachment; filename=foo; trouble", + "attachment", "foo"], + + // Same, followed by space, hits another case + ["attachment; filename=foo; trouble ", + "attachment", "foo"], + + ["attachment", + "attachment", Cr.NS_ERROR_INVALID_ARG], + + // Bug 732369: Content-Disposition parser does not require presence of ";" between params + + ["attachment; extension=bla filename=foo", + "attachment", "foo"], ]; function do_tests(whichRFC) diff --git a/toolkit/components/search/tests/xpcshell/head_search.js b/toolkit/components/search/tests/xpcshell/head_search.js index 2b45f0f135c8..6d7897ae4f70 100644 --- a/toolkit/components/search/tests/xpcshell/head_search.js +++ b/toolkit/components/search/tests/xpcshell/head_search.js @@ -93,6 +93,7 @@ function afterCommit(callback) { let obs = function(result, topic, verb) { if (verb == "write-metadata-to-disk-complete") { + Services.obs.removeObserver(obs, topic); callback(result); } else { dump("TOPIC: " + topic+ "\n"); diff --git a/toolkit/components/telemetry/TelemetryHistograms.h b/toolkit/components/telemetry/TelemetryHistograms.h index 57e20e324a1b..4ba5430cb836 100644 --- a/toolkit/components/telemetry/TelemetryHistograms.h +++ b/toolkit/components/telemetry/TelemetryHistograms.h @@ -365,6 +365,7 @@ HISTOGRAM_BOOLEAN(FX_KEYWORD_URL_USERSET, "Firefox: keyword.URL has a user-set v HISTOGRAM(FX_IDENTITY_POPUP_OPEN_MS, 1, 1000, 10, EXPONENTIAL, "Firefox: Time taken by the identity popup to open in milliseconds") HISTOGRAM(FX_APP_MENU_OPEN_MS, 1, 1000, 10, EXPONENTIAL, "Firefox: Time taken by the app-menu opening in milliseconds") HISTOGRAM(FX_BOOKMARKS_TOOLBAR_INIT_MS, 50, 5000, 10, EXPONENTIAL, "Firefox: Time to initialize the bookmarks toolbar view (ms)") +HISTOGRAM(FX_NEW_WINDOW_MS, 1, 10000, 20, EXPONENTIAL, "Firefox: Time taken to open a new browser window (ms)") /** * Thumbnail Service telemetry. diff --git a/toolkit/content/license.html b/toolkit/content/license.html index 17b2bebc3510..49421e5e982c 100644 --- a/toolkit/content/license.html +++ b/toolkit/content/license.html @@ -110,7 +110,7 @@
  • Other Required Notices
  • Optional Notices #ifdef XP_WIN -
  • Proprietary Operating System Libraries +
  • Proprietary Operating System Components #endif @@ -2676,30 +2676,38 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. that specific operating system. The following license statements apply to such inclusions.

    -

    Microsoft Windows: Microsoft DirectX License

    +

    Microsoft Windows: Terms for 'Microsoft Distributable Code'

    -

    This license applies to the following files; +

    These terms apply to the following files; they are referred to below as "Distributable Code": - d3dx9_*.dll and d3dcompiler_*.dll.

    +
      +
    • d3d*.dll (Direct3D libraries)
    • +
    • msvc*.dll (C and C++ runtime libraries)
    • +
    +

     Copyright (c) Microsoft Corporation.
    +
     The Distributable Code may be used and distributed only if you comply with the
    -following terms: (i) You may use, copy, and distribute the Distributable Code
    -only as part of this product; (ii) You may not use the Distributable Code on a
    -platform other than Windows; (iii) You may not alter any copyright, trademark
    -or patent notice in the Distributable Code; (iv) You may not modify or
    -distribute the source code of any Distributable Code so that any part of the
    -source code becomes subject to the MPL or any other copyleft license; (v) You
    -must comply with any technical limitations in the Distributable Code that only
    -allow you to use it in certain ways; and (vi) You must comply with all domestic
    -and international export laws and regulations that apply to the Distributable
    -Code.
    +following terms:
    +
    +(i)   You may use, copy, and distribute the Distributable Code only as part of
    +      this product;
    +(ii)  You may not use the Distributable Code on a platform other than Windows;
    +(iii) You may not alter any copyright, trademark or patent notice in the
    +      Distributable Code;
    +(iv)  You may not modify or distribute the source code of any Distributable
    +      Code so that any part of the source code becomes subject to the MPL or
    +      any other copyleft license;
    +(v)   You must comply with any technical limitations in the Distributable Code
    +      that only allow you to use it in certain ways; and
    +(vi)  You must comply with all domestic and international export laws and
    +      regulations that apply to the Distributable Code.
     
    #endif -
    diff --git a/toolkit/content/tests/chrome/test_tooltip_noautohide.xul b/toolkit/content/tests/chrome/test_tooltip_noautohide.xul index f46b054424cf..c8a30f53e22a 100644 --- a/toolkit/content/tests/chrome/test_tooltip_noautohide.xul +++ b/toolkit/content/tests/chrome/test_tooltip_noautohide.xul @@ -40,6 +40,7 @@ function tooltipStillShown() document.getElementById("thetooltip").hidePopup(); } +SimpleTest.waitForExplicitFinish(); SimpleTest.waitForFocus(runTests); ]]> diff --git a/widget/android/AndroidBridge.cpp b/widget/android/AndroidBridge.cpp index 4e7a1b4dd3bf..ad2dc74f3b56 100644 --- a/widget/android/AndroidBridge.cpp +++ b/widget/android/AndroidBridge.cpp @@ -60,6 +60,7 @@ #include "nsPresContext.h" #include "nsIDocShell.h" #include "nsPIDOMWindow.h" +#include "mozilla/dom/ScreenOrientation.h" #ifdef DEBUG #define ALOG_BRIDGE(args...) ALOG(args) @@ -180,6 +181,10 @@ AndroidBridge::Init(JNIEnv *jEnv, jDisableNetworkNotifications = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "disableNetworkNotifications", "()V"); jEmitGeckoAccessibilityEvent = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "emitGeckoAccessibilityEvent", "(I[Ljava/lang/String;Ljava/lang/String;ZZZ)V"); + jGetScreenOrientation = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "getScreenOrientation", "()S"); + jEnableScreenOrientationNotifications = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "enableScreenOrientationNotifications", "()V"); + jDisableScreenOrientationNotifications = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "disableScreenOrientationNotifications", "()V"); + jEGLContextClass = (jclass) jEnv->NewGlobalRef(jEnv->FindClass("javax/microedition/khronos/egl/EGLContext")); jEGL10Class = (jclass) jEnv->NewGlobalRef(jEnv->FindClass("javax/microedition/khronos/egl/EGL10")); jEGLSurfaceImplClass = (jclass) jEnv->NewGlobalRef(jEnv->FindClass("com/google/android/gles_jni/EGLSurfaceImpl")); @@ -2088,6 +2093,27 @@ AndroidBridge::HideSurface(jobject surface) #endif } +void +AndroidBridge::GetScreenOrientation(dom::ScreenOrientationWrapper& aOrientation) +{ + ALOG_BRIDGE("AndroidBridge::GetScreenOrientation"); + aOrientation.orientation = static_cast(mJNIEnv->CallStaticShortMethod(mGeckoAppShellClass, jGetScreenOrientation)); +} + +void +AndroidBridge::EnableScreenOrientationNotifications() +{ + ALOG_BRIDGE("AndroidBridge::EnableScreenOrientationNotifications"); + mJNIEnv->CallStaticVoidMethod(mGeckoAppShellClass, jEnableScreenOrientationNotifications); +} + +void +AndroidBridge::DisableScreenOrientationNotifications() +{ + ALOG_BRIDGE("AndroidBridge::DisableScreenOrientationNotifications"); + mJNIEnv->CallStaticVoidMethod(mGeckoAppShellClass, jDisableScreenOrientationNotifications); +} + /* attribute nsIAndroidBrowserApp browserApp; */ NS_IMETHODIMP nsAndroidBridge::GetBrowserApp(nsIAndroidBrowserApp * *aBrowserApp) diff --git a/widget/android/AndroidBridge.h b/widget/android/AndroidBridge.h index 39660f440fed..c83be4f04b12 100644 --- a/widget/android/AndroidBridge.h +++ b/widget/android/AndroidBridge.h @@ -85,6 +85,7 @@ class NetworkInformation; } // namespace hal namespace dom { +class ScreenOrientationWrapper; namespace sms { struct SmsFilterData; } // namespace sms @@ -417,6 +418,14 @@ public: void ShowSurface(jobject surface, const gfxRect& aRect, bool aInverted, bool aBlend); void HideSurface(jobject surface); + // This method doesn't take a ScreenOrientation because it's an enum and + // that would require including the header which requires include IPC + // headers which requires including basictypes.h which requires a lot of + // changes... + void GetScreenOrientation(dom::ScreenOrientationWrapper& aOrientation); + void EnableScreenOrientationNotifications(); + void DisableScreenOrientationNotifications(); + protected: static AndroidBridge *sBridge; @@ -520,6 +529,10 @@ protected: jmethodID jEnableNetworkNotifications; jmethodID jDisableNetworkNotifications; + jmethodID jGetScreenOrientation; + jmethodID jEnableScreenOrientationNotifications; + jmethodID jDisableScreenOrientationNotifications; + // stuff we need for CallEglCreateWindowSurface jclass jEGLSurfaceImplClass; jclass jEGLContextImplClass; diff --git a/widget/android/AndroidJavaWrappers.cpp b/widget/android/AndroidJavaWrappers.cpp index 0e98af3a994c..d04c7f7217d7 100644 --- a/widget/android/AndroidJavaWrappers.cpp +++ b/widget/android/AndroidJavaWrappers.cpp @@ -72,6 +72,7 @@ jfieldID AndroidGeckoEvent::jRangeBackColorField = 0; jfieldID AndroidGeckoEvent::jLocationField = 0; jfieldID AndroidGeckoEvent::jBandwidthField = 0; jfieldID AndroidGeckoEvent::jCanBeMeteredField = 0; +jfieldID AndroidGeckoEvent::jScreenOrientationField = 0; jclass AndroidPoint::jPointClass = 0; jfieldID AndroidPoint::jXField = 0; @@ -183,6 +184,7 @@ AndroidGeckoEvent::InitGeckoEventClass(JNIEnv *jEnv) jLocationField = getField("mLocation", "Landroid/location/Location;"); jBandwidthField = getField("mBandwidth", "D"); jCanBeMeteredField = getField("mCanBeMetered", "Z"); + jScreenOrientationField = getField("mScreenOrientation", "S"); } void @@ -523,6 +525,11 @@ AndroidGeckoEvent::Init(JNIEnv *jenv, jobject jobj) ReadPointArray(mPoints, jenv, jPoints, 2); } + case SCREENORIENTATION_CHANGED: { + mScreenOrientation = jenv->GetShortField(jobj, jScreenOrientationField); + break; + } + default: break; } diff --git a/widget/android/AndroidJavaWrappers.h b/widget/android/AndroidJavaWrappers.h index ab3afa776cdf..8a39e30117e2 100644 --- a/widget/android/AndroidJavaWrappers.h +++ b/widget/android/AndroidJavaWrappers.h @@ -484,6 +484,7 @@ public: nsGeoPosition* GeoPosition() { return mGeoPosition; } double Bandwidth() { return mBandwidth; } bool CanBeMetered() { return mCanBeMetered; } + short ScreenOrientation() { return mScreenOrientation; } protected: int mAction; @@ -507,6 +508,7 @@ protected: nsRefPtr mGeoPosition; double mBandwidth; bool mCanBeMetered; + short mScreenOrientation; void ReadIntArray(nsTArray &aVals, JNIEnv *jenv, @@ -558,6 +560,8 @@ protected: static jfieldID jBandwidthField; static jfieldID jCanBeMeteredField; + static jfieldID jScreenOrientationField; + public: enum { NATIVE_POKE = 0, @@ -586,6 +590,7 @@ public: ACTIVITY_RESUMING = 24, SCREENSHOT = 25, SENSOR_ACCURACY = 26, + SCREENORIENTATION_CHANGED = 27, dummy_java_enum_list_end }; diff --git a/widget/android/nsAppShell.cpp b/widget/android/nsAppShell.cpp index 6020cd91dc0e..738e09611239 100644 --- a/widget/android/nsAppShell.cpp +++ b/widget/android/nsAppShell.cpp @@ -61,6 +61,8 @@ #include #include +#include "mozilla/dom/ScreenOrientation.h" + #ifdef MOZ_ANDROID_HISTORY #include "nsAndroidHistory.h" #endif @@ -560,6 +562,11 @@ nsAppShell::ProcessNextNativeEvent(bool mayWait) break; } + case AndroidGeckoEvent::SCREENORIENTATION_CHANGED: { + hal::NotifyScreenOrientationChange(static_cast(curEvent->ScreenOrientation())); + break; + } + default: nsWindow::OnGlobalAndroidEvent(curEvent); } diff --git a/widget/android/nsLookAndFeel.cpp b/widget/android/nsLookAndFeel.cpp index 571300e4b504..3426ab6cb9f0 100644 --- a/widget/android/nsLookAndFeel.cpp +++ b/widget/android/nsLookAndFeel.cpp @@ -423,8 +423,11 @@ nsLookAndFeel::GetIntImpl(IntID aID, PRInt32 &aResult) aResult = eScrollThumbStyle_Proportional; break; - case eIntID_WindowsDefaultTheme: case eIntID_TouchEnabled: + aResult = 1; + break; + + case eIntID_WindowsDefaultTheme: case eIntID_MaemoClassic: case eIntID_WindowsThemeIdentifier: aResult = 0; diff --git a/widget/cocoa/nsCocoaWindow.h b/widget/cocoa/nsCocoaWindow.h index f01aebe26973..c9450d9d652d 100644 --- a/widget/cocoa/nsCocoaWindow.h +++ b/widget/cocoa/nsCocoaWindow.h @@ -53,6 +53,21 @@ class nsCocoaWindow; class nsChildView; class nsMenuBarX; +// If we are using an SDK older than 10.7, define bits we need that are missing +// from it. +#if !defined(MAC_OS_X_VERSION_10_7) || \ + MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7 + +enum { + NSWindowCollectionBehaviorFullScreenPrimary = 1 << 7, +}; + +@interface NSWindow (NewInMacOS107) +- (void)toggleFullScreen:(id)sender; +@end + +#endif + typedef struct _nsCocoaWindowList { _nsCocoaWindowList() : prev(NULL), window(NULL) {} struct _nsCocoaWindowList *prev; @@ -255,6 +270,7 @@ public: nsIWidget *aWidget, bool aActivate); NS_IMETHOD SetSizeMode(PRInt32 aMode); NS_IMETHOD HideWindowChrome(bool aShouldHide); + void EnteredFullScreen(bool aFullScreen); NS_IMETHOD MakeFullScreen(bool aFullScreen); NS_IMETHOD Resize(PRInt32 aWidth,PRInt32 aHeight, bool aRepaint); NS_IMETHOD Resize(PRInt32 aX, PRInt32 aY, PRInt32 aWidth, PRInt32 aHeight, bool aRepaint); @@ -281,6 +297,7 @@ public: virtual void SetTransparencyMode(nsTransparencyMode aMode); NS_IMETHOD SetWindowShadowStyle(PRInt32 aStyle); virtual void SetShowsToolbarButton(bool aShow); + virtual void SetShowsFullScreenButton(bool aShow); virtual void SetWindowAnimationType(WindowAnimationType aType); NS_IMETHOD SetWindowTitlebarColor(nscolor aColor, bool aActive); virtual void SetDrawsInTitlebar(bool aState); @@ -359,6 +376,8 @@ protected: bool mFullScreen; bool mModal; + bool mUsesNativeFullScreen; // only true on Lion if SetShowsFullScreenButton(true); + bool mIsAnimationSuppressed; bool mInReportMoveEvent; // true if in a call to ReportMoveEvent(). diff --git a/widget/cocoa/nsCocoaWindow.mm b/widget/cocoa/nsCocoaWindow.mm index 7175679bc08a..80fc621d7f66 100644 --- a/widget/cocoa/nsCocoaWindow.mm +++ b/widget/cocoa/nsCocoaWindow.mm @@ -140,6 +140,7 @@ nsCocoaWindow::nsCocoaWindow() , mSheetNeedsShow(false) , mFullScreen(false) , mModal(false) +, mUsesNativeFullScreen(false) , mIsAnimationSuppressed(false) , mInReportMoveEvent(false) , mNumModalDescendents(0) @@ -513,7 +514,10 @@ NS_IMETHODIMP nsCocoaWindow::Destroy() nsBaseWidget::Destroy(); nsBaseWidget::OnDestroy(); - if (mFullScreen) { + // On Lion we do not have to mess with the OS chrome when in Full Screen mode. So we + // can simply skip that. When the Window is destroyed, the OS will take care of removing + // the full screen 'Space' that was setup for us. + if (!mUsesNativeFullScreen && mFullScreen) { nsCocoaUtils::HideOSChromeOnScreen(false, [mWindow screen]); } @@ -1180,24 +1184,40 @@ NS_IMETHODIMP nsCocoaWindow::HideWindowChrome(bool aShouldHide) NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT; } +void nsCocoaWindow::EnteredFullScreen(bool aFullScreen) +{ + mFullScreen = aFullScreen; + DispatchSizeModeEvent(); +} NS_METHOD nsCocoaWindow::MakeFullScreen(bool aFullScreen) { NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT; - NS_ASSERTION(mFullScreen != aFullScreen, "Unnecessary MakeFullScreen call"); + // We will call into MakeFullScreen redundantly when entering/exiting + // fullscreen mode via OS X controls. When that happens we should just handle + // it gracefully - no need to ASSERT. + if (mFullScreen == aFullScreen) { + return NS_OK; + } - NSDisableScreenUpdates(); - // The order here matters. When we exit full screen mode, we need to show the - // Dock first, otherwise the newly-created window won't have its minimize - // button enabled. See bug 526282. - nsCocoaUtils::HideOSChromeOnScreen(aFullScreen, [mWindow screen]); - nsresult rv = nsBaseWidget::MakeFullScreen(aFullScreen); - NSEnableScreenUpdates(); - NS_ENSURE_SUCCESS(rv, rv); + if (mUsesNativeFullScreen) { + // Calling toggleFullScreen will result in windowDid(Enter|Exit)FullScreen + // to be called from the OS. We will call EnteredFullScreen from those methods, + // where mFullScreen will be set and a sizemode event will be dispatched. + [mWindow toggleFullScreen:nil]; + } else { + NSDisableScreenUpdates(); + // The order here matters. When we exit full screen mode, we need to show the + // Dock first, otherwise the newly-created window won't have its minimize + // button enabled. See bug 526282. + nsCocoaUtils::HideOSChromeOnScreen(aFullScreen, [mWindow screen]); + nsresult rv = nsBaseWidget::MakeFullScreen(aFullScreen); + NSEnableScreenUpdates(); + NS_ENSURE_SUCCESS(rv, rv); - mFullScreen = aFullScreen; - DispatchSizeModeEvent(); + EnteredFullScreen(aFullScreen); + } return NS_OK; @@ -1642,6 +1662,42 @@ void nsCocoaWindow::SetShowsToolbarButton(bool aShow) NS_OBJC_END_TRY_ABORT_BLOCK; } +void nsCocoaWindow::SetShowsFullScreenButton(bool aShow) +{ + NS_OBJC_BEGIN_TRY_ABORT_BLOCK; + + if (![mWindow respondsToSelector:@selector(toggleFullScreen:)] || + mUsesNativeFullScreen == aShow) { + return; + } + + // If the window is currently in fullscreen mode, then we're going to + // transition out first, then set the collection behavior & toggle + // mUsesNativeFullScreen, then transtion back into fullscreen mode. This + // prevents us from getting into a conflicting state with MakeFullScreen + // where mUsesNativeFullScreen would lead us down the wrong path. + bool wasFullScreen = mFullScreen; + + if (wasFullScreen) { + MakeFullScreen(false); + } + + NSWindowCollectionBehavior newBehavior = [mWindow collectionBehavior]; + if (aShow) { + newBehavior |= NSWindowCollectionBehaviorFullScreenPrimary; + } else { + newBehavior &= ~NSWindowCollectionBehaviorFullScreenPrimary; + } + [mWindow setCollectionBehavior:newBehavior]; + mUsesNativeFullScreen = aShow; + + if (wasFullScreen) { + MakeFullScreen(true); + } + + NS_OBJC_END_TRY_ABORT_BLOCK; +} + void nsCocoaWindow::SetWindowAnimationType(nsIWidget::WindowAnimationType aType) { mAnimationType = aType; @@ -1875,6 +1931,27 @@ bool nsCocoaWindow::ShouldFocusPlugin() mGeckoWindow->ReportMoveEvent(); } +// Lion's full screen mode will bypass our internal fullscreen tracking, so +// we need to catch it when we transition and call our own methods, which in +// turn will fire "fullscreen" events. +- (void)windowDidEnterFullScreen:(NSNotification *)notification +{ + if (!mGeckoWindow) { + return; + } + + mGeckoWindow->EnteredFullScreen(true); +} + +- (void)windowDidExitFullScreen:(NSNotification *)notification +{ + if (!mGeckoWindow) { + return; + } + + mGeckoWindow->EnteredFullScreen(false); +} + - (void)windowDidBecomeMain:(NSNotification *)aNotification { NS_OBJC_BEGIN_TRY_ABORT_BLOCK; diff --git a/widget/gonk/nsLookAndFeel.cpp b/widget/gonk/nsLookAndFeel.cpp index 336acc3f3287..91ec0e44f3b0 100644 --- a/widget/gonk/nsLookAndFeel.cpp +++ b/widget/gonk/nsLookAndFeel.cpp @@ -367,8 +367,11 @@ nsLookAndFeel::GetIntImpl(IntID aID, PRInt32 &aResult) aResult = eScrollThumbStyle_Proportional; break; - case eIntID_WindowsDefaultTheme: case eIntID_TouchEnabled: + aResult = 1; + break; + + case eIntID_WindowsDefaultTheme: case eIntID_MaemoClassic: case eIntID_WindowsThemeIdentifier: aResult = 0; diff --git a/widget/nsIWidget.h b/widget/nsIWidget.h index 5e75c9dfcd41..8be7bcf5f92f 100644 --- a/widget/nsIWidget.h +++ b/widget/nsIWidget.h @@ -118,8 +118,8 @@ typedef nsEventStatus (* EVENT_CALLBACK)(nsGUIEvent *event); #endif #define NS_IWIDGET_IID \ - { 0x3fa36ce2, 0x472d, 0x4bff, \ - { 0xb1, 0xe4, 0xc3, 0xe3, 0x19, 0x24, 0xa1, 0xe4 } } + { 0xf60ba9a0, 0x3013, 0x4381, \ + { 0xb7, 0xd4, 0x34, 0xeb, 0x0c, 0xe7, 0x79, 0x0e } } /* * Window shadow styles @@ -1017,6 +1017,14 @@ class nsIWidget : public nsISupports { */ virtual void SetShowsToolbarButton(bool aShow) = 0; + /* + * On Mac OS X Lion, this method shows or hides the full screen button in + * the titlebar that handles native full screen mode. + * + * Ignored on child widgets, non-Mac platforms, & pre-Lion Mac. + */ + virtual void SetShowsFullScreenButton(bool aShow) = 0; + enum WindowAnimationType { eGenericWindowAnimation, eDocumentWindowAnimation diff --git a/widget/xpwidgets/nsBaseWidget.h b/widget/xpwidgets/nsBaseWidget.h index 46a2352dc96d..98d0772596b8 100644 --- a/widget/xpwidgets/nsBaseWidget.h +++ b/widget/xpwidgets/nsBaseWidget.h @@ -123,6 +123,7 @@ public: virtual void GetWindowClipRegion(nsTArray* aRects); NS_IMETHOD SetWindowShadowStyle(PRInt32 aStyle); virtual void SetShowsToolbarButton(bool aShow) {} + virtual void SetShowsFullScreenButton(bool aShow) {} virtual void SetWindowAnimationType(WindowAnimationType aType) {} NS_IMETHOD HideWindowChrome(bool aShouldHide); NS_IMETHOD MakeFullScreen(bool aFullScreen); diff --git a/xpcom/string/public/nsTSubstring.h b/xpcom/string/public/nsTSubstring.h index 7347855a1601..2335cce15636 100644 --- a/xpcom/string/public/nsTSubstring.h +++ b/xpcom/string/public/nsTSubstring.h @@ -472,7 +472,7 @@ class nsTSubstring_CharT */ bool NS_FASTCALL SetCapacity( size_type newCapacity ); - void NS_FASTCALL SetLength( size_type newLength ); + bool NS_FASTCALL SetLength( size_type newLength ); void Truncate( size_type newLength = 0 ) { diff --git a/xpcom/string/src/nsTSubstring.cpp b/xpcom/string/src/nsTSubstring.cpp index 46382c69f34e..4df8e7dccb71 100644 --- a/xpcom/string/src/nsTSubstring.cpp +++ b/xpcom/string/src/nsTSubstring.cpp @@ -289,16 +289,9 @@ nsTSubstring_CharT::EnsureMutable( size_type newLen ) if ((mFlags & F_SHARED) && !nsStringBuffer::FromData(mData)->IsReadonly()) return true; - // promote to a shared string buffer - char_type* prevData = mData; - Assign(mData, mLength); - return mData != prevData; - } - else - { - SetLength(newLen); - return mLength == newLen; + newLen = mLength; } + return SetLength(newLen); } // --------------------------------------------------------------------------- @@ -573,11 +566,14 @@ nsTSubstring_CharT::SetCapacity( size_type capacity ) return true; } -void +bool nsTSubstring_CharT::SetLength( size_type length ) { - if (SetCapacity(length)) - mLength = length; + if (!SetCapacity(length)) + return false; + + mLength = length; + return true; } void diff --git a/xpfe/appshell/src/nsXULWindow.cpp b/xpfe/appshell/src/nsXULWindow.cpp index d9701a926901..57dc4662260d 100644 --- a/xpfe/appshell/src/nsXULWindow.cpp +++ b/xpfe/appshell/src/nsXULWindow.cpp @@ -1413,6 +1413,12 @@ void nsXULWindow::SyncAttributesToWidget() mWindow->SetShowsToolbarButton(attr.LowerCaseEqualsLiteral("true")); } + // "fullscreenbutton" attribute + rv = windowElement->GetAttribute(NS_LITERAL_STRING("fullscreenbutton"), attr); + if (NS_SUCCEEDED(rv)) { + mWindow->SetShowsFullScreenButton(attr.LowerCaseEqualsLiteral("true")); + } + // "macanimationtype" attribute rv = windowElement->GetAttribute(NS_LITERAL_STRING("macanimationtype"), attr); if (NS_SUCCEEDED(rv) && attr.EqualsLiteral("document")) { @@ -1513,11 +1519,9 @@ NS_IMETHODIMP nsXULWindow::SavePersistentAttributes() } if (mPersistentAttributesDirty & PAD_MISC) { - if (sizeMode != nsSizeMode_Minimized) { + if (sizeMode != nsSizeMode_Minimized && sizeMode != nsSizeMode_Fullscreen) { if (sizeMode == nsSizeMode_Maximized) sizeString.Assign(SIZEMODE_MAXIMIZED); - else if (sizeMode == nsSizeMode_Fullscreen) - sizeString.Assign(SIZEMODE_FULLSCREEN); else sizeString.Assign(SIZEMODE_NORMAL); docShellElement->SetAttribute(MODE_ATTRIBUTE, sizeString);