From 166055b7596c823a7fc780590c19f78e9af32f4e Mon Sep 17 00:00:00 2001 From: Blake Kaplan Date: Fri, 10 Feb 2012 13:13:21 +0100 Subject: [PATCH 01/34] Bug 725750 - Restore auto-Mozilla network joining hack. r=gal --- dom/wifi/nsWifiWorker.js | 55 +++++++++++++++++++++++++++++++++++----- 1 file changed, 49 insertions(+), 6 deletions(-) diff --git a/dom/wifi/nsWifiWorker.js b/dom/wifi/nsWifiWorker.js index d1ccc99115e8..93eaea68406e 100644 --- a/dom/wifi/nsWifiWorker.js +++ b/dom/wifi/nsWifiWorker.js @@ -493,6 +493,7 @@ var WifiManager = (function() { for (let i = 0; i < lines.length; ++i) { let [key, value] = lines[i].split("="); if (key === "wpa_state") { + notify("statechange", { state: value }); if (value === "COMPLETED") onconnected(); } @@ -564,8 +565,8 @@ var WifiManager = (function() { } var supplicantStatesMap = ["DISCONNECTED", "INACTIVE", "SCANNING", "ASSOCIATING", - "FOUR_WAY_HANDSHAKE", "GROUP_HANDSHAKE", "COMPLETED", - "DORMANT", "UNINITIALIZED"]; + "ASSOCIATED", "FOUR_WAY_HANDSHAKE", "GROUP_HANDSHAKE", + "COMPLETED", "DORMANT", "UNINITIALIZED"]; var driverEventMap = { STOPPED: "driverstopped", STARTED: "driverstarted", HANGED: "driverhung" }; // handle events sent to us by the event worker @@ -580,11 +581,12 @@ var WifiManager = (function() { return true; } - var eventData = event.substr(0, event.indexOf(" ") + 1); + var space = event.indexOf(" "); + var eventData = event.substr(0, space + 1); if (eventData.indexOf("CTRL-EVENT-STATE-CHANGE") === 0) { // Parse the event data var fields = {}; - var tokens = eventData.split(" "); + var tokens = event.substr(space + 1).split(" "); for (var n = 0; n < tokens.length; ++n) { var kv = tokens[n].split("="); if (kv.length === 2) @@ -630,7 +632,7 @@ var WifiManager = (function() { return true; } if (eventData.indexOf("CTRL-EVENT-SCAN-RESULTS") === 0) { - debug("Notifying of scn results available"); + debug("Notifying of scan results available"); notify("scanresultsavailable"); return true; } @@ -804,6 +806,47 @@ function nsWifiWorker() { debug("Couldn't connect to supplicant"); } + var state; + WifiManager.onstatechange = function() { + debug("State change: " + state + " -> " + this.state); + if (state === "SCANNING" && this.state === "INACTIVE") { + // We're not trying to connect so try to find an open Mozilla network. + // TODO Remove me in favor of UI and a way to select a network. + + debug("Haven't connected to a network, trying a default (for now)"); + var name = "Mozilla"; + var net = networks[name]; + if (net && (net[1] && net[1] !== "[IBSS]")) { + debug("Network Mozilla exists, but is encrypted"); + net = null; + } + if (!net) { + name = "Mozilla Guest"; + net = networks[name]; + if (!net || (net[1] && net[1] !== "[IBSS]")) { + debug("Network Mozilla Guest doesn't exist or is encrypted"); + return; + } + } + + var config = Object.create(null); + config["ssid"] = '"' + name + '"'; + config["key_mgmt"] = "NONE"; + WifiManager.addNetwork(config, function(ok) { + if (!ok) { + debug("Unable to add the network!"); + return; + } + + WifiManager.enableNetwork(config.netId, false, function(ok) { + debug((ok ? "Successfully enabled " : "Didn't enable ") + name); + }); + }); + } + + state = this.state; + } + var networks = Object.create(null); WifiManager.onscanresultsavailable = function() { debug("Scan results are available! Asking for them."); @@ -814,7 +857,7 @@ function nsWifiWorker() { // bssid / frequency / signal level / flags / ssid var match = /([\S]+)\s+([\S]+)\s+([\S]+)\s+(\[[\S]+\])?\s+(.*)/.exec(lines[i]) if (match) - networks[match[5]] = match[1]; + networks[match[5]] = [match[1], match[4]]; else debug("Match didn't find anything for: " + lines[i]); } From 989bcc0208056e5c57cf992fc63e5931d364e9ef Mon Sep 17 00:00:00 2001 From: Jonathan Watt Date: Fri, 10 Feb 2012 12:33:18 +0000 Subject: [PATCH 02/34] Bug 725897 - Remove the inaccurate nsSVGUtils::ToAppPixelRect, and use nsLayoutUtils::RoundGfxRectToAppRect instead. r=longsonr. --- content/svg/content/test/test_bounds.html | 50 ++++++++----------- .../svg/base/src/nsSVGForeignObjectFrame.cpp | 8 +-- layout/svg/base/src/nsSVGGlyphFrame.cpp | 3 +- layout/svg/base/src/nsSVGImageFrame.cpp | 3 +- .../svg/base/src/nsSVGPathGeometryFrame.cpp | 3 +- layout/svg/base/src/nsSVGUtils.cpp | 18 ------- layout/svg/base/src/nsSVGUtils.h | 9 ---- 7 files changed, 30 insertions(+), 64 deletions(-) diff --git a/content/svg/content/test/test_bounds.html b/content/svg/content/test/test_bounds.html index dc9726d44224..611f70070e90 100644 --- a/content/svg/content/test/test_bounds.html +++ b/content/svg/content/test/test_bounds.html @@ -35,11 +35,9 @@ Rect.prototype.roundOut = function() this.top = Math.floor(this.top); } -var delta = 1; - -function isApproximately(a, b, message) +function isWithAbsTolerance(a, b, tolerance, message) { - ok(delta >= Math.abs(a - b), message + " - got " + a + ", expected " + b + " ± " + delta); + ok(tolerance >= Math.abs(a - b), message + " - got " + a + ", expected " + b + " ± " + tolerance); } function runTest() @@ -54,7 +52,7 @@ function runTest() var sin45 = Math.sin(Math.PI / 4); - isApproximately(text1Bounds.left, 24, "text1.getBoundingClientRect().left"); + isWithAbsTolerance(text1Bounds.left, 24, 1, "text1.getBoundingClientRect().left"); is(text2Bounds.left, text1Bounds.left + 100, "text2.getBoundingClientRect().left"); is(text2Bounds.top, text1Bounds.top, "text2.getBoundingClientRect().top"); @@ -62,8 +60,8 @@ function runTest() is(text2Bounds.height, text1Bounds.height, "text2.getBoundingClientRect().height"); var r = (text1Bounds.width + text1Bounds.height) * sin45; - isApproximately(text3Bounds.width, Math.ceil(r), "text3.getBoundingClientRect().width"); - isApproximately(text3Bounds.height, Math.ceil(r), "text3.getBoundingClientRect().height"); + isWithAbsTolerance(text3Bounds.width, Math.ceil(r), 1, "text3.getBoundingClientRect().width"); + isWithAbsTolerance(text3Bounds.height, Math.ceil(r), 1, "text3.getBoundingClientRect().height"); var rect1Bounds = doc.getElementById("rect1").getBoundingClientRect(); var rect2Bounds = doc.getElementById("rect2").getBoundingClientRect(); @@ -76,11 +74,10 @@ function runTest() is(rect1Bounds.height, 50, "rect1.getBoundingClientRect().height"); rect = new Rect(175 - 50 * sin45, 75 - 50 * sin45, 50 * sin45 * 2, 50 * sin45 * 2); - rect.roundOut(); - is(rect2Bounds.left, rect.left, "rect2.getBoundingClientRect().left"); - is(rect2Bounds.top, rect.top, "rect2.getBoundingClientRect().top"); - is(rect2Bounds.width, rect.width, "rect2.getBoundingClientRect().width"); - is(rect2Bounds.height, rect.height, "rect2.getBoundingClientRect().height"); + isWithAbsTolerance(rect2Bounds.left, rect.left, 0.1, "rect2.getBoundingClientRect().left"); + isWithAbsTolerance(rect2Bounds.top, rect.top, 0.1, "rect2.getBoundingClientRect().top"); + isWithAbsTolerance(rect2Bounds.width, rect.width, 0.1, "rect2.getBoundingClientRect().width"); + isWithAbsTolerance(rect2Bounds.height, rect.height, 0.1, "rect2.getBoundingClientRect().height"); is(rect3Bounds.left, 50, "rect3.getBoundingClientRect().left"); is(rect3Bounds.top, 160, "rect3.getBoundingClientRect().top"); @@ -88,11 +85,10 @@ function runTest() is(rect3Bounds.height, 100, "rect3.getBoundingClientRect().height"); rect = new Rect(350 - 100 * sin45, 150 - 100 * sin45, 100 * sin45 * 2, 100 * sin45 * 2); - rect.roundOut(); - is(rect4Bounds.left, rect.left, "rect4.getBoundingClientRect().left"); - is(rect4Bounds.top, rect.top, "rect4.getBoundingClientRect().top"); - is(rect4Bounds.width, rect.width, "rect4.getBoundingClientRect().width"); - is(rect4Bounds.height, rect.height, "rect4.getBoundingClientRect().height"); + isWithAbsTolerance(rect4Bounds.left, rect.left, 0.1, "rect4.getBoundingClientRect().left"); + isWithAbsTolerance(rect4Bounds.top, rect.top, 0.1, "rect4.getBoundingClientRect().top"); + isWithAbsTolerance(rect4Bounds.width, rect.width, 0.1, "rect4.getBoundingClientRect().width"); + isWithAbsTolerance(rect4Bounds.height, rect.height, 0.1, "rect4.getBoundingClientRect().height"); var rect1aBounds = doc.getElementById("rect1a").getBoundingClientRect(); var rect2aBounds = doc.getElementById("rect2a").getBoundingClientRect(); @@ -105,11 +101,10 @@ function runTest() is(rect1aBounds.height, 54, "rect1a.getBoundingClientRect().height"); rect = new Rect(175 - 54 * sin45, 75 - 54 * sin45, 54 * sin45 * 2, 54 * sin45 * 2); - rect.roundOut(); - is(rect2aBounds.left, rect.left, "rect2a.getBoundingClientRect().left"); - is(rect2aBounds.top, rect.top, "rect2a.getBoundingClientRect().top"); - is(rect2aBounds.width, rect.width, "rect2a.getBoundingClientRect().width"); - is(rect2aBounds.height, rect.height, "rect2a.getBoundingClientRect().height"); + isWithAbsTolerance(rect2aBounds.left, rect.left, 0.1, "rect2a.getBoundingClientRect().left"); + isWithAbsTolerance(rect2aBounds.top, rect.top, 0.1, "rect2a.getBoundingClientRect().top"); + isWithAbsTolerance(rect2aBounds.width, rect.width, 0.1, "rect2a.getBoundingClientRect().width"); + isWithAbsTolerance(rect2aBounds.height, rect.height, 0.1, "rect2a.getBoundingClientRect().height"); is(rect3aBounds.left, 46, "rect3a.getBoundingClientRect().left"); is(rect3aBounds.top, 156, "rect3a.getBoundingClientRect().top"); @@ -117,18 +112,17 @@ function runTest() is(rect3aBounds.height, 108, "rect3a.getBoundingClientRect().height"); rect = new Rect(350 - 108 * sin45, 150 - 108 * sin45, 108 * sin45 * 2, 108 * sin45 * 2); - rect.roundOut(); - is(rect4aBounds.left, rect.left, "rect4a.getBoundingClientRect().left"); - is(rect4aBounds.top, rect.top, "rect4a.getBoundingClientRect().top"); - is(rect4aBounds.width, rect.width, "rect4a.getBoundingClientRect().width"); - is(rect4aBounds.height, rect.height, "rect4a.getBoundingClientRect().height"); + isWithAbsTolerance(rect4aBounds.left, rect.left, 0.1, "rect4a.getBoundingClientRect().left"); + isWithAbsTolerance(rect4aBounds.top, rect.top, 0.1, "rect4a.getBoundingClientRect().top"); + isWithAbsTolerance(rect4aBounds.width, rect.width, 0.1, "rect4a.getBoundingClientRect().width"); + isWithAbsTolerance(rect4aBounds.height, rect.height, 0.1, "rect4a.getBoundingClientRect().height"); var text1a = doc.getElementById("text1a"); var text1aBounds = text1a.getBoundingClientRect(); var text2aBounds = doc.getElementById("text2a").getBoundingClientRect(); - isApproximately(text1aBounds.left, 82, "text1a.getBoundingClientRect().left"); + isWithAbsTolerance(text1aBounds.left, 82, 1, "text1a.getBoundingClientRect().left"); is(text1aBounds.width, text1Bounds.width + 4, "text1a.getBoundingClientRect().width"); is(text2aBounds.left, text1aBounds.left + 100 - 3, "text2a.getBoundingClientRect().left"); diff --git a/layout/svg/base/src/nsSVGForeignObjectFrame.cpp b/layout/svg/base/src/nsSVGForeignObjectFrame.cpp index 44d1e8d7fd6f..4a930f23cbb8 100644 --- a/layout/svg/base/src/nsSVGForeignObjectFrame.cpp +++ b/layout/svg/base/src/nsSVGForeignObjectFrame.cpp @@ -264,13 +264,9 @@ nsSVGForeignObjectFrame::PaintSVG(nsSVGRenderState *aContext, aDirtyRect->width, aDirtyRect->height); transDirtyRect = invmatrix.TransformBounds(transDirtyRect); - transDirtyRect.Scale(nsPresContext::AppUnitsPerCSSPixel()); - nsPoint tl(NSToCoordFloor(transDirtyRect.X()), - NSToCoordFloor(transDirtyRect.Y())); - nsPoint br(NSToCoordCeil(transDirtyRect.XMost()), - NSToCoordCeil(transDirtyRect.YMost())); kidDirtyRect.IntersectRect(kidDirtyRect, - nsRect(tl.x, tl.y, br.x - tl.x, br.y - tl.y)); + nsLayoutUtils::RoundGfxRectToAppRect(transDirtyRect, + PresContext()->AppUnitsPerCSSPixel())); } PRUint32 flags = nsLayoutUtils::PAINT_IN_TRANSFORM; diff --git a/layout/svg/base/src/nsSVGGlyphFrame.cpp b/layout/svg/base/src/nsSVGGlyphFrame.cpp index 307a8e361f91..3af5eb5d73db 100644 --- a/layout/svg/base/src/nsSVGGlyphFrame.cpp +++ b/layout/svg/base/src/nsSVGGlyphFrame.cpp @@ -491,7 +491,8 @@ nsSVGGlyphFrame::UpdateCoveredRegion() } if (!extent.IsEmpty()) { - mRect = nsSVGUtils::ToAppPixelRect(PresContext(), extent); + mRect = nsLayoutUtils::RoundGfxRectToAppRect(extent, + PresContext()->AppUnitsPerDevPixel()); } return NS_OK; diff --git a/layout/svg/base/src/nsSVGImageFrame.cpp b/layout/svg/base/src/nsSVGImageFrame.cpp index e42b5b836c09..0d55f3f58b46 100644 --- a/layout/svg/base/src/nsSVGImageFrame.cpp +++ b/layout/svg/base/src/nsSVGImageFrame.cpp @@ -489,7 +489,8 @@ nsSVGImageFrame::UpdateCoveredRegion() gfxRect extent = context.GetUserPathExtent(); if (!extent.IsEmpty()) { - mRect = nsSVGUtils::ToAppPixelRect(PresContext(), extent); + mRect = nsLayoutUtils::RoundGfxRectToAppRect(extent, + PresContext()->AppUnitsPerDevPixel()); } return NS_OK; diff --git a/layout/svg/base/src/nsSVGPathGeometryFrame.cpp b/layout/svg/base/src/nsSVGPathGeometryFrame.cpp index c7f2d5ae3e59..241743754da4 100644 --- a/layout/svg/base/src/nsSVGPathGeometryFrame.cpp +++ b/layout/svg/base/src/nsSVGPathGeometryFrame.cpp @@ -206,7 +206,8 @@ nsSVGPathGeometryFrame::UpdateCoveredRegion() nsSVGUtils::eBBoxIncludeFill | nsSVGUtils::eBBoxIgnoreFillIfNone | nsSVGUtils::eBBoxIncludeStroke | nsSVGUtils::eBBoxIgnoreStrokeIfNone | nsSVGUtils::eBBoxIncludeMarkers); - mRect = nsSVGUtils::ToAppPixelRect(PresContext(), extent); + mRect = nsLayoutUtils::RoundGfxRectToAppRect(extent, + PresContext()->AppUnitsPerDevPixel()); return NS_OK; } diff --git a/layout/svg/base/src/nsSVGUtils.cpp b/layout/svg/base/src/nsSVGUtils.cpp index 982446b3ead7..f3ef78a2d413 100644 --- a/layout/svg/base/src/nsSVGUtils.cpp +++ b/layout/svg/base/src/nsSVGUtils.cpp @@ -1178,24 +1178,6 @@ nsSVGUtils::GetCoveredRegion(const nsFrameList &aFrames) return rect; } -nsRect -nsSVGUtils::ToAppPixelRect(nsPresContext *aPresContext, - double xmin, double ymin, - double xmax, double ymax) -{ - return ToAppPixelRect(aPresContext, - gfxRect(xmin, ymin, xmax - xmin, ymax - ymin)); -} - -nsRect -nsSVGUtils::ToAppPixelRect(nsPresContext *aPresContext, const gfxRect& rect) -{ - return nsRect(aPresContext->DevPixelsToAppUnits(NSToIntFloor(rect.X())), - aPresContext->DevPixelsToAppUnits(NSToIntFloor(rect.Y())), - aPresContext->DevPixelsToAppUnits(NSToIntCeil(rect.XMost()) - NSToIntFloor(rect.X())), - aPresContext->DevPixelsToAppUnits(NSToIntCeil(rect.YMost()) - NSToIntFloor(rect.Y()))); -} - gfxIntSize nsSVGUtils::ConvertToSurfaceSize(const gfxSize& aSize, bool *aResultOverflows) diff --git a/layout/svg/base/src/nsSVGUtils.h b/layout/svg/base/src/nsSVGUtils.h index 41673f314da6..f44de9c2bbda 100644 --- a/layout/svg/base/src/nsSVGUtils.h +++ b/layout/svg/base/src/nsSVGUtils.h @@ -447,15 +447,6 @@ public: static nsRect GetCoveredRegion(const nsFrameList &aFrames); - /* - * Convert a rect from device pixel units to app pixel units by inflation. - */ - static nsRect - ToAppPixelRect(nsPresContext *aPresContext, - double xmin, double ymin, double xmax, double ymax); - static nsRect - ToAppPixelRect(nsPresContext *aPresContext, const gfxRect& rect); - /* * Convert a surface size to an integer for use by thebes * possibly making it smaller in the process so the surface does not From d36fb51f1ecb2f2e26a11aaa223f402995fa9588 Mon Sep 17 00:00:00 2001 From: Jonathan Watt Date: Fri, 10 Feb 2012 12:33:39 +0000 Subject: [PATCH 03/34] Bug 725903 - PathExtentsToMaxStrokeExtents needs to take a transform argument. r=longsonr. --- layout/svg/base/src/nsSVGGlyphFrame.cpp | 6 ++++-- .../svg/base/src/nsSVGPathGeometryFrame.cpp | 4 +++- layout/svg/base/src/nsSVGUtils.cpp | 20 ++++++++++--------- layout/svg/base/src/nsSVGUtils.h | 6 ++++-- 4 files changed, 22 insertions(+), 14 deletions(-) diff --git a/layout/svg/base/src/nsSVGGlyphFrame.cpp b/layout/svg/base/src/nsSVGGlyphFrame.cpp index 3af5eb5d73db..62b1866ea531 100644 --- a/layout/svg/base/src/nsSVGGlyphFrame.cpp +++ b/layout/svg/base/src/nsSVGGlyphFrame.cpp @@ -487,7 +487,7 @@ nsSVGGlyphFrame::UpdateCoveredRegion() // calls to record and then reset the stroke width. gfxRect extent = tmpCtx->GetUserPathExtent(); if (hasStroke) { - extent = nsSVGUtils::PathExtentsToMaxStrokeExtents(extent, this); + extent = nsSVGUtils::PathExtentsToMaxStrokeExtents(extent, this, matrix); } if (!extent.IsEmpty()) { @@ -621,7 +621,9 @@ nsSVGGlyphFrame::GetBBoxContribution(const gfxMatrix &aToBBoxUserspace, if ((aFlags & nsSVGUtils::eBBoxIncludeStroke) != 0 && ((aFlags & nsSVGUtils::eBBoxIgnoreStrokeIfNone) == 0 || HasStroke())) { bbox = - bbox.Union(nsSVGUtils::PathExtentsToMaxStrokeExtents(pathExtents, this)); + bbox.Union(nsSVGUtils::PathExtentsToMaxStrokeExtents(pathExtents, + this, + aToBBoxUserspace)); } return bbox; diff --git a/layout/svg/base/src/nsSVGPathGeometryFrame.cpp b/layout/svg/base/src/nsSVGPathGeometryFrame.cpp index 241743754da4..bf234663ff01 100644 --- a/layout/svg/base/src/nsSVGPathGeometryFrame.cpp +++ b/layout/svg/base/src/nsSVGPathGeometryFrame.cpp @@ -308,7 +308,9 @@ nsSVGPathGeometryFrame::GetBBoxContribution(const gfxMatrix &aToBBoxUserspace, pathExtents.SizeTo(0, 0); } bbox = - bbox.Union(nsSVGUtils::PathExtentsToMaxStrokeExtents(pathExtents, this)); + bbox.Union(nsSVGUtils::PathExtentsToMaxStrokeExtents(pathExtents, + this, + aToBBoxUserspace)); } // Account for markers: diff --git a/layout/svg/base/src/nsSVGUtils.cpp b/layout/svg/base/src/nsSVGUtils.cpp index f3ef78a2d413..067f9620593d 100644 --- a/layout/svg/base/src/nsSVGUtils.cpp +++ b/layout/svg/base/src/nsSVGUtils.cpp @@ -1477,15 +1477,14 @@ nsSVGUtils::WritePPM(const char *fname, gfxImageSurface *aSurface) static gfxRect PathExtentsToMaxStrokeExtents(const gfxRect& aPathExtents, nsSVGGeometryFrame* aFrame, - double styleExpansionFactor) + double styleExpansionFactor, + const gfxMatrix& aMatrix) { double style_expansion = styleExpansionFactor * aFrame->GetStrokeWidth(); - gfxMatrix ctm = aFrame->GetCanvasTM(); - - double dx = style_expansion * (fabs(ctm.xx) + fabs(ctm.xy)); - double dy = style_expansion * (fabs(ctm.yy) + fabs(ctm.yx)); + double dx = style_expansion * (fabs(aMatrix.xx) + fabs(aMatrix.xy)); + double dy = style_expansion * (fabs(aMatrix.yy) + fabs(aMatrix.yx)); gfxRect strokeExtents = aPathExtents; strokeExtents.Inflate(dx, dy); @@ -1494,14 +1493,16 @@ PathExtentsToMaxStrokeExtents(const gfxRect& aPathExtents, /*static*/ gfxRect nsSVGUtils::PathExtentsToMaxStrokeExtents(const gfxRect& aPathExtents, - nsSVGGeometryFrame* aFrame) + nsSVGGeometryFrame* aFrame, + const gfxMatrix& aMatrix) { - return ::PathExtentsToMaxStrokeExtents(aPathExtents, aFrame, 0.5); + return ::PathExtentsToMaxStrokeExtents(aPathExtents, aFrame, 0.5, aMatrix); } /*static*/ gfxRect nsSVGUtils::PathExtentsToMaxStrokeExtents(const gfxRect& aPathExtents, - nsSVGPathGeometryFrame* aFrame) + nsSVGPathGeometryFrame* aFrame, + const gfxMatrix& aMatrix) { double styleExpansionFactor = 0.5; @@ -1521,7 +1522,8 @@ nsSVGUtils::PathExtentsToMaxStrokeExtents(const gfxRect& aPathExtents, return ::PathExtentsToMaxStrokeExtents(aPathExtents, aFrame, - styleExpansionFactor); + styleExpansionFactor, + aMatrix); } // ---------------------------------------------------------------------- diff --git a/layout/svg/base/src/nsSVGUtils.h b/layout/svg/base/src/nsSVGUtils.h index f44de9c2bbda..07cfabea8eb8 100644 --- a/layout/svg/base/src/nsSVGUtils.h +++ b/layout/svg/base/src/nsSVGUtils.h @@ -572,9 +572,11 @@ public: * This should die once bug 478152 is fixed. */ static gfxRect PathExtentsToMaxStrokeExtents(const gfxRect& aPathExtents, - nsSVGGeometryFrame* aFrame); + nsSVGGeometryFrame* aFrame, + const gfxMatrix& aMatrix); static gfxRect PathExtentsToMaxStrokeExtents(const gfxRect& aPathExtents, - nsSVGPathGeometryFrame* aFrame); + nsSVGPathGeometryFrame* aFrame, + const gfxMatrix& aMatrix); /** * Convert a floating-point value to a 32-bit integer value, clamping to From 8e104f6863ea7eb34049423e45ae4aedaa9e5222 Mon Sep 17 00:00:00 2001 From: Jonathan Watt Date: Fri, 10 Feb 2012 12:33:46 +0000 Subject: [PATCH 04/34] Bug 614732 - For SVG leaf frames, use mRect to store the frame's user space bounds, and stop using it to store its covered region (compute that on demand). r=roc. --- .../backgrounds/vector/empty/reftest.list | 13 ++-- .../svg/base/src/nsSVGForeignObjectFrame.cpp | 59 +++++++++++-------- layout/svg/base/src/nsSVGGlyphFrame.cpp | 13 ++-- layout/svg/base/src/nsSVGImageFrame.cpp | 8 ++- .../svg/base/src/nsSVGPathGeometryFrame.cpp | 14 ++++- layout/svg/base/src/nsSVGUtils.cpp | 33 ++++++++++- layout/svg/base/src/nsSVGUtils.h | 14 +++++ 7 files changed, 108 insertions(+), 46 deletions(-) diff --git a/layout/reftests/backgrounds/vector/empty/reftest.list b/layout/reftests/backgrounds/vector/empty/reftest.list index 8cacdc1e469b..a7be83c99053 100644 --- a/layout/reftests/backgrounds/vector/empty/reftest.list +++ b/layout/reftests/backgrounds/vector/empty/reftest.list @@ -3,15 +3,16 @@ == wide--contain--height.html ref-wide-empty.html == wide--contain--width.html ref-wide-empty.html -# Either OS X 32-bit or 10.5, judging from imprecise Tinderbox results, renders -# these tests as empty boxes, not filled boxes. We don't really care about this +# We don't really care about the failures for this # extreme edge case (the test exists more to test for safety against division by # zero), so there is no bug has been filed to fix it, although a patch would # probably be accepted. -random-if(cocoaWidget) == tall--cover--height.html ref-tall-lime.html -random-if(cocoaWidget) == tall--cover--width.html ref-tall-lime.html -random-if(cocoaWidget) == wide--cover--height.html ref-wide-lime.html -random-if(cocoaWidget) == wide--cover--width.html ref-wide-lime.html +# They're still marked as failing though, rather than 'load', since +# we want to know if they start working when we upgrade to Azure. +fails == tall--cover--height.html ref-tall-lime.html +fails == tall--cover--width.html ref-tall-lime.html +fails == wide--cover--height.html ref-wide-lime.html +fails == wide--cover--width.html ref-wide-lime.html == zero-height-ratio-contain.html ref-tall-empty.html == zero-height-ratio-cover.html ref-tall-empty.html diff --git a/layout/svg/base/src/nsSVGForeignObjectFrame.cpp b/layout/svg/base/src/nsSVGForeignObjectFrame.cpp index 4a930f23cbb8..e5f678db0e5c 100644 --- a/layout/svg/base/src/nsSVGForeignObjectFrame.cpp +++ b/layout/svg/base/src/nsSVGForeignObjectFrame.cpp @@ -229,10 +229,29 @@ nsSVGForeignObjectFrame::PaintSVG(nsSVGRenderState *aContext, return NS_ERROR_FAILURE; } + nsRect kidDirtyRect = kid->GetVisualOverflowRect(); + /* Check if we need to draw anything. */ if (aDirtyRect) { - PRInt32 appUnitsPerDevPx = PresContext()->AppUnitsPerDevPixel(); - if (!mRect.ToOutsidePixels(appUnitsPerDevPx).Intersects(*aDirtyRect)) + // Transform the dirty rect into app units in our userspace. + gfxMatrix invmatrix = matrix; + invmatrix.Invert(); + NS_ASSERTION(!invmatrix.IsSingular(), + "inverse of non-singular matrix should be non-singular"); + + gfxRect transDirtyRect = gfxRect(aDirtyRect->x, aDirtyRect->y, + aDirtyRect->width, aDirtyRect->height); + transDirtyRect = invmatrix.TransformBounds(transDirtyRect); + + kidDirtyRect.IntersectRect(kidDirtyRect, + nsLayoutUtils::RoundGfxRectToAppRect(transDirtyRect, + PresContext()->AppUnitsPerCSSPixel())); + + // XXX after bug 614732 is fixed, we will compare mRect with aDirtyRect, + // not with kidDirtyRect. I.e. + // PRInt32 appUnitsPerDevPx = PresContext()->AppUnitsPerDevPixel(); + // mRect.ToOutsidePixels(appUnitsPerDevPx).Intersects(*aDirtyRect) + if (kidDirtyRect.IsEmpty()) return NS_OK; } @@ -258,17 +277,6 @@ nsSVGForeignObjectFrame::PaintSVG(nsSVGRenderState *aContext, NS_ASSERTION(!invmatrix.IsSingular(), "inverse of non-singular matrix should be non-singular"); - nsRect kidDirtyRect = kid->GetVisualOverflowRect(); - if (aDirtyRect) { - gfxRect transDirtyRect = gfxRect(aDirtyRect->x, aDirtyRect->y, - aDirtyRect->width, aDirtyRect->height); - transDirtyRect = invmatrix.TransformBounds(transDirtyRect); - - kidDirtyRect.IntersectRect(kidDirtyRect, - nsLayoutUtils::RoundGfxRectToAppRect(transDirtyRect, - PresContext()->AppUnitsPerCSSPixel())); - } - PRUint32 flags = nsLayoutUtils::PAINT_IN_TRANSFORM; if (aContext->IsPaintingToWindow()) { flags |= nsLayoutUtils::PAINT_TO_WINDOW; @@ -340,7 +348,7 @@ nsSVGForeignObjectFrame::GetFrameForPoint(const nsPoint &aPoint) NS_IMETHODIMP_(nsRect) nsSVGForeignObjectFrame::GetCoveredRegion() { - return mRect; + return nsSVGUtils::TransformFrameRectToOuterSVG(mRect, GetCanvasTM(), PresContext()); } NS_IMETHODIMP @@ -358,8 +366,10 @@ nsSVGForeignObjectFrame::UpdateCoveredRegion() if (h < 0.0f) h = 0.0f; // GetCanvasTM includes the x,y translation - mRect = ToCanvasBounds(gfxRect(0.0, 0.0, w, h), GetCanvasTM(), PresContext()); - + mRect = nsLayoutUtils::RoundGfxRectToAppRect( + gfxRect(0.0, 0.0, w, h), + PresContext()->AppUnitsPerDevPixel()); + return NS_OK; } @@ -641,19 +651,18 @@ nsSVGForeignObjectFrame::InvalidateDirtyRect(nsSVGOuterSVGFrame* aOuter, if (aRect.IsEmpty()) return; - // The areas dirtied by children are in app units, relative to this frame. - // We need to convert the rect to userspace to use IntersectRect. - - gfxRect r(aRect.x, aRect.y, aRect.width, aRect.height); - r.Scale(1.0 / nsPresContext::AppUnitsPerCSSPixel()); - - nsRect rect = ToCanvasBounds(r, GetCanvasTM(), PresContext()); - // Don't invalidate areas outside our bounds: - rect.IntersectRect(rect, mRect); + nsRect rect = aRect.Intersect(mRect); if (rect.IsEmpty()) return; + // The areas dirtied by children are in app units, relative to this frame. + // We need to convert the rect from app units in our userspace to app units + // relative to our nsSVGOuterSVGFrame's content rect. + + gfxRect r(aRect.x, aRect.y, aRect.width, aRect.height); + r.Scale(1.0 / nsPresContext::AppUnitsPerCSSPixel()); + rect = ToCanvasBounds(r, GetCanvasTM(), PresContext()); rect = nsSVGUtils::FindFilterInvalidation(this, rect); aOuter->InvalidateWithFlags(rect, aFlags); } diff --git a/layout/svg/base/src/nsSVGGlyphFrame.cpp b/layout/svg/base/src/nsSVGGlyphFrame.cpp index 62b1866ea531..5c24dfbe871c 100644 --- a/layout/svg/base/src/nsSVGGlyphFrame.cpp +++ b/layout/svg/base/src/nsSVGGlyphFrame.cpp @@ -440,7 +440,7 @@ nsSVGGlyphFrame::GetFrameForPoint(const nsPoint &aPoint) NS_IMETHODIMP_(nsRect) nsSVGGlyphFrame::GetCoveredRegion() { - return mRect; + return nsSVGUtils::TransformFrameRectToOuterSVG(mRect, GetCanvasTM(), PresContext()); } NS_IMETHODIMP @@ -448,13 +448,9 @@ nsSVGGlyphFrame::UpdateCoveredRegion() { mRect.SetEmpty(); - gfxMatrix matrix = GetCanvasTM(); - if (matrix.IsSingular()) { - return NS_ERROR_FAILURE; - } - + // XXX here we have tmpCtx use its default identity matrix, but does this + // function call anything that will call GetCanvasTM and break things? nsRefPtr tmpCtx = MakeTmpCtx(); - tmpCtx->Multiply(matrix); bool hasStroke = HasStroke(); if (hasStroke) { @@ -487,7 +483,8 @@ nsSVGGlyphFrame::UpdateCoveredRegion() // calls to record and then reset the stroke width. gfxRect extent = tmpCtx->GetUserPathExtent(); if (hasStroke) { - extent = nsSVGUtils::PathExtentsToMaxStrokeExtents(extent, this, matrix); + extent = + nsSVGUtils::PathExtentsToMaxStrokeExtents(extent, this, gfxMatrix()); } if (!extent.IsEmpty()) { diff --git a/layout/svg/base/src/nsSVGImageFrame.cpp b/layout/svg/base/src/nsSVGImageFrame.cpp index 0d55f3f58b46..3cc8fa5ca6f5 100644 --- a/layout/svg/base/src/nsSVGImageFrame.cpp +++ b/layout/svg/base/src/nsSVGImageFrame.cpp @@ -365,7 +365,9 @@ nsSVGImageFrame::PaintSVG(nsSVGRenderState *aContext, if (aDirtyRect) { dirtyRect = aDirtyRect->ToAppUnits(appUnitsPerDevPx); // Adjust dirtyRect to match our local coordinate system. - dirtyRect.MoveBy(-mRect.TopLeft()); + nsRect rootRect = + nsSVGUtils::TransformFrameRectToOuterSVG(mRect, GetCanvasTM(), PresContext()); + dirtyRect.MoveBy(-rootRect.TopLeft()); } // XXXbholley - I don't think huge images in SVGs are common enough to @@ -483,8 +485,8 @@ nsSVGImageFrame::UpdateCoveredRegion() gfxContext context(gfxPlatform::GetPlatform()->ScreenReferenceSurface()); - GeneratePath(&context); - context.IdentityMatrix(); + gfxMatrix identity; + GeneratePath(&context, &identity); gfxRect extent = context.GetUserPathExtent(); diff --git a/layout/svg/base/src/nsSVGPathGeometryFrame.cpp b/layout/svg/base/src/nsSVGPathGeometryFrame.cpp index bf234663ff01..33106b0828ef 100644 --- a/layout/svg/base/src/nsSVGPathGeometryFrame.cpp +++ b/layout/svg/base/src/nsSVGPathGeometryFrame.cpp @@ -159,8 +159,16 @@ nsSVGPathGeometryFrame::GetFrameForPoint(const nsPoint &aPoint) fillRule = GetClipRule(); } else { hitTestFlags = GetHitTestFlags(); + // XXX once bug 614732 is fixed, aPoint won't need any conversion in order + // to compare it with mRect. + gfxMatrix canvasTM = GetCanvasTM(); + if (canvasTM.IsSingular()) { + return nsnull; + } + nsPoint point = + nsSVGUtils::TransformOuterSVGPointToChildFrame(aPoint, canvasTM, PresContext()); if (!hitTestFlags || ((hitTestFlags & SVG_HIT_TEST_CHECK_MRECT) && - !mRect.Contains(aPoint))) + !mRect.Contains(point))) return nsnull; fillRule = GetStyleSVG()->mFillRule; } @@ -196,13 +204,13 @@ nsSVGPathGeometryFrame::GetFrameForPoint(const nsPoint &aPoint) NS_IMETHODIMP_(nsRect) nsSVGPathGeometryFrame::GetCoveredRegion() { - return mRect; + return nsSVGUtils::TransformFrameRectToOuterSVG(mRect, GetCanvasTM(), PresContext()); } NS_IMETHODIMP nsSVGPathGeometryFrame::UpdateCoveredRegion() { - gfxRect extent = GetBBoxContribution(GetCanvasTM(), + gfxRect extent = GetBBoxContribution(gfxMatrix(), nsSVGUtils::eBBoxIncludeFill | nsSVGUtils::eBBoxIgnoreFillIfNone | nsSVGUtils::eBBoxIncludeStroke | nsSVGUtils::eBBoxIgnoreStrokeIfNone | nsSVGUtils::eBBoxIncludeMarkers); diff --git a/layout/svg/base/src/nsSVGUtils.cpp b/layout/svg/base/src/nsSVGUtils.cpp index 067f9620593d..e6ced730902a 100644 --- a/layout/svg/base/src/nsSVGUtils.cpp +++ b/layout/svg/base/src/nsSVGUtils.cpp @@ -1010,8 +1010,10 @@ nsSVGUtils::PaintFrameWithEffects(nsSVGRenderState *aContext, if (!aDirtyRect->Intersects(filterFrame->GetFilterBBox(aFrame, nsnull))) return; } else { + nsRect leafBounds = nsSVGUtils::TransformFrameRectToOuterSVG( + aFrame->GetRect(), GetCanvasTM(aFrame), aFrame->PresContext()); nsRect rect = aDirtyRect->ToAppUnits(aFrame->PresContext()->AppUnitsPerDevPixel()); - if (!rect.Intersects(aFrame->GetRect())) + if (!rect.Intersects(leafBounds)) return; } } @@ -1178,6 +1180,35 @@ nsSVGUtils::GetCoveredRegion(const nsFrameList &aFrames) return rect; } +nsPoint +nsSVGUtils::TransformOuterSVGPointToChildFrame(nsPoint aPoint, + const gfxMatrix& aFrameToCanvasTM, + nsPresContext* aPresContext) +{ + gfxMatrix devToUser = aFrameToCanvasTM; + devToUser.Invert(); + NS_ABORT_IF_FALSE(!devToUser.IsSingular(), "should not get here"); + gfxPoint devPt = gfxPoint(aPoint.x, aPoint.y) / + aPresContext->AppUnitsPerDevPixel(); + gfxPoint userPt = devToUser.Transform(devPt).Round(); + gfxPoint appPt = userPt * aPresContext->AppUnitsPerCSSPixel(); + userPt.x = clamped(appPt.x, gfxFloat(nscoord_MIN), gfxFloat(nscoord_MAX)); + userPt.y = clamped(appPt.y, gfxFloat(nscoord_MIN), gfxFloat(nscoord_MAX)); + // now guaranteed to be safe: + return nsPoint(nscoord(userPt.x), nscoord(userPt.y)); +} + +nsRect +nsSVGUtils::TransformFrameRectToOuterSVG(const nsRect& aRect, + const gfxMatrix& aMatrix, + nsPresContext* aPresContext) +{ + gfxRect r(aRect.x, aRect.y, aRect.width, aRect.height); + r.Scale(1.0 / nsPresContext::AppUnitsPerCSSPixel()); + return nsLayoutUtils::RoundGfxRectToAppRect( + aMatrix.TransformBounds(r), aPresContext->AppUnitsPerDevPixel()); +} + gfxIntSize nsSVGUtils::ConvertToSurfaceSize(const gfxSize& aSize, bool *aResultOverflows) diff --git a/layout/svg/base/src/nsSVGUtils.h b/layout/svg/base/src/nsSVGUtils.h index 07cfabea8eb8..e7fcb2ed3c6d 100644 --- a/layout/svg/base/src/nsSVGUtils.h +++ b/layout/svg/base/src/nsSVGUtils.h @@ -447,6 +447,20 @@ public: static nsRect GetCoveredRegion(const nsFrameList &aFrames); + // Converts aPoint from an app unit point in outer- content rect space + // to an app unit point in a frame's SVG userspace. + // This is a temporary helper we should no longer need after bug 614732 is + // fixed. + static nsPoint + TransformOuterSVGPointToChildFrame(nsPoint aPoint, + const gfxMatrix& aFrameToCanvasTM, + nsPresContext* aPresContext); + + static nsRect + TransformFrameRectToOuterSVG(const nsRect& aRect, + const gfxMatrix& aMatrix, + nsPresContext* aPresContext); + /* * Convert a surface size to an integer for use by thebes * possibly making it smaller in the process so the surface does not From 5e2766c08f65c51bc0087adad2cea7ec4bf20c1f Mon Sep 17 00:00:00 2001 From: Jonathan Watt Date: Fri, 10 Feb 2012 12:33:49 +0000 Subject: [PATCH 05/34] Bug 614732 - Temporary patch to add an mCoveredRegion to SVG leaf frames to cache their covered regions, since we can't reliably compute their pre-change covered regions for invalidation from the user space bounds now in their mRects (see bug 614732 comment 32 solution #1). r=roc. --- layout/svg/base/src/nsSVGForeignObjectFrame.cpp | 5 ++++- layout/svg/base/src/nsSVGForeignObjectFrame.h | 2 ++ layout/svg/base/src/nsSVGGeometryFrame.h | 2 ++ layout/svg/base/src/nsSVGGlyphFrame.cpp | 8 +++++++- layout/svg/base/src/nsSVGImageFrame.cpp | 4 ++++ layout/svg/base/src/nsSVGPathGeometryFrame.cpp | 9 ++++++++- 6 files changed, 27 insertions(+), 3 deletions(-) diff --git a/layout/svg/base/src/nsSVGForeignObjectFrame.cpp b/layout/svg/base/src/nsSVGForeignObjectFrame.cpp index e5f678db0e5c..67de74f79dba 100644 --- a/layout/svg/base/src/nsSVGForeignObjectFrame.cpp +++ b/layout/svg/base/src/nsSVGForeignObjectFrame.cpp @@ -348,7 +348,9 @@ nsSVGForeignObjectFrame::GetFrameForPoint(const nsPoint &aPoint) NS_IMETHODIMP_(nsRect) nsSVGForeignObjectFrame::GetCoveredRegion() { - return nsSVGUtils::TransformFrameRectToOuterSVG(mRect, GetCanvasTM(), PresContext()); + // See bug 614732 comment 32: + //return nsSVGUtils::TransformFrameRectToOuterSVG(mRect, GetCanvasTM(), PresContext()); + return mCoveredRegion; } NS_IMETHODIMP @@ -369,6 +371,7 @@ nsSVGForeignObjectFrame::UpdateCoveredRegion() mRect = nsLayoutUtils::RoundGfxRectToAppRect( gfxRect(0.0, 0.0, w, h), PresContext()->AppUnitsPerDevPixel()); + mCoveredRegion = ToCanvasBounds(gfxRect(0.0, 0.0, w, h), GetCanvasTM(), PresContext()); return NS_OK; } diff --git a/layout/svg/base/src/nsSVGForeignObjectFrame.h b/layout/svg/base/src/nsSVGForeignObjectFrame.h index 2bc685b95faf..f2d016c587fc 100644 --- a/layout/svg/base/src/nsSVGForeignObjectFrame.h +++ b/layout/svg/base/src/nsSVGForeignObjectFrame.h @@ -166,6 +166,8 @@ protected: // Areas dirtied by changes to sub-documents embedded by our decendents nsRegion mSubDocDirtyRegion; + nsRect mCoveredRegion; + bool mInReflow; }; diff --git a/layout/svg/base/src/nsSVGGeometryFrame.h b/layout/svg/base/src/nsSVGGeometryFrame.h index 15065c75b6b3..07e0d6581288 100644 --- a/layout/svg/base/src/nsSVGGeometryFrame.h +++ b/layout/svg/base/src/nsSVGGeometryFrame.h @@ -124,6 +124,8 @@ protected: */ float MaybeOptimizeOpacity(float aFillOrStrokeOpacity); + nsRect mCoveredRegion; + private: bool GetStrokeDashData(FallibleTArray& dashes, gfxFloat *dashOffset); }; diff --git a/layout/svg/base/src/nsSVGGlyphFrame.cpp b/layout/svg/base/src/nsSVGGlyphFrame.cpp index 5c24dfbe871c..3a372b960d7d 100644 --- a/layout/svg/base/src/nsSVGGlyphFrame.cpp +++ b/layout/svg/base/src/nsSVGGlyphFrame.cpp @@ -440,7 +440,9 @@ nsSVGGlyphFrame::GetFrameForPoint(const nsPoint &aPoint) NS_IMETHODIMP_(nsRect) nsSVGGlyphFrame::GetCoveredRegion() { - return nsSVGUtils::TransformFrameRectToOuterSVG(mRect, GetCanvasTM(), PresContext()); + // See bug 614732 comment 32: + //return nsSVGUtils::TransformFrameRectToOuterSVG(mRect, GetCanvasTM(), PresContext()); + return mCoveredRegion; } NS_IMETHODIMP @@ -492,6 +494,10 @@ nsSVGGlyphFrame::UpdateCoveredRegion() PresContext()->AppUnitsPerDevPixel()); } + // See bug 614732 comment 32. + mCoveredRegion = nsSVGUtils::TransformFrameRectToOuterSVG( + mRect, GetCanvasTM(), PresContext()); + return NS_OK; } diff --git a/layout/svg/base/src/nsSVGImageFrame.cpp b/layout/svg/base/src/nsSVGImageFrame.cpp index 3cc8fa5ca6f5..9a2cd3205d6e 100644 --- a/layout/svg/base/src/nsSVGImageFrame.cpp +++ b/layout/svg/base/src/nsSVGImageFrame.cpp @@ -495,6 +495,10 @@ nsSVGImageFrame::UpdateCoveredRegion() PresContext()->AppUnitsPerDevPixel()); } + // See bug 614732 comment 32. + mCoveredRegion = nsSVGUtils::TransformFrameRectToOuterSVG( + mRect, GetCanvasTM(), PresContext()); + return NS_OK; } diff --git a/layout/svg/base/src/nsSVGPathGeometryFrame.cpp b/layout/svg/base/src/nsSVGPathGeometryFrame.cpp index 33106b0828ef..e989c287eb58 100644 --- a/layout/svg/base/src/nsSVGPathGeometryFrame.cpp +++ b/layout/svg/base/src/nsSVGPathGeometryFrame.cpp @@ -204,7 +204,9 @@ nsSVGPathGeometryFrame::GetFrameForPoint(const nsPoint &aPoint) NS_IMETHODIMP_(nsRect) nsSVGPathGeometryFrame::GetCoveredRegion() { - return nsSVGUtils::TransformFrameRectToOuterSVG(mRect, GetCanvasTM(), PresContext()); + // See bug 614732 comment 32: + //return nsSVGUtils::TransformFrameRectToOuterSVG(mRect, GetCanvasTM(), PresContext()); + return mCoveredRegion; } NS_IMETHODIMP @@ -216,6 +218,11 @@ nsSVGPathGeometryFrame::UpdateCoveredRegion() nsSVGUtils::eBBoxIncludeMarkers); mRect = nsLayoutUtils::RoundGfxRectToAppRect(extent, PresContext()->AppUnitsPerDevPixel()); + + // See bug 614732 comment 32. + mCoveredRegion = nsSVGUtils::TransformFrameRectToOuterSVG( + mRect, GetCanvasTM(), PresContext()); + return NS_OK; } From bb2a6b1326fd390fd31f2f47cbfe517346dc46f8 Mon Sep 17 00:00:00 2001 From: Ed Morley Date: Fri, 10 Feb 2012 12:38:05 +0000 Subject: [PATCH 06/34] Bug 725517 - Properly quote $ac_cv_func_dladdr to fix "test: too many arguments" during configure; r=glandium --- configure.in | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/configure.in b/configure.in index 3ea22a76964f..be86d82c4fe1 100644 --- a/configure.in +++ b/configure.in @@ -9063,14 +9063,14 @@ if test -z "$MOZ_NATIVE_NSPR"; then if test -n "$USE_ARM_KUSER"; then ac_configure_args="$ac_configure_args --with-arm-kuser" fi - if test -n "$MOZ_LINKER" -a -z "$MOZ_OLD_LINKER" -a $ac_cv_func_dladdr = no ; then + if test -n "$MOZ_LINKER" -a -z "$MOZ_OLD_LINKER" -a "$ac_cv_func_dladdr" = no ; then # dladdr is supported by the new linker, even when the system linker doesn't # support it. Trick nspr into using dladdr when it's not supported. _SAVE_CPPFLAGS="$CPPFLAGS" export CPPFLAGS="-include $_topsrcdir/mozglue/linker/dladdr.h $CPPFLAGS" fi AC_OUTPUT_SUBDIRS(nsprpub) - if test -n "$MOZ_LINKER" -a -z "$MOZ_OLD_LINKER" -a $ac_cv_func_dladdr = no; then + if test -n "$MOZ_LINKER" -a -z "$MOZ_OLD_LINKER" -a "$ac_cv_func_dladdr" = no; then unset CPPFLAGS CPPFLAGS="$_SAVE_CFLAGS" fi From 807f24ae2cff43cb30d26940526127afa5fad088 Mon Sep 17 00:00:00 2001 From: Ed Morley Date: Fri, 10 Feb 2012 12:38:05 +0000 Subject: [PATCH 07/34] Bug 725524 - Fix check for $MOZ_WEBSMS_BACKEND to prevent "test: -eq: unary operator expected" during configure; r=glandium --- configure.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.in b/configure.in index be86d82c4fe1..70b7630225fe 100644 --- a/configure.in +++ b/configure.in @@ -5481,7 +5481,7 @@ MOZ_ARG_DISABLE_BOOL(websms-backend, MOZ_WEBSMS_BACKEND=, MOZ_WEBSMS_BACKEND=1) -if test $MOZ_WEBSMS_BACKEND -eq 1; then +if test -n "$MOZ_WEBSMS_BACKEND"; then AC_DEFINE(MOZ_WEBSMS_BACKEND) fi From 626e546398c203f2cb84b6ce34fda0e0f89260af Mon Sep 17 00:00:00 2001 From: Ed Morley Date: Fri, 10 Feb 2012 12:40:30 +0000 Subject: [PATCH 08/34] Bug 725429 - Clean up *makefiles.sh, Feb 2012 edition; rs=build mobile/android/makefiles.sh & b2g/makefiles.sh were hg copied from mobile/makefiles.sh prior to it's original cleanup and then move, so most of the changes to them here are just to sync them with mobile/xul/makefiles.sh. --- allmakefiles.sh | 7 +++++ b2g/makefiles.sh | 12 ++------ browser/makefiles.sh | 5 ++++ mobile/android/makefiles.sh | 25 ++++++++-------- mobile/xul/makefiles.sh | 11 +++++-- toolkit/toolkit-makefiles.sh | 58 +++++++++++++++++++++++++++++++----- 6 files changed, 86 insertions(+), 32 deletions(-) diff --git a/allmakefiles.sh b/allmakefiles.sh index 628c72ef8718..d0325ff973d1 100755 --- a/allmakefiles.sh +++ b/allmakefiles.sh @@ -68,6 +68,7 @@ config/nspr/Makefile config/doxygen.cfg config/expandlibs_config.py config/tests/src-simple/Makefile +mfbt/Makefile probes/Makefile extensions/Makefile " @@ -125,6 +126,11 @@ if [ "$ENABLE_TESTS" ]; then add_makefiles " build/autoconf/test/Makefile " + if [ ! "$LIBXUL_SDK" ]; then + add_makefiles " + mozglue/tests/Makefile + " + fi if [ "$_MSC_VER" -a "$OS_TEST" != "x86_64" ]; then add_makefiles " build/win32/vmwarerecordinghelper/Makefile @@ -137,6 +143,7 @@ if [ "$ENABLE_TESTS" ]; then fi if [ "$MOZ_WIDGET_TOOLKIT" = "android" ]; then add_makefiles " + build/mobile/robocop/Makefile build/mobile/sutagent/android/Makefile build/mobile/sutagent/android/fencp/Makefile build/mobile/sutagent/android/ffxcp/Makefile diff --git a/b2g/makefiles.sh b/b2g/makefiles.sh index 8406b1ddf89d..ad14c5d4c398 100644 --- a/b2g/makefiles.sh +++ b/b2g/makefiles.sh @@ -35,21 +35,13 @@ # ***** END LICENSE BLOCK ***** add_makefiles " -netwerk/locales/Makefile -dom/locales/Makefile -toolkit/locales/Makefile -security/manager/locales/Makefile b2g/app/Makefile $MOZ_BRANDING_DIRECTORY/Makefile +$MOZ_BRANDING_DIRECTORY/content/Makefile +$MOZ_BRANDING_DIRECTORY/locales/Makefile b2g/chrome/Makefile b2g/components/Makefile b2g/installer/Makefile b2g/locales/Makefile b2g/Makefile " - -if test -n "$MOZ_UPDATE_PACKAGING"; then - add_makefiles " - tools/update-packaging/Makefile - " -fi diff --git a/browser/makefiles.sh b/browser/makefiles.sh index 6cbd36c69421..e5bc351d0baf 100644 --- a/browser/makefiles.sh +++ b/browser/makefiles.sh @@ -67,6 +67,7 @@ browser/components/shell/Makefile browser/components/shell/public/Makefile browser/components/shell/src/Makefile browser/components/tabview/Makefile +browser/components/thumbnails/Makefile browser/devtools/Makefile browser/devtools/debugger/Makefile browser/devtools/highlighter/Makefile @@ -75,6 +76,7 @@ browser/devtools/shared/Makefile browser/devtools/sourceeditor/Makefile browser/devtools/styleeditor/Makefile browser/devtools/styleinspector/Makefile +browser/devtools/tilt/Makefile browser/devtools/webconsole/Makefile browser/fuel/Makefile browser/fuel/public/Makefile @@ -122,6 +124,7 @@ fi if [ "$ENABLE_TESTS" ]; then add_makefiles " browser/base/content/test/Makefile + browser/base/content/test/newtab/Makefile browser/components/certerror/test/Makefile browser/components/dirprovider/tests/Makefile browser/components/preferences/tests/Makefile @@ -137,6 +140,7 @@ if [ "$ENABLE_TESTS" ]; then browser/components/privatebrowsing/test/browser/Makefile browser/components/tabview/test/Makefile browser/components/test/Makefile + browser/components/thumbnails/test/Makefile browser/devtools/debugger/test/Makefile browser/devtools/highlighter/test/Makefile browser/devtools/scratchpad/test/Makefile @@ -144,6 +148,7 @@ if [ "$ENABLE_TESTS" ]; then browser/devtools/sourceeditor/test/Makefile browser/devtools/styleeditor/test/Makefile browser/devtools/styleinspector/test/Makefile + browser/devtools/tilt/test/Makefile browser/devtools/webconsole/test/Makefile browser/fuel/test/Makefile browser/modules/test/Makefile diff --git a/mobile/android/makefiles.sh b/mobile/android/makefiles.sh index 4d259ef1e304..1e27c17a1960 100644 --- a/mobile/android/makefiles.sh +++ b/mobile/android/makefiles.sh @@ -36,30 +36,31 @@ # ***** END LICENSE BLOCK ***** add_makefiles " -netwerk/locales/Makefile -dom/locales/Makefile -toolkit/locales/Makefile -security/manager/locales/Makefile +mobile/locales/Makefile +mobile/android/Makefile mobile/android/app/Makefile mobile/android/app/profile/extensions/Makefile mobile/android/base/Makefile mobile/android/base/locales/Makefile -mobile/locales/Makefile $MOZ_BRANDING_DIRECTORY/Makefile +$MOZ_BRANDING_DIRECTORY/content/Makefile $MOZ_BRANDING_DIRECTORY/locales/Makefile mobile/android/chrome/Makefile -mobile/android/chrome/tests/Makefile mobile/android/components/Makefile -mobile/android/components/build/Makefile mobile/android/modules/Makefile mobile/android/installer/Makefile mobile/android/locales/Makefile -mobile/android/Makefile mobile/android/themes/core/Makefile " -if test -n "$MOZ_UPDATE_PACKAGING"; then - add_makefiles " - tools/update-packaging/Makefile - " +if [ ! "$LIBXUL_SDK" ]; then + add_makefiles " + mobile/android/components/build/Makefile + " +fi + +if [ "$ENABLE_TESTS" ]; then + add_makefiles " + mobile/android/chrome/tests/Makefile + " fi diff --git a/mobile/xul/makefiles.sh b/mobile/xul/makefiles.sh index d0eb64c54966..3d713f1a00a2 100644 --- a/mobile/xul/makefiles.sh +++ b/mobile/xul/makefiles.sh @@ -36,6 +36,8 @@ # ***** END LICENSE BLOCK ***** add_makefiles " +mobile/locales/Makefile +mobile/xul/Makefile mobile/xul/app/Makefile mobile/xul/app/profile/extensions/Makefile $MOZ_BRANDING_DIRECTORY/Makefile @@ -43,15 +45,18 @@ $MOZ_BRANDING_DIRECTORY/content/Makefile $MOZ_BRANDING_DIRECTORY/locales/Makefile mobile/xul/chrome/Makefile mobile/xul/components/Makefile -mobile/xul/components/build/Makefile mobile/xul/modules/Makefile mobile/xul/installer/Makefile mobile/xul/locales/Makefile -mobile/locales/Makefile -mobile/xul/Makefile mobile/xul/themes/core/Makefile " +if [ ! "$LIBXUL_SDK" ]; then + add_makefiles " + mobile/xul/components/build/Makefile + " +fi + if [ "$ENABLE_TESTS" ]; then add_makefiles " mobile/xul/chrome/tests/Makefile diff --git a/toolkit/toolkit-makefiles.sh b/toolkit/toolkit-makefiles.sh index afb7c132133b..b02f33eba4e7 100644 --- a/toolkit/toolkit-makefiles.sh +++ b/toolkit/toolkit-makefiles.sh @@ -67,10 +67,17 @@ MAKEFILES_dom=" dom/interfaces/xbl/Makefile dom/interfaces/xpath/Makefile dom/interfaces/xul/Makefile - dom/ipc/Makefile dom/base/Makefile dom/battery/Makefile dom/indexedDB/Makefile + dom/ipc/Makefile + dom/locales/Makefile + dom/network/Makefile + dom/network/interfaces/Makefile + dom/network/src/Makefile + dom/plugins/base/Makefile + dom/plugins/ipc/Makefile + dom/power/Makefile dom/sms/Makefile dom/sms/interfaces/Makefile dom/sms/src/Makefile @@ -84,9 +91,6 @@ MAKEFILES_dom=" dom/src/storage/Makefile dom/system/Makefile dom/workers/Makefile - dom/locales/Makefile - dom/plugins/base/Makefile - dom/plugins/ipc/Makefile " MAKEFILES_editor=" @@ -255,6 +259,7 @@ MAKEFILES_layout=" layout/ipc/Makefile layout/inspector/public/Makefile layout/inspector/src/Makefile + layout/media/Makefile layout/style/Makefile layout/style/xbl-marquee/Makefile layout/tables/Makefile @@ -468,7 +473,6 @@ MAKEFILES_xulapp=" toolkit/components/filepicker/Makefile toolkit/components/find/Makefile toolkit/components/intl/Makefile - toolkit/components/maintenanceservice/Makefile toolkit/components/microformats/Makefile toolkit/components/parentalcontrols/Makefile toolkit/components/passwordmgr/Makefile @@ -714,6 +718,7 @@ if [ "$ENABLE_TESTS" ]; then chrome/test/Makefile content/base/test/Makefile content/base/test/chrome/Makefile + content/base/test/websocket_hybi/Makefile content/canvas/test/Makefile content/canvas/test/crossorigin/Makefile content/canvas/test/webgl/Makefile @@ -736,8 +741,11 @@ if [ "$ENABLE_TESTS" ]; then docshell/test/navigation/Makefile dom/battery/test/Makefile dom/indexedDB/test/Makefile + dom/indexedDB/test/unit/Makefile + dom/network/tests/Makefile dom/plugins/test/Makefile dom/plugins/test/testplugin/Makefile + dom/power/test/Makefile dom/sms/tests/Makefile dom/src/foo/Makefile dom/src/json/test/Makefile @@ -894,6 +902,7 @@ if [ "$ENABLE_TESTS" ]; then toolkit/content/tests/chrome/rtlchrome/Makefile toolkit/content/tests/chrome/rtltest/Makefile toolkit/content/tests/widgets/Makefile + toolkit/devtools/debugger/tests/Makefile toolkit/mozapps/downloads/tests/Makefile toolkit/mozapps/downloads/tests/chrome/Makefile toolkit/mozapps/extensions/test/Makefile @@ -926,11 +935,13 @@ if [ "$ENABLE_TESTS" ]; then accessible/tests/mochitest/hyperlink/Makefile accessible/tests/mochitest/hypertext/Makefile accessible/tests/mochitest/name/Makefile + accessible/tests/mochitest/pivot/Makefile accessible/tests/mochitest/relations/Makefile accessible/tests/mochitest/selectable/Makefile accessible/tests/mochitest/states/Makefile accessible/tests/mochitest/table/Makefile accessible/tests/mochitest/text/Makefile + accessible/tests/mochitest/textcaret/Makefile accessible/tests/mochitest/textselection/Makefile accessible/tests/mochitest/tree/Makefile accessible/tests/mochitest/treeupdate/Makefile @@ -1007,6 +1018,11 @@ if [ "$ENABLE_TESTS" ]; then toolkit/mozapps/update/test/chrome/Makefile " fi + if [ "$MOZ_MAINTENANCE_SERVICE" ]; then + add_makefiles " + toolkit/mozapps/update/test_svc/Makefile + " + fi fi if [ "$MOZ_URL_CLASSIFIER" ]; then add_makefiles " @@ -1038,7 +1054,7 @@ if [ "$ENABLE_TESTS" ]; then toolkit/components/downloads/test/browser/Makefile toolkit/components/passwordmgr/test/browser/Makefile toolkit/components/places/tests/browser/Makefile - toolkit/components/startup/tests/Makefile + toolkit/components/startup/tests/browser/Makefile toolkit/content/tests/browser/Makefile toolkit/content/tests/browser/common/Makefile toolkit/content/tests/browser/data/Makefile @@ -1071,6 +1087,11 @@ if [ "$ENABLE_TESTS" ]; then xpcom/tests/windows/Makefile " fi + if [ "$MOZ_BUILD_APP" = "mobile/android" ]; then + add_makefiles " + testing/mochitest/roboextender/Makefile + " + fi fi @@ -1142,6 +1163,7 @@ if [ "$MOZ_B2G_RIL" ]; then add_makefiles " dom/system/b2g/Makefile dom/telephony/Makefile + dom/wifi/Makefile ipc/ril/Makefile " fi @@ -1250,6 +1272,12 @@ if [ "$MOZ_FEEDS" ]; then " fi +if [ "$MOZ_GRAPHITE" ]; then + add_makefiles " + gfx/graphite2/src/Makefile + " +fi + if [ "$MOZ_HELP_VIEWER" ]; then add_makefiles " toolkit/components/help/Makefile @@ -1286,6 +1314,12 @@ if [ "$MOZ_JSDEBUGGER" ]; then " fi +if [ "$MOZ_MAINTENANCE_SERVICE" ]; then + add_makefiles " + toolkit/components/maintenanceservice/Makefile + " +fi + if [ ! "$MOZ_NATIVE_SQLITE" ]; then add_makefiles " db/sqlite3/src/Makefile @@ -1330,7 +1364,6 @@ if [ "$MOZ_UPDATER" ]; then modules/libmar/Makefile modules/libmar/src/Makefile modules/libmar/tool/Makefile - toolkit/mozapps/readstrings/Makefile " if [ ! "$SYSTEM_BZ2" ]; then add_makefiles " @@ -1345,6 +1378,17 @@ if [ "$MOZ_UPDATER" ]; then fi fi +if [ "$MOZ_UPDATER" -o "$MOZ_MAINTENANCE_SERVICE" ]; then + add_makefiles " + toolkit/mozapps/readstrings/Makefile + " + if [ "$OS_TARGET" != "Android" ]; then + add_makefiles " + toolkit/mozapps/update/common/Makefile + " + fi +fi + if [ "$MOZ_UPDATER" -o "$MOZ_UPDATE_PACKAGING" ]; then add_makefiles " other-licenses/bsdiff/Makefile From f3e79511f41fd16bd58955ac7a52707fa4ccc9cd Mon Sep 17 00:00:00 2001 From: Veeraya Pupatwibul Date: Fri, 10 Feb 2012 14:11:53 +0100 Subject: [PATCH 09/34] Bug 722305 - Remove contentAreaClick's redundant return value. r=dao --- browser/base/content/browser.js | 16 +++++++--------- browser/base/content/browser.xul | 2 +- .../content/test/browser_contentAreaClick.js | 2 +- browser/base/content/web-panels.xul | 2 +- 4 files changed, 10 insertions(+), 12 deletions(-) diff --git a/browser/base/content/browser.js b/browser/base/content/browser.js index e2ecfd7e8850..4dd85bebf4fc 100644 --- a/browser/base/content/browser.js +++ b/browser/base/content/browser.js @@ -5865,7 +5865,7 @@ function hrefAndLinkNodeForClickEvent(event) function contentAreaClick(event, isPanelClick) { if (!event.isTrusted || event.defaultPrevented || event.button == 2) - return true; + return; let [href, linkNode] = hrefAndLinkNodeForClickEvent(event); if (!href) { @@ -5876,7 +5876,7 @@ function contentAreaClick(event, isPanelClick) middleMousePaste(event); event.preventDefault(); } - return true; + return; } // This code only applies if we have a linkNode (i.e. clicks on real anchor @@ -5893,7 +5893,7 @@ function contentAreaClick(event, isPanelClick) if (linkNode.getAttribute("onclick") || href.substr(0, 11) === "javascript:" || href.substr(0, 5) === "data:") - return true; + return; try { urlSecurityCheck(href, linkNode.ownerDocument.nodePrincipal); @@ -5901,16 +5901,16 @@ function contentAreaClick(event, isPanelClick) catch(ex) { // Prevent loading unsecure destinations. event.preventDefault(); - return true; + return; } let postData = {}; let url = getShortcutOrURI(href, postData); if (!url) - return true; + return; loadURI(url, null, postData.value, false); event.preventDefault(); - return true; + return; } if (linkNode.getAttribute("rel") == "sidebar") { @@ -5927,7 +5927,7 @@ function contentAreaClick(event, isPanelClick) , "keyword" ] }, window); event.preventDefault(); - return true; + return; } } @@ -5940,8 +5940,6 @@ function contentAreaClick(event, isPanelClick) try { PlacesUIUtils.markPageAsFollowedLink(href); } catch (ex) { /* Skip invalid URIs. */ } - - return true; } /** diff --git a/browser/base/content/browser.xul b/browser/base/content/browser.xul index 13ccc2833085..64c99679b3f4 100644 --- a/browser/base/content/browser.xul +++ b/browser/base/content/browser.xul @@ -966,7 +966,7 @@ tabcontainer="tabbrowser-tabs" contentcontextmenu="contentAreaContextMenu" autocompletepopup="PopupAutoComplete" - onclick="return contentAreaClick(event, false);"/> + onclick="contentAreaClick(event, false);"/> diff --git a/browser/base/content/test/browser_contentAreaClick.js b/browser/base/content/test/browser_contentAreaClick.js index f151f5f21b7b..e5097e75e008 100644 --- a/browser/base/content/test/browser_contentAreaClick.js +++ b/browser/base/content/test/browser_contentAreaClick.js @@ -232,7 +232,7 @@ let gClickHandler = { gCurrentTest.desc + ":Handler received a click event on " + linkId); let isPanelClick = linkId == "panellink"; - let returnValue = gTestWin.contentAreaClick(event, isPanelClick); + gTestWin.contentAreaClick(event, isPanelClick); let prevent = event.defaultPrevented; is(prevent, gCurrentTest.preventDefault, gCurrentTest.desc + ": event.defaultPrevented is correct (" + prevent + ")") diff --git a/browser/base/content/web-panels.xul b/browser/base/content/web-panels.xul index 6d3d1910f84f..b68dcd214788 100644 --- a/browser/base/content/web-panels.xul +++ b/browser/base/content/web-panels.xul @@ -98,5 +98,5 @@ + onclick="window.parent.contentAreaClick(event, true);"/> From 3e44c9c61a3758fd6e2f7c3da6c77fbbaf96c04b Mon Sep 17 00:00:00 2001 From: Julian Reschke Date: Fri, 10 Feb 2012 14:12:51 +0100 Subject: [PATCH 10/34] Bug 598304 - XHR rewrites non-POST methods upon 301/302 redirects. r=bz --- netwerk/protocol/http/HttpBaseChannel.cpp | 9 ++++----- netwerk/test/unit/test_XHR_redirects.js | 18 +++++++++--------- 2 files changed, 13 insertions(+), 14 deletions(-) diff --git a/netwerk/protocol/http/HttpBaseChannel.cpp b/netwerk/protocol/http/HttpBaseChannel.cpp index d5bcfd603e99..a1007e182c26 100644 --- a/netwerk/protocol/http/HttpBaseChannel.cpp +++ b/netwerk/protocol/http/HttpBaseChannel.cpp @@ -1552,14 +1552,13 @@ bool HttpBaseChannel::ShouldRewriteRedirectToGET(PRUint32 httpStatus, nsHttpAtom method) { - // always rewrite for 301 and 302, but see bug 598304 - // and RFC 2616, Section 8.3. + // for 301 and 302, only rewrite POST if (httpStatus == 301 || httpStatus == 302) - return true; + return method == nsHttp::Post; - // always rewrite for 303 + // rewrite for 303 unless it was HEAD if (httpStatus == 303) - return true; + return method != nsHttp::Head; // otherwise, such as for 307, do not rewrite return false; diff --git a/netwerk/test/unit/test_XHR_redirects.js b/netwerk/test/unit/test_XHR_redirects.js index 697a650e60de..6908c80f8929 100644 --- a/netwerk/test/unit/test_XHR_redirects.js +++ b/netwerk/test/unit/test_XHR_redirects.js @@ -75,23 +75,23 @@ function run_test() { // same-origin variant var tests = [ // 301: rewrite just POST - [301, "DELETE", "GET", 200], // but see bug 598304 + [301, "DELETE", null, 301], [301, "GET", "GET", 200], - [301, "HEAD", "GET", 200], // but see bug 598304 + [301, "HEAD", "HEAD", 200], [301, "POST", "GET", 200], - [301, "PUT", "GET", 200], // but see bug 598304 - [301, "PROPFIND", "GET", 200], // but see bug 598304 + [301, "PUT", null, 301], + [301, "PROPFIND", "PROPFIND", 200], // 302: see 301 - [302, "DELETE", "GET", 200], // but see bug 598304 + [302, "DELETE", null, 302], [302, "GET", "GET", 200], - [302, "HEAD", "GET", 200], // but see bug 598304 + [302, "HEAD", "HEAD", 200], [302, "POST", "GET", 200], - [302, "PUT", "GET", 200], // but see bug 598304 - [302, "PROPFIND", "GET", 200], // but see bug 598304 + [302, "PUT", null, 302], + [302, "PROPFIND", "PROPFIND", 200], // 303: rewrite to GET except HEAD [303, "DELETE", "GET", 200], [303, "GET", "GET", 200], - [303, "HEAD", "GET", 200], + [303, "HEAD", "HEAD", 200], [303, "POST", "GET", 200], [303, "PUT", "GET", 200], [303, "PROPFIND", "GET", 200], From 5eef1757823b4ffb9dd57b1f76ccc5fdb0dc3374 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Str=C3=A1nsk=C3=BD?= Date: Fri, 10 Feb 2012 14:15:28 +0100 Subject: [PATCH 11/34] Bug 627699 - Port GTK2 to GTK3, gkt3drawing part. r=karlt --HG-- rename : widget/gtk2/gtk2drawing.c => widget/gtk2/gtk3drawing.c --- widget/gtk2/gtk3drawing.c | 3338 +++++++++++++++++++++++++++++++++++++ widget/gtk2/gtkdrawing.h | 10 + 2 files changed, 3348 insertions(+) create mode 100644 widget/gtk2/gtk3drawing.c diff --git a/widget/gtk2/gtk3drawing.c b/widget/gtk2/gtk3drawing.c new file mode 100644 index 000000000000..49dfb4d9afa6 --- /dev/null +++ b/widget/gtk2/gtk3drawing.c @@ -0,0 +1,3338 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Brian Ryner (Original Author) + * Pierre Chanial + * Michael Ventnor + * Martin Stransky + * Jan Horak + * + * 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 file contains painting functions for each of the gtk2 widgets. + * Adapted from the gtkdrawing.c, and gtk+2.0 source. + */ + +#include +#include +#include +#include "gtkdrawing.h" +#include "nsDebug.h" +#include "prinrval.h" + +#include + +static GtkWidget* gProtoWindow; +static GtkWidget* gProtoLayout; +static GtkWidget* gButtonWidget; +static GtkWidget* gToggleButtonWidget; +static GtkWidget* gButtonArrowWidget; +static GtkWidget* gCheckboxWidget; +static GtkWidget* gRadiobuttonWidget; +static GtkWidget* gHorizScrollbarWidget; +static GtkWidget* gVertScrollbarWidget; +static GtkWidget* gSpinWidget; +static GtkWidget* gHScaleWidget; +static GtkWidget* gVScaleWidget; +static GtkWidget* gEntryWidget; +static GtkWidget* gComboBoxWidget; +static GtkWidget* gComboBoxButtonWidget; +static GtkWidget* gComboBoxArrowWidget; +static GtkWidget* gComboBoxSeparatorWidget; +static GtkWidget* gComboBoxEntryWidget; +static GtkWidget* gComboBoxEntryTextareaWidget; +static GtkWidget* gComboBoxEntryButtonWidget; +static GtkWidget* gComboBoxEntryArrowWidget; +static GtkWidget* gHandleBoxWidget; +static GtkWidget* gToolbarWidget; +static GtkWidget* gFrameWidget; +static GtkWidget* gStatusbarWidget; +static GtkWidget* gProgressWidget; +static GtkWidget* gTabWidget; +static GtkWidget* gTooltipWidget; +static GtkWidget* gMenuBarWidget; +static GtkWidget* gMenuBarItemWidget; +static GtkWidget* gMenuPopupWidget; +static GtkWidget* gMenuItemWidget; +static GtkWidget* gImageMenuItemWidget; +static GtkWidget* gCheckMenuItemWidget; +static GtkWidget* gTreeViewWidget; +static GtkTreeViewColumn* gMiddleTreeViewColumn; +static GtkWidget* gTreeHeaderCellWidget; +static GtkWidget* gTreeHeaderSortArrowWidget; +static GtkWidget* gExpanderWidget; +static GtkWidget* gToolbarSeparatorWidget; +static GtkWidget* gMenuSeparatorWidget; +static GtkWidget* gHPanedWidget; +static GtkWidget* gVPanedWidget; +static GtkWidget* gScrolledWindowWidget; + +static style_prop_t style_prop_func; +static gboolean have_arrow_scaling; +static gboolean is_initialized; + +#define ARROW_UP 0 +#define ARROW_DOWN G_PI +#define ARROW_RIGHT G_PI_2 +#define ARROW_LEFT (G_PI+G_PI_2) + +static GtkStateFlags +GetStateFlagsFromGtkWidgetState(GtkWidgetState* state) +{ + GtkStateFlags stateFlags = GTK_STATE_FLAG_NORMAL; + + if (state->disabled) + stateFlags = GTK_STATE_FLAG_INSENSITIVE; + else { + if (state->depressed || state->active) + stateFlags |= GTK_STATE_FLAG_ACTIVE; + if (state->inHover) + stateFlags |= GTK_STATE_FLAG_PRELIGHT; + if (state->focused) + stateFlags |= GTK_STATE_FLAG_FOCUSED; + } + + return stateFlags; +} + +/* Because we have such an unconventional way of drawing widgets, signal to the GTK theme engine + that they are drawing for Mozilla instead of a conventional GTK app so they can do any specific + things they may want to do. */ +static void +moz_gtk_set_widget_name(GtkWidget* widget) +{ + gtk_widget_set_name(widget, "MozillaGtkWidget"); +} + +gint +moz_gtk_enable_style_props(style_prop_t styleGetProp) +{ + style_prop_func = styleGetProp; + return MOZ_GTK_SUCCESS; +} + +static gint +ensure_window_widget() +{ + if (!gProtoWindow) { + gProtoWindow = gtk_window_new(GTK_WINDOW_POPUP); + gtk_widget_realize(gProtoWindow); + moz_gtk_set_widget_name(gProtoWindow); + } + return MOZ_GTK_SUCCESS; +} + +static gint +setup_widget_prototype(GtkWidget* widget) +{ + ensure_window_widget(); + if (!gProtoLayout) { + gProtoLayout = gtk_fixed_new(); + gtk_container_add(GTK_CONTAINER(gProtoWindow), gProtoLayout); + } + + gtk_container_add(GTK_CONTAINER(gProtoLayout), widget); + gtk_widget_realize(widget); + return MOZ_GTK_SUCCESS; +} + +static gint +ensure_button_widget() +{ + if (!gButtonWidget) { + gButtonWidget = gtk_button_new_with_label("M"); + setup_widget_prototype(gButtonWidget); + } + return MOZ_GTK_SUCCESS; +} + +static gint +ensure_hpaned_widget() +{ + if (!gHPanedWidget) { + gHPanedWidget = gtk_hpaned_new(); + setup_widget_prototype(gHPanedWidget); + } + return MOZ_GTK_SUCCESS; +} + +static gint +ensure_vpaned_widget() +{ + if (!gVPanedWidget) { + gVPanedWidget = gtk_vpaned_new(); + setup_widget_prototype(gVPanedWidget); + } + return MOZ_GTK_SUCCESS; +} + +static gint +ensure_toggle_button_widget() +{ + if (!gToggleButtonWidget) { + gToggleButtonWidget = gtk_toggle_button_new(); + setup_widget_prototype(gToggleButtonWidget); + } + return MOZ_GTK_SUCCESS; +} + +static gint +ensure_button_arrow_widget() +{ + if (!gButtonArrowWidget) { + ensure_toggle_button_widget(); + + gButtonArrowWidget = gtk_arrow_new(GTK_ARROW_DOWN, GTK_SHADOW_OUT); + gtk_container_add(GTK_CONTAINER(gToggleButtonWidget), gButtonArrowWidget); + gtk_widget_realize(gButtonArrowWidget); + } + return MOZ_GTK_SUCCESS; +} + +static gint +ensure_checkbox_widget() +{ + if (!gCheckboxWidget) { + gCheckboxWidget = gtk_check_button_new_with_label("M"); + setup_widget_prototype(gCheckboxWidget); + } + return MOZ_GTK_SUCCESS; +} + +static gint +ensure_radiobutton_widget() +{ + if (!gRadiobuttonWidget) { + gRadiobuttonWidget = gtk_radio_button_new_with_label(NULL, "M"); + setup_widget_prototype(gRadiobuttonWidget); + } + return MOZ_GTK_SUCCESS; +} + +static gint +ensure_scrollbar_widget() +{ + if (!gVertScrollbarWidget) { + gVertScrollbarWidget = gtk_vscrollbar_new(NULL); + setup_widget_prototype(gVertScrollbarWidget); + } + if (!gHorizScrollbarWidget) { + gHorizScrollbarWidget = gtk_hscrollbar_new(NULL); + setup_widget_prototype(gHorizScrollbarWidget); + } + return MOZ_GTK_SUCCESS; +} + +static gint +ensure_spin_widget() +{ + if (!gSpinWidget) { + gSpinWidget = gtk_spin_button_new(NULL, 1, 0); + setup_widget_prototype(gSpinWidget); + } + return MOZ_GTK_SUCCESS; +} + +static gint +ensure_scale_widget() +{ + if (!gHScaleWidget) { + gHScaleWidget = gtk_hscale_new(NULL); + setup_widget_prototype(gHScaleWidget); + } + if (!gVScaleWidget) { + gVScaleWidget = gtk_vscale_new(NULL); + setup_widget_prototype(gVScaleWidget); + } + return MOZ_GTK_SUCCESS; +} + +static gint +ensure_entry_widget() +{ + if (!gEntryWidget) { + gEntryWidget = gtk_entry_new(); + setup_widget_prototype(gEntryWidget); + } + return MOZ_GTK_SUCCESS; +} + +/* We need to have pointers to the inner widgets (button, separator, arrow) + * of the ComboBox to get the correct rendering from theme engines which + * special cases their look. Since the inner layout can change, we ask GTK + * to NULL our pointers when they are about to become invalid because the + * corresponding widgets don't exist anymore. It's the role of + * g_object_add_weak_pointer(). + * Note that if we don't find the inner widgets (which shouldn't happen), we + * fallback to use generic "non-inner" widgets, and they don't need that kind + * of weak pointer since they are explicit children of gProtoWindow and as + * such GTK holds a strong reference to them. */ +static void +moz_gtk_get_combo_box_inner_button(GtkWidget *widget, gpointer client_data) +{ + if (GTK_IS_TOGGLE_BUTTON(widget)) { + gComboBoxButtonWidget = widget; + g_object_add_weak_pointer(G_OBJECT(widget), + (gpointer) &gComboBoxButtonWidget); + gtk_widget_realize(widget); + } +} + +static void +moz_gtk_get_combo_box_button_inner_widgets(GtkWidget *widget, + gpointer client_data) +{ + if (GTK_IS_SEPARATOR(widget)) { + gComboBoxSeparatorWidget = widget; + g_object_add_weak_pointer(G_OBJECT(widget), + (gpointer) &gComboBoxSeparatorWidget); + } else if (GTK_IS_ARROW(widget)) { + gComboBoxArrowWidget = widget; + g_object_add_weak_pointer(G_OBJECT(widget), + (gpointer) &gComboBoxArrowWidget); + } else + return; + gtk_widget_realize(widget); +} + +static gint +ensure_combo_box_widgets() +{ + GtkWidget* buttonChild; + + if (gComboBoxButtonWidget && gComboBoxArrowWidget) + return MOZ_GTK_SUCCESS; + + /* Create a ComboBox if needed */ + if (!gComboBoxWidget) { + gComboBoxWidget = gtk_combo_box_new(); + setup_widget_prototype(gComboBoxWidget); + } + + /* Get its inner Button */ + gtk_container_forall(GTK_CONTAINER(gComboBoxWidget), + moz_gtk_get_combo_box_inner_button, + NULL); + + if (gComboBoxButtonWidget) { + /* Get the widgets inside the Button */ + buttonChild = gtk_bin_get_child(GTK_BIN(gComboBoxButtonWidget)); + if (GTK_IS_HBOX(buttonChild)) { + /* appears-as-list = FALSE, cell-view = TRUE; the button + * contains an hbox. This hbox is there because the ComboBox + * needs to place a cell renderer, a separator, and an arrow in + * the button when appears-as-list is FALSE. */ + gtk_container_forall(GTK_CONTAINER(buttonChild), + moz_gtk_get_combo_box_button_inner_widgets, + NULL); + } else if(GTK_IS_ARROW(buttonChild)) { + /* appears-as-list = TRUE, or cell-view = FALSE; + * the button only contains an arrow */ + gComboBoxArrowWidget = buttonChild; + g_object_add_weak_pointer(G_OBJECT(buttonChild), (gpointer) + &gComboBoxArrowWidget); + gtk_widget_realize(gComboBoxArrowWidget); + } + } else { + /* Shouldn't be reached with current internal gtk implementation; we + * use a generic toggle button as last resort fallback to avoid + * crashing. */ + ensure_toggle_button_widget(); + gComboBoxButtonWidget = gToggleButtonWidget; + } + + if (!gComboBoxArrowWidget) { + /* Shouldn't be reached with current internal gtk implementation; + * we gButtonArrowWidget as last resort fallback to avoid + * crashing. */ + ensure_button_arrow_widget(); + gComboBoxArrowWidget = gButtonArrowWidget; + } + + /* We don't test the validity of gComboBoxSeparatorWidget since there + * is none when "appears-as-list" = TRUE or "cell-view" = FALSE; if it + * is invalid we just won't paint it. */ + + return MOZ_GTK_SUCCESS; +} + +/* We need to have pointers to the inner widgets (entry, button, arrow) of + * the ComboBoxEntry to get the correct rendering from theme engines which + * special cases their look. Since the inner layout can change, we ask GTK + * to NULL our pointers when they are about to become invalid because the + * corresponding widgets don't exist anymore. It's the role of + * g_object_add_weak_pointer(). + * Note that if we don't find the inner widgets (which shouldn't happen), we + * fallback to use generic "non-inner" widgets, and they don't need that kind + * of weak pointer since they are explicit children of gProtoWindow and as + * such GTK holds a strong reference to them. */ +static void +moz_gtk_get_combo_box_entry_inner_widgets(GtkWidget *widget, + gpointer client_data) +{ + if (GTK_IS_TOGGLE_BUTTON(widget)) { + gComboBoxEntryButtonWidget = widget; + g_object_add_weak_pointer(G_OBJECT(widget), + (gpointer) &gComboBoxEntryButtonWidget); + } else if (GTK_IS_ENTRY(widget)) { + gComboBoxEntryTextareaWidget = widget; + g_object_add_weak_pointer(G_OBJECT(widget), + (gpointer) &gComboBoxEntryTextareaWidget); + } else + return; + gtk_widget_realize(widget); +} + +static void +moz_gtk_get_combo_box_entry_arrow(GtkWidget *widget, gpointer client_data) +{ + if (GTK_IS_ARROW(widget)) { + gComboBoxEntryArrowWidget = widget; + g_object_add_weak_pointer(G_OBJECT(widget), + (gpointer) &gComboBoxEntryArrowWidget); + gtk_widget_realize(widget); + } +} + +static gint +ensure_combo_box_entry_widgets() +{ + GtkWidget* buttonChild; + + if (gComboBoxEntryTextareaWidget && + gComboBoxEntryButtonWidget && + gComboBoxEntryArrowWidget) + return MOZ_GTK_SUCCESS; + + /* Create a ComboBoxEntry if needed */ + if (!gComboBoxEntryWidget) { + gComboBoxEntryWidget = NULL; /* TODO - gtk_combo_box_entry_new();*/ + setup_widget_prototype(gComboBoxEntryWidget); + } + + /* Get its inner Entry and Button */ + gtk_container_forall(GTK_CONTAINER(gComboBoxEntryWidget), + moz_gtk_get_combo_box_entry_inner_widgets, + NULL); + + if (!gComboBoxEntryTextareaWidget) { + ensure_entry_widget(); + gComboBoxEntryTextareaWidget = gEntryWidget; + } + + if (gComboBoxEntryButtonWidget) { + /* Get the Arrow inside the Button */ + buttonChild = gtk_bin_get_child(GTK_BIN(gComboBoxEntryButtonWidget)); + if (GTK_IS_HBOX(buttonChild)) { + /* appears-as-list = FALSE, cell-view = TRUE; the button + * contains an hbox. This hbox is there because ComboBoxEntry + * inherits from ComboBox which needs to place a cell renderer, + * a separator, and an arrow in the button when appears-as-list + * is FALSE. Here the hbox should only contain an arrow, since + * a ComboBoxEntry doesn't need all those widgets in the + * button. */ + gtk_container_forall(GTK_CONTAINER(buttonChild), + moz_gtk_get_combo_box_entry_arrow, + NULL); + } else if(GTK_IS_ARROW(buttonChild)) { + /* appears-as-list = TRUE, or cell-view = FALSE; + * the button only contains an arrow */ + gComboBoxEntryArrowWidget = buttonChild; + g_object_add_weak_pointer(G_OBJECT(buttonChild), (gpointer) + &gComboBoxEntryArrowWidget); + gtk_widget_realize(gComboBoxEntryArrowWidget); + } + } else { + /* Shouldn't be reached with current internal gtk implementation; + * we use a generic toggle button as last resort fallback to avoid + * crashing. */ + ensure_toggle_button_widget(); + gComboBoxEntryButtonWidget = gToggleButtonWidget; + } + + if (!gComboBoxEntryArrowWidget) { + /* Shouldn't be reached with current internal gtk implementation; + * we gButtonArrowWidget as last resort fallback to avoid + * crashing. */ + ensure_button_arrow_widget(); + gComboBoxEntryArrowWidget = gButtonArrowWidget; + } + + return MOZ_GTK_SUCCESS; +} + + +static gint +ensure_handlebox_widget() +{ + if (!gHandleBoxWidget) { + gHandleBoxWidget = gtk_handle_box_new(); + setup_widget_prototype(gHandleBoxWidget); + } + return MOZ_GTK_SUCCESS; +} + +static gint +ensure_toolbar_widget() +{ + if (!gToolbarWidget) { + ensure_handlebox_widget(); + gToolbarWidget = gtk_toolbar_new(); + gtk_container_add(GTK_CONTAINER(gHandleBoxWidget), gToolbarWidget); + gtk_widget_realize(gToolbarWidget); + } + return MOZ_GTK_SUCCESS; +} + +static gint +ensure_toolbar_separator_widget() +{ + if (!gToolbarSeparatorWidget) { + ensure_toolbar_widget(); + gToolbarSeparatorWidget = GTK_WIDGET(gtk_separator_tool_item_new()); + setup_widget_prototype(gToolbarSeparatorWidget); + } + return MOZ_GTK_SUCCESS; +} + +static gint +ensure_tooltip_widget() +{ + if (!gTooltipWidget) { + gTooltipWidget = gtk_window_new(GTK_WINDOW_POPUP); + gtk_widget_realize(gTooltipWidget); + moz_gtk_set_widget_name(gTooltipWidget); + } + return MOZ_GTK_SUCCESS; +} + +static gint +ensure_tab_widget() +{ + if (!gTabWidget) { + gTabWidget = gtk_notebook_new(); + setup_widget_prototype(gTabWidget); + } + return MOZ_GTK_SUCCESS; +} + +static gint +ensure_progress_widget() +{ + if (!gProgressWidget) { + gProgressWidget = gtk_progress_bar_new(); + setup_widget_prototype(gProgressWidget); + } + return MOZ_GTK_SUCCESS; +} + +static gint +ensure_statusbar_widget() +{ + if (!gStatusbarWidget) { + gStatusbarWidget = gtk_statusbar_new(); + setup_widget_prototype(gStatusbarWidget); + } + return MOZ_GTK_SUCCESS; +} + +static gint +ensure_frame_widget() +{ + if (!gFrameWidget) { + ensure_statusbar_widget(); + gFrameWidget = gtk_frame_new(NULL); + gtk_container_add(GTK_CONTAINER(gStatusbarWidget), gFrameWidget); + gtk_widget_realize(gFrameWidget); + } + return MOZ_GTK_SUCCESS; +} + +static gint +ensure_menu_bar_widget() +{ + if (!gMenuBarWidget) { + gMenuBarWidget = gtk_menu_bar_new(); + setup_widget_prototype(gMenuBarWidget); + } + return MOZ_GTK_SUCCESS; +} + +static gint +ensure_menu_bar_item_widget() +{ + if (!gMenuBarItemWidget) { + ensure_menu_bar_widget(); + gMenuBarItemWidget = gtk_menu_item_new(); + gtk_menu_shell_append(GTK_MENU_SHELL(gMenuBarWidget), + gMenuBarItemWidget); + gtk_widget_realize(gMenuBarItemWidget); + } + return MOZ_GTK_SUCCESS; +} + +static gint +ensure_menu_popup_widget() +{ + if (!gMenuPopupWidget) { + ensure_menu_bar_item_widget(); + gMenuPopupWidget = gtk_menu_new(); + gtk_menu_item_set_submenu(GTK_MENU_ITEM(gMenuBarItemWidget), + gMenuPopupWidget); + gtk_widget_realize(gMenuPopupWidget); + } + return MOZ_GTK_SUCCESS; +} + +static gint +ensure_menu_item_widget() +{ + if (!gMenuItemWidget) { + ensure_menu_popup_widget(); + gMenuItemWidget = gtk_menu_item_new_with_label("M"); + gtk_menu_shell_append(GTK_MENU_SHELL(gMenuPopupWidget), + gMenuItemWidget); + gtk_widget_realize(gMenuItemWidget); + } + return MOZ_GTK_SUCCESS; +} + +static gint +ensure_image_menu_item_widget() +{ + if (!gImageMenuItemWidget) { + ensure_menu_popup_widget(); + gImageMenuItemWidget = gtk_image_menu_item_new(); + gtk_menu_shell_append(GTK_MENU_SHELL(gMenuPopupWidget), + gImageMenuItemWidget); + gtk_widget_realize(gImageMenuItemWidget); + } + return MOZ_GTK_SUCCESS; +} + +static gint +ensure_menu_separator_widget() +{ + if (!gMenuSeparatorWidget) { + ensure_menu_popup_widget(); + gMenuSeparatorWidget = gtk_separator_menu_item_new(); + gtk_menu_shell_append(GTK_MENU_SHELL(gMenuPopupWidget), + gMenuSeparatorWidget); + gtk_widget_realize(gMenuSeparatorWidget); + } + return MOZ_GTK_SUCCESS; +} + +static gint +ensure_check_menu_item_widget() +{ + if (!gCheckMenuItemWidget) { + ensure_menu_popup_widget(); + gCheckMenuItemWidget = gtk_check_menu_item_new_with_label("M"); + gtk_menu_shell_append(GTK_MENU_SHELL(gMenuPopupWidget), + gCheckMenuItemWidget); + gtk_widget_realize(gCheckMenuItemWidget); + } + return MOZ_GTK_SUCCESS; +} + +static gint +ensure_tree_view_widget() +{ + if (!gTreeViewWidget) { + gTreeViewWidget = gtk_tree_view_new(); + setup_widget_prototype(gTreeViewWidget); + } + return MOZ_GTK_SUCCESS; +} + +static gint +ensure_tree_header_cell_widget() +{ + if(!gTreeHeaderCellWidget) { + /* + * Some GTK engines paint the first and last cell + * of a TreeView header with a highlight. + * Since we do not know where our widget will be relative + * to the other buttons in the TreeView header, we must + * paint it as a button that is between two others, + * thus ensuring it is neither the first or last button + * in the header. + * GTK doesn't give us a way to do this explicitly, + * so we must paint with a button that is between two + * others. + */ + + GtkTreeViewColumn* firstTreeViewColumn; + GtkTreeViewColumn* lastTreeViewColumn; + + ensure_tree_view_widget(); + + /* Create and append our three columns */ + firstTreeViewColumn = gtk_tree_view_column_new(); + gtk_tree_view_column_set_title(firstTreeViewColumn, "M"); + gtk_tree_view_append_column(GTK_TREE_VIEW(gTreeViewWidget), firstTreeViewColumn); + + gMiddleTreeViewColumn = gtk_tree_view_column_new(); + gtk_tree_view_column_set_title(gMiddleTreeViewColumn, "M"); + gtk_tree_view_append_column(GTK_TREE_VIEW(gTreeViewWidget), + gMiddleTreeViewColumn); + + lastTreeViewColumn = gtk_tree_view_column_new(); + gtk_tree_view_column_set_title(lastTreeViewColumn, "M"); + gtk_tree_view_append_column(GTK_TREE_VIEW(gTreeViewWidget), lastTreeViewColumn); + + /* Use the middle column's header for our button */ + /* TODO */ + gTreeHeaderCellWidget = NULL; + gTreeHeaderSortArrowWidget = NULL; + } + return MOZ_GTK_SUCCESS; +} + +static gint +ensure_expander_widget() +{ + if (!gExpanderWidget) { + gExpanderWidget = gtk_expander_new("M"); + setup_widget_prototype(gExpanderWidget); + } + return MOZ_GTK_SUCCESS; +} + +static gint +ensure_scrolled_window_widget() +{ + if (!gScrolledWindowWidget) { + gScrolledWindowWidget = gtk_scrolled_window_new(NULL, NULL); + setup_widget_prototype(gScrolledWindowWidget); + } + return MOZ_GTK_SUCCESS; +} + +gint +moz_gtk_init() +{ + GtkWidgetClass *entry_class; + + if (is_initialized) + return MOZ_GTK_SUCCESS; + + is_initialized = TRUE; + have_arrow_scaling = (gtk_major_version > 2 || + (gtk_major_version == 2 && gtk_minor_version >= 12)); + + /* Add style property to GtkEntry. + * Adding the style property to the normal GtkEntry class means that it + * will work without issues inside GtkComboBox and for Spinbuttons. */ + entry_class = g_type_class_ref(GTK_TYPE_ENTRY); + + return MOZ_GTK_SUCCESS; +} + +gint +moz_gtk_checkbox_get_metrics(gint* indicator_size, gint* indicator_spacing) +{ + ensure_checkbox_widget(); + + gtk_widget_style_get (gCheckboxWidget, + "indicator_size", indicator_size, + "indicator_spacing", indicator_spacing, + NULL); + + return MOZ_GTK_SUCCESS; +} + +gint +moz_gtk_radio_get_metrics(gint* indicator_size, gint* indicator_spacing) +{ + ensure_radiobutton_widget(); + + gtk_widget_style_get (gRadiobuttonWidget, + "indicator_size", indicator_size, + "indicator_spacing", indicator_spacing, + NULL); + + return MOZ_GTK_SUCCESS; +} + +gint +moz_gtk_widget_get_focus(GtkWidget* widget, gboolean* interior_focus, + gint* focus_width, gint* focus_pad) +{ + gtk_widget_style_get (widget, + "interior-focus", interior_focus, + "focus-line-width", focus_width, + "focus-padding", focus_pad, + NULL); + + return MOZ_GTK_SUCCESS; +} + +gint +moz_gtk_menuitem_get_horizontal_padding(gint* horizontal_padding) +{ + ensure_menu_item_widget(); + + gtk_widget_style_get (gMenuItemWidget, + "horizontal-padding", horizontal_padding, + NULL); + + return MOZ_GTK_SUCCESS; +} + +gint +moz_gtk_checkmenuitem_get_horizontal_padding(gint* horizontal_padding) +{ + ensure_check_menu_item_widget(); + + gtk_widget_style_get (gCheckMenuItemWidget, + "horizontal-padding", horizontal_padding, + NULL); + + return MOZ_GTK_SUCCESS; +} + +gint +moz_gtk_button_get_default_overflow(gint* border_top, gint* border_left, + gint* border_bottom, gint* border_right) +{ + GtkBorder* default_outside_border; + + ensure_button_widget(); + gtk_widget_style_get(gButtonWidget, + "default-outside-border", &default_outside_border, + NULL); + + if (default_outside_border) { + *border_top = default_outside_border->top; + *border_left = default_outside_border->left; + *border_bottom = default_outside_border->bottom; + *border_right = default_outside_border->right; + gtk_border_free(default_outside_border); + } else { + *border_top = *border_left = *border_bottom = *border_right = 0; + } + return MOZ_GTK_SUCCESS; +} + +static gint +moz_gtk_button_get_default_border(gint* border_top, gint* border_left, + gint* border_bottom, gint* border_right) +{ + GtkBorder* default_border; + + ensure_button_widget(); + gtk_widget_style_get(gButtonWidget, + "default-border", &default_border, + NULL); + + if (default_border) { + *border_top = default_border->top; + *border_left = default_border->left; + *border_bottom = default_border->bottom; + *border_right = default_border->right; + gtk_border_free(default_border); + } else { + /* see gtkbutton.c */ + *border_top = *border_left = *border_bottom = *border_right = 1; + } + return MOZ_GTK_SUCCESS; +} + +gint +moz_gtk_splitter_get_metrics(gint orientation, gint* size) +{ + if (orientation == GTK_ORIENTATION_HORIZONTAL) { + ensure_hpaned_widget(); + gtk_widget_style_get(gHPanedWidget, "handle_size", size, NULL); + } else { + ensure_vpaned_widget(); + gtk_widget_style_get(gVPanedWidget, "handle_size", size, NULL); + } + return MOZ_GTK_SUCCESS; +} + +gint +moz_gtk_button_get_inner_border(GtkWidget* widget, GtkBorder* inner_border) +{ + static const GtkBorder default_inner_border = { 1, 1, 1, 1 }; + GtkBorder *tmp_border; + + gtk_widget_style_get (widget, "inner-border", &tmp_border, NULL); + + if (tmp_border) { + *inner_border = *tmp_border; + gtk_border_free(tmp_border); + } + else + *inner_border = default_inner_border; + + return MOZ_GTK_SUCCESS; +} + +static gint +moz_gtk_button_paint(cairo_t *cr, GdkRectangle* rect, + GdkRectangle* cliprect, GtkWidgetState* state, + GtkReliefStyle relief, GtkWidget* widget, + GtkTextDirection direction) +{ + GtkStateFlags state_flags = GetStateFlagsFromGtkWidgetState(state); + GtkStyleContext* style = gtk_widget_get_style_context(widget); + gint x = rect->x, y=rect->y, width=rect->width, height=rect->height; + + gboolean interior_focus; + gint focus_width, focus_pad; + + moz_gtk_widget_get_focus(widget, &interior_focus, &focus_width, &focus_pad); + gtk_widget_set_direction(widget, direction); + + if (!interior_focus && state->focused) { + x += focus_width + focus_pad; + y += focus_width + focus_pad; + width -= 2 * (focus_width + focus_pad); + height -= 2 * (focus_width + focus_pad); + } + + gtk_style_context_save(style); + gtk_style_context_set_state(style, state_flags); + + if (state->isDefault && relief == GTK_RELIEF_NORMAL) { + /* handle default borders both outside and inside the button */ + gint default_top, default_left, default_bottom, default_right; + moz_gtk_button_get_default_overflow(&default_top, &default_left, + &default_bottom, &default_right); + x -= default_left; + y -= default_top; + width += default_left + default_right; + height += default_top + default_bottom; + gtk_render_background(style, cr, x, y, width, height); + gtk_render_frame(style, cr, x, y, width, height); + moz_gtk_button_get_default_border(&default_top, &default_left, + &default_bottom, &default_right); + x += default_left; + y += default_top; + width -= (default_left + default_right); + height -= (default_top + default_bottom); + } + + if (relief != GTK_RELIEF_NONE || state->depressed || + (state_flags & GTK_STATE_FLAG_PRELIGHT)) { + /* the following line can trigger an assertion (Crux theme) + file ../../gdk/gdkwindow.c: line 1846 (gdk_window_clear_area): + assertion `GDK_IS_WINDOW (window)' failed */ + gtk_render_background(style, cr, x, y, width, height); + gtk_render_frame(style, cr, x, y, width, height); + } + + if (state->focused) { + if (interior_focus) { + GtkBorder border; + gtk_style_context_get_border(style, state_flags, &border); + x += border.left + focus_pad; + y += border.top + focus_pad; + width -= 2 * (border.left + focus_pad); + height -= 2 * (border.top + focus_pad); + } else { + x -= focus_width + focus_pad; + y -= focus_width + focus_pad; + width += 2 * (focus_width + focus_pad); + height += 2 * (focus_width + focus_pad); + } + + gtk_render_focus(style, cr, x, y, width, height); + } + gtk_style_context_restore(style); + return MOZ_GTK_SUCCESS; +} + +static gint +moz_gtk_toggle_paint(cairo_t *cr, GdkRectangle* rect, + GdkRectangle* cliprect, GtkWidgetState* state, + gboolean selected, gboolean inconsistent, + gboolean isradio, GtkTextDirection direction) +{ + gint indicator_size, indicator_spacing; + gint x, y, width, height; + gint focus_x, focus_y, focus_width, focus_height; + GtkWidget *w; + GtkStyleContext *style; + + if (isradio) { + moz_gtk_radio_get_metrics(&indicator_size, &indicator_spacing); + w = gRadiobuttonWidget; + } else { + moz_gtk_checkbox_get_metrics(&indicator_size, &indicator_spacing); + w = gCheckboxWidget; + } + + NS_ASSERTION(rect->width == indicator_size, + "GetMinimumWidgetSize was ignored"); + /* + * vertically center in the box, since XUL sometimes ignores our + * GetMinimumWidgetSize in the vertical dimension + */ + x = rect->x; + y = rect->y + (rect->height - indicator_size) / 2; + width = indicator_size; + height = indicator_size; + + focus_x = x - indicator_spacing; + focus_y = y - indicator_spacing; + focus_width = width + 2 * indicator_spacing; + focus_height = height + 2 * indicator_spacing; + + style = gtk_widget_get_style_context(w); + + gtk_widget_set_sensitive(w, !state->disabled); + gtk_widget_set_direction(w, direction); + gtk_style_context_save(style); + + if (isradio) { + gtk_style_context_add_class(style, GTK_STYLE_CLASS_RADIO); + if (selected) { + gtk_style_context_set_state(style, GTK_STATE_FLAG_ACTIVE); + } + gtk_render_option(style, cr, x, y, width, height); + if (state->focused) { + gtk_render_focus(style, cr, focus_x, focus_y, + focus_width, focus_height); + } + } + else { + /* + * 'indeterminate' type on checkboxes. In GTK, the shadow type + * must also be changed for the state to be drawn. + */ + gtk_style_context_add_class(style, GTK_STYLE_CLASS_CHECK); + if (inconsistent) { + gtk_style_context_set_state(style, GTK_STATE_FLAG_INCONSISTENT); + gtk_toggle_button_set_inconsistent(GTK_TOGGLE_BUTTON(gCheckboxWidget), TRUE); + } else if (selected) { + gtk_style_context_set_state(style, GTK_STATE_FLAG_ACTIVE); + } else { + gtk_toggle_button_set_inconsistent(GTK_TOGGLE_BUTTON(gCheckboxWidget), FALSE); + } + gtk_render_check(style, cr, x, y, width, height); + if (state->focused) { + gtk_render_focus(style, cr, + focus_x, focus_y, focus_width, focus_height); + } + } + gtk_style_context_restore(style); + + return MOZ_GTK_SUCCESS; +} + +static gint +calculate_button_inner_rect(GtkWidget* button, GdkRectangle* rect, + GdkRectangle* inner_rect, + GtkTextDirection direction, + gboolean ignore_focus) +{ + GtkBorder inner_border; + gboolean interior_focus; + gint focus_width, focus_pad; + GtkStyleContext* style; + GtkBorder border; + + style = gtk_widget_get_style_context(button); + + /* This mirrors gtkbutton's child positioning */ + moz_gtk_button_get_inner_border(button, &inner_border); + moz_gtk_widget_get_focus(button, &interior_focus, + &focus_width, &focus_pad); + + if (ignore_focus) + focus_width = focus_pad = 0; + + gtk_style_context_get_border(style, 0, &border); + + inner_rect->x = rect->x + border.left + focus_width + focus_pad; + inner_rect->x += direction == GTK_TEXT_DIR_LTR ? + inner_border.left : inner_border.right; + inner_rect->y = rect->y + inner_border.top + border.top + + focus_width + focus_pad; + inner_rect->width = MAX(1, rect->width - inner_border.left - + inner_border.right - (border.left + focus_pad + focus_width) * 2); + inner_rect->height = MAX(1, rect->height - inner_border.top - + inner_border.bottom - (border.top + focus_pad + focus_width) * 2); + + return MOZ_GTK_SUCCESS; +} + + +static gint +calculate_arrow_rect(GtkWidget* arrow, GdkRectangle* rect, + GdkRectangle* arrow_rect, GtkTextDirection direction) +{ + /* defined in gtkarrow.c */ + gfloat arrow_scaling = 0.7; + gfloat xalign, xpad; + gint extent; + gint mxpad, mypad; + gfloat mxalign, myalign; + GtkMisc* misc = GTK_MISC(arrow); + + if (have_arrow_scaling) + gtk_widget_style_get(arrow, "arrow_scaling", &arrow_scaling, NULL); + + gtk_misc_get_padding(misc, &mxpad, &mypad); + extent = MIN((rect->width - mxpad * 2), + (rect->height - mypad * 2)) * arrow_scaling; + + gtk_misc_get_alignment(misc, &mxalign, &myalign); + + xalign = direction == GTK_TEXT_DIR_LTR ? mxalign : 1.0 - mxalign; + xpad = mxpad + (rect->width - extent) * xalign; + + arrow_rect->x = direction == GTK_TEXT_DIR_LTR ? + floor(rect->x + xpad) : ceil(rect->x + xpad); + arrow_rect->y = floor(rect->y + mypad + + ((rect->height - extent) * myalign)); + + arrow_rect->width = arrow_rect->height = extent; + + return MOZ_GTK_SUCCESS; +} + +static gint +moz_gtk_scrollbar_button_paint(cairo_t *cr, GdkRectangle* rect, + GdkRectangle* cliprect, GtkWidgetState* state, + GtkScrollbarButtonFlags flags, + GtkTextDirection direction) +{ + GtkStateFlags state_flags = GetStateFlagsFromGtkWidgetState(state); + GtkStateType saved_state; + GdkRectangle arrow_rect; + gdouble arrow_angle; + GtkStyleContext* style; + GtkWidget *scrollbar; + gint arrow_displacement_x, arrow_displacement_y; + const char* detail = (flags & MOZ_GTK_STEPPER_VERTICAL) ? + "vscrollbar" : "hscrollbar"; + + ensure_scrollbar_widget(); + + if (flags & MOZ_GTK_STEPPER_VERTICAL) + scrollbar = gVertScrollbarWidget; + else + scrollbar = gHorizScrollbarWidget; + + gtk_widget_set_direction(scrollbar, direction); + + if (flags & MOZ_GTK_STEPPER_VERTICAL) { + arrow_angle = (flags & MOZ_GTK_STEPPER_DOWN) ? ARROW_DOWN : ARROW_UP; + } else { + arrow_angle = (flags & MOZ_GTK_STEPPER_DOWN) ? ARROW_RIGHT : ARROW_LEFT; + } + + style = gtk_widget_get_style_context(scrollbar); + + gtk_style_context_save(style); + gtk_style_context_add_class(style, GTK_STYLE_CLASS_SCROLLBAR); + gtk_style_context_set_state(style, state_flags); + + gtk_render_background(style, cr, rect->x, rect->y, rect->width, rect->height); + gtk_render_frame(style, cr, rect->x, rect->y, rect->width, rect->height); + + arrow_rect.width = rect->width / 2; + arrow_rect.height = rect->height / 2; + arrow_rect.x = rect->x + (rect->width - arrow_rect.width) / 2; + arrow_rect.y = rect->y + (rect->height - arrow_rect.height) / 2; + + if (state_flags & GTK_STATE_FLAG_ACTIVE) { + gtk_widget_style_get(scrollbar, + "arrow-displacement-x", &arrow_displacement_x, + "arrow-displacement-y", &arrow_displacement_y, + NULL); + + arrow_rect.x += arrow_displacement_x; + arrow_rect.y += arrow_displacement_y; + } + + gtk_render_arrow(style, cr, arrow_angle, + arrow_rect.x, + arrow_rect.y, + arrow_rect.width); + + gtk_style_context_restore(style); + + return MOZ_GTK_SUCCESS; +} + +static gint +moz_gtk_scrollbar_trough_paint(GtkThemeWidgetType widget, + cairo_t *cr, GdkRectangle* rect, + GdkRectangle* cliprect, GtkWidgetState* state, + GtkTextDirection direction) +{ + GtkStyleContext* style; + GtkScrollbar *scrollbar; + + ensure_scrollbar_widget(); + + if (widget == MOZ_GTK_SCROLLBAR_TRACK_HORIZONTAL) + scrollbar = GTK_SCROLLBAR(gHorizScrollbarWidget); + else + scrollbar = GTK_SCROLLBAR(gVertScrollbarWidget); + + gtk_widget_set_direction(GTK_WIDGET(scrollbar), direction); + + style = gtk_widget_get_style_context(GTK_WIDGET(scrollbar)); + gtk_style_context_save(style); + gtk_style_context_add_class(style, GTK_STYLE_CLASS_TROUGH); + + gtk_render_background(style, cr, rect->x, rect->y, rect->width, rect->height); + gtk_render_frame(style, cr, rect->x, rect->y, rect->width, rect->height); + + if (state->focused) { + gtk_render_focus(style, cr, + rect->x, rect->y, rect->width, rect->height); + } + gtk_style_context_restore(style); + return MOZ_GTK_SUCCESS; +} + +static gint +moz_gtk_scrollbar_thumb_paint(GtkThemeWidgetType widget, + cairo_t *cr, GdkRectangle* rect, + GdkRectangle* cliprect, GtkWidgetState* state, + GtkTextDirection direction) +{ + GtkStateFlags state_flags = GetStateFlagsFromGtkWidgetState(state); + GtkStyleContext* style; + GtkScrollbar *scrollbar; + GtkAdjustment *adj; + + ensure_scrollbar_widget(); + + if (widget == MOZ_GTK_SCROLLBAR_THUMB_HORIZONTAL) + scrollbar = GTK_SCROLLBAR(gHorizScrollbarWidget); + else + scrollbar = GTK_SCROLLBAR(gVertScrollbarWidget); + + gtk_widget_set_direction(GTK_WIDGET(scrollbar), direction); + + style = gtk_widget_get_style_context(GTK_WIDGET(scrollbar)); + gtk_style_context_save(style); + + gtk_style_context_add_class(style, GTK_STYLE_CLASS_SLIDER); + gtk_style_context_set_state(style, state_flags); + + gtk_render_slider(style, cr, rect->x, rect->y, + rect->width, rect->height, + (widget == MOZ_GTK_SCROLLBAR_THUMB_HORIZONTAL) ? + GTK_ORIENTATION_HORIZONTAL : GTK_ORIENTATION_VERTICAL); + + gtk_style_context_restore(style); + + return MOZ_GTK_SUCCESS; +} + +static gint +moz_gtk_spin_paint(cairo_t *cr, GdkRectangle* rect, + GtkTextDirection direction) +{ + GtkStyleContext* style; + + ensure_spin_widget(); + gtk_widget_set_direction(gSpinWidget, direction); + style = gtk_widget_get_style_context(gSpinWidget); + gtk_style_context_save(style); + gtk_style_context_add_class(style, GTK_STYLE_CLASS_SPINBUTTON); + gtk_render_background(style, cr, rect->x, rect->y, rect->width, rect->height); + gtk_render_frame(style, cr, rect->x, rect->y, rect->width, rect->height); + gtk_style_context_restore(style); + + return MOZ_GTK_SUCCESS; +} + +static gint +moz_gtk_spin_updown_paint(cairo_t *cr, GdkRectangle* rect, + gboolean isDown, GtkWidgetState* state, + GtkTextDirection direction) +{ + GdkRectangle arrow_rect; + GtkStyleContext* style; + + ensure_spin_widget(); + style = gtk_widget_get_style_context(gSpinWidget); + gtk_style_context_save(style); + gtk_style_context_add_class(style, GTK_STYLE_CLASS_SPINBUTTON); + gtk_style_context_set_state(style, GetStateFlagsFromGtkWidgetState(state)); + gtk_widget_set_direction(gSpinWidget, direction); + + gtk_render_background(style, cr, rect->x, rect->y, rect->width, rect->height); + gtk_render_frame(style, cr, rect->x, rect->y, rect->width, rect->height); + + + /* hard code these values */ + arrow_rect.width = 6; + arrow_rect.height = 6; + arrow_rect.x = rect->x + (rect->width - arrow_rect.width) / 2; + arrow_rect.y = rect->y + (rect->height - arrow_rect.height) / 2; + arrow_rect.y += isDown ? -1 : 1; + + gtk_render_arrow(style, cr, + isDown ? ARROW_DOWN : ARROW_UP, + arrow_rect.x, arrow_rect.y, + arrow_rect.width); + gtk_style_context_restore(style); + return MOZ_GTK_SUCCESS; +} + +static gint +moz_gtk_scale_paint(cairo_t *cr, GdkRectangle* rect, + GdkRectangle* cliprect, GtkWidgetState* state, + GtkOrientation flags, GtkTextDirection direction) +{ + GtkStateFlags state_flags = GetStateFlagsFromGtkWidgetState(state); + gint x = 0, y = 0; + GtkStyleContext* style; + GtkWidget* widget; + GtkBorder border; + + ensure_scale_widget(); + widget = ((flags == GTK_ORIENTATION_HORIZONTAL) ? gHScaleWidget : gVScaleWidget); + gtk_widget_set_direction(widget, direction); + + style = gtk_widget_get_style_context(widget); + gtk_style_context_save(style); + gtk_style_context_add_class(style, GTK_STYLE_CLASS_SCALE); + gtk_style_context_get_border(style, state_flags, &border); + + if (flags == GTK_ORIENTATION_HORIZONTAL) { + x = border.left; + y++; + } + else { + x++; + y = border.top; + } + + gtk_render_background(style, cr, rect->x + x, rect->y + y, + rect->width - 2*x, rect->height - 2*y); + gtk_render_frame(style, cr, rect->x + x, rect->y + y, + rect->width - 2*x, rect->height - 2*y); + + if (state->focused) + gtk_render_focus(style, cr, + rect->x, rect->y, rect->width, rect->height); + gtk_style_context_restore(style); + return MOZ_GTK_SUCCESS; +} + +static gint +moz_gtk_scale_thumb_paint(cairo_t *cr, GdkRectangle* rect, + GdkRectangle* cliprect, GtkWidgetState* state, + GtkOrientation flags, GtkTextDirection direction) +{ + GtkStateFlags state_flags = GetStateFlagsFromGtkWidgetState(state); + GtkStyleContext* style; + GtkWidget* widget; + gint thumb_width, thumb_height, x, y; + + ensure_scale_widget(); + widget = ((flags == GTK_ORIENTATION_HORIZONTAL) ? gHScaleWidget : gVScaleWidget); + gtk_widget_set_direction(widget, direction); + + style = gtk_widget_get_style_context(widget); + gtk_style_context_add_class(style, GTK_STYLE_CLASS_SLIDER); + gtk_style_context_save(style); + gtk_style_context_set_state(style, state_flags); + /* determine the thumb size, and position the thumb in the center in the opposite axis + */ + if (flags == GTK_ORIENTATION_HORIZONTAL) { + moz_gtk_get_scalethumb_metrics(GTK_ORIENTATION_HORIZONTAL, &thumb_width, &thumb_height); + x = rect->x; + y = rect->y + (rect->height - thumb_height) / 2; + } + else { + moz_gtk_get_scalethumb_metrics(GTK_ORIENTATION_VERTICAL, &thumb_height, &thumb_width); + x = rect->x + (rect->width - thumb_width) / 2; + y = rect->y; + } + + gtk_render_slider(style, cr, x, y, thumb_width, thumb_height, flags); + gtk_style_context_restore(style); + return MOZ_GTK_SUCCESS; +} + +static gint +moz_gtk_gripper_paint(cairo_t *cr, GdkRectangle* rect, + GdkRectangle* cliprect, GtkWidgetState* state, + GtkTextDirection direction) +{ + GtkStyleContext* style; + + ensure_handlebox_widget(); + gtk_widget_set_direction(gHandleBoxWidget, direction); + + style = gtk_widget_get_style_context(gHandleBoxWidget); + gtk_style_context_save(style); + gtk_style_context_add_class(style, GTK_STYLE_CLASS_GRIP); + gtk_style_context_set_state(style, GetStateFlagsFromGtkWidgetState(state)); + + gtk_render_background(style, cr, rect->x, rect->y, rect->width, rect->height); + gtk_render_frame(style, cr, rect->x, rect->y, rect->width, rect->height); + gtk_style_context_restore(style); + + return MOZ_GTK_SUCCESS; +} + +static gint +moz_gtk_hpaned_paint(cairo_t *cr, GdkRectangle* rect, + GdkRectangle* cliprect, GtkWidgetState* state) +{ + GtkStyleContext* style; + + ensure_hpaned_widget(); + style = gtk_widget_get_style_context(gHPanedWidget); + gtk_style_context_save(style); + gtk_style_context_add_class(style, GTK_STYLE_CLASS_PANE_SEPARATOR); + gtk_style_context_set_state(style, GetStateFlagsFromGtkWidgetState(state)); + gtk_render_handle(style, cr, + rect->x, rect->y, rect->width, rect->height); + gtk_style_context_restore(style); + + return MOZ_GTK_SUCCESS; +} + +static gint +moz_gtk_vpaned_paint(cairo_t *cr, GdkRectangle* rect, + GdkRectangle* cliprect, GtkWidgetState* state) +{ + GtkStyleContext* style; + + ensure_vpaned_widget(); + style = gtk_widget_get_style_context(gVPanedWidget); + gtk_style_context_save(style); + gtk_style_context_add_class(style, GTK_STYLE_CLASS_PANE_SEPARATOR); + gtk_style_context_set_state(style, GetStateFlagsFromGtkWidgetState(state)); + gtk_render_handle(style, cr, + rect->x, rect->y, rect->width, rect->height); + gtk_style_context_restore(style); + + return MOZ_GTK_SUCCESS; +} + +static gint +moz_gtk_caret_paint(cairo_t *cr, GdkRectangle* rect, + GdkRectangle* cliprect, GtkTextDirection direction) +{ + GdkRectangle location = *rect; + + if (direction == GTK_TEXT_DIR_RTL) { + /* gtk_draw_insertion_cursor ignores location.width */ + location.x = rect->x + rect->width; + } + + ensure_entry_widget(); + gtk_draw_insertion_cursor(gEntryWidget, cr, + &location, TRUE, direction, FALSE); + return MOZ_GTK_SUCCESS; +} + +static gint +moz_gtk_entry_paint(cairo_t *cr, GdkRectangle* rect, + GdkRectangle* cliprect, GtkWidgetState* state, + GtkWidget* widget, GtkTextDirection direction) +{ + gint x = rect->x, y = rect->y, width = rect->width, height = rect->height; + GtkStyleContext* style; + gboolean interior_focus; + gint focus_width; + + gtk_widget_set_direction(widget, direction); + + style = gtk_widget_get_style_context(widget); + + gtk_widget_style_get(widget, + "interior-focus", &interior_focus, + "focus-line-width", &focus_width, + NULL); + + /* gtkentry.c uses two windows, one for the entire widget and one for the + * text area inside it. The background of both windows is set to the "base" + * color of the new state in gtk_entry_state_changed, but only the inner + * textarea window uses gtk_paint_flat_box when exposed */ + + /* This gets us a lovely greyish disabledish look */ + gtk_widget_set_sensitive(widget, !state->disabled); + + gtk_style_context_save(style); + gtk_style_context_add_class(style, GTK_STYLE_CLASS_ENTRY); + + /* Now paint the shadow and focus border. + * We do like in gtk_entry_draw_frame, we first draw the shadow, a tad + * smaller when focused if the focus is not interior, then the focus. */ + + if (state->focused && !state->disabled) { + /* This will get us the lit borders that focused textboxes enjoy on + * some themes. */ + gtk_style_context_set_state(style, GTK_STATE_FLAG_FOCUSED); + if (!interior_focus) { + /* Indent the border a little bit if we have exterior focus + (this is what GTK does to draw native entries) */ + x += focus_width; + y += focus_width; + width -= 2 * focus_width; + height -= 2 * focus_width; + } + } + + if (state->disabled) { + gtk_style_context_set_state(style, GTK_STATE_FLAG_INSENSITIVE); + } + + gtk_render_background(style, cr, x, y, width, height); + gtk_render_frame(style, cr, x, y, width, height); + + if (state->focused && !state->disabled) { + if (!interior_focus) { + gtk_render_focus(style, cr, rect->x, rect->y, rect->width, rect->height); + } + } + gtk_style_context_restore(style); + + return MOZ_GTK_SUCCESS; +} + +static gint +moz_gtk_treeview_paint(cairo_t *cr, GdkRectangle* rect, + GdkRectangle* cliprect, GtkWidgetState* state, + GtkTextDirection direction) +{ + gint xthickness, ythickness; + GtkStyleContext *style; + GtkStyleContext *style_tree; + GtkStateFlags state_flags; + GtkBorder border; + + ensure_tree_view_widget(); + ensure_scrolled_window_widget(); + + gtk_widget_set_direction(gTreeViewWidget, direction); + gtk_widget_set_direction(gScrolledWindowWidget, direction); + + /* only handle disabled and normal states, otherwise the whole background + * area will be painted differently with other states */ + state_flags = state->disabled ? GTK_STATE_FLAG_INSENSITIVE : GTK_STATE_FLAG_NORMAL; + + style = gtk_widget_get_style_context(gScrolledWindowWidget); + gtk_style_context_save(style); + gtk_style_context_add_class(style, GTK_STYLE_CLASS_FRAME); + gtk_style_context_get_border(style, state_flags, &border); + xthickness = border.left; + ythickness = border.top; + + style_tree = gtk_widget_get_style_context(gTreeViewWidget); + gtk_style_context_save(style_tree); + gtk_style_context_add_class(style_tree, GTK_STYLE_CLASS_VIEW); + + gtk_render_background(style_tree, cr, + rect->x + xthickness, rect->y + ythickness, + rect->width - 2 * xthickness, + rect->height - 2 * ythickness); + gtk_render_frame(style, cr, + rect->x, rect->y, rect->width, rect->height); + gtk_style_context_restore(style); + gtk_style_context_restore(style_tree); + return MOZ_GTK_SUCCESS; +} + +static gint +moz_gtk_tree_header_cell_paint(cairo_t *cr, GdkRectangle* rect, + GdkRectangle* cliprect, GtkWidgetState* state, + gboolean isSorted, GtkTextDirection direction) +{ + moz_gtk_button_paint(cr, rect, cliprect, state, GTK_RELIEF_NORMAL, + gTreeHeaderCellWidget, direction); + return MOZ_GTK_SUCCESS; +} + +static gint +moz_gtk_tree_header_sort_arrow_paint(cairo_t *cr, GdkRectangle* rect, + GdkRectangle* cliprect, + GtkWidgetState* state, GtkArrowType arrow_type, + GtkTextDirection direction) +{ + GdkRectangle arrow_rect; + gdouble arrow_angle; + GtkStyleContext* style; + + ensure_tree_header_cell_widget(); + gtk_widget_set_direction(gTreeHeaderSortArrowWidget, direction); + + /* hard code these values */ + arrow_rect.width = 11; + arrow_rect.height = 11; + arrow_rect.x = rect->x + (rect->width - arrow_rect.width) / 2; + arrow_rect.y = rect->y + (rect->height - arrow_rect.height) / 2; + style = gtk_widget_get_style_context(gTreeHeaderSortArrowWidget); + gtk_style_context_save(style); + gtk_style_context_set_state(style, GetStateFlagsFromGtkWidgetState(state)); + + switch (arrow_type) { + case GTK_ARROW_LEFT: + arrow_angle = ARROW_LEFT; + break; + case GTK_ARROW_RIGHT: + arrow_angle = ARROW_RIGHT; + break; + case GTK_ARROW_DOWN: + arrow_angle = ARROW_DOWN; + break; + default: + arrow_angle = ARROW_UP; + break; + } + if (arrow_type != GTK_ARROW_NONE) + gtk_render_arrow(style, cr, arrow_angle, + arrow_rect.x, arrow_rect.y, + arrow_rect.width); + gtk_style_context_restore(style); + return MOZ_GTK_SUCCESS; +} + +static gint +moz_gtk_treeview_expander_paint(cairo_t *cr, GdkRectangle* rect, + GdkRectangle* cliprect, GtkWidgetState* state, + GtkExpanderStyle expander_state, + GtkTextDirection direction) +{ + GtkStyleContext *style; + + ensure_tree_view_widget(); + gtk_widget_set_direction(gTreeViewWidget, direction); + + style = gtk_widget_get_style_context(gTreeViewWidget); + gtk_style_context_save(style); + gtk_style_context_add_class(style, GTK_STYLE_CLASS_EXPANDER); + /* Because the frame we get is of the entire treeview, we can't get the precise + * event state of one expander, thus rendering hover and active feedback useless. */ + gtk_style_context_set_state(style, GetStateFlagsFromGtkWidgetState(state)); + gtk_render_expander(style, cr, + rect->x + rect->width / 2, rect->y + rect->height / 2, + rect->width, rect->height); + gtk_style_context_restore(style); + return MOZ_GTK_SUCCESS; +} + +static gint +moz_gtk_expander_paint(cairo_t *cr, GdkRectangle* rect, + GdkRectangle* cliprect, GtkWidgetState* state, + GtkExpanderStyle expander_state, + GtkTextDirection direction) +{ + GtkStyleContext *style; + + ensure_expander_widget(); + gtk_widget_set_direction(gExpanderWidget, direction); + + style = gtk_widget_get_style_context(gExpanderWidget); + gtk_style_context_save(style); + gtk_style_context_add_class(style, GTK_STYLE_CLASS_EXPANDER); + gtk_style_context_set_state(style, GetStateFlagsFromGtkWidgetState(state)); + gtk_render_expander(style, cr, + rect->x + rect->width / 2, rect->y + rect->height / 2, + rect->width, rect->height); + gtk_style_context_restore(style); + return MOZ_GTK_SUCCESS; +} + +static gint +moz_gtk_combo_box_paint(cairo_t *cr, GdkRectangle* rect, + GdkRectangle* cliprect, GtkWidgetState* state, + gboolean ishtml, GtkTextDirection direction) +{ + GdkRectangle arrow_rect, real_arrow_rect; + gint arrow_size, separator_width; + gboolean wide_separators; + GtkStyleContext* style; + GtkRequisition arrow_req; + + ensure_combo_box_widgets(); + + /* Also sets the direction on gComboBoxButtonWidget, which is then + * inherited by the separator and arrow */ + moz_gtk_button_paint(cr, rect, cliprect, state, GTK_RELIEF_NORMAL, + gComboBoxButtonWidget, direction); + + calculate_button_inner_rect(gComboBoxButtonWidget, + rect, &arrow_rect, direction, ishtml); + /* Now arrow_rect contains the inner rect ; we want to correct the width + * to what the arrow needs (see gtk_combo_box_size_allocate) */ + gtk_widget_size_request(gComboBoxArrowWidget, &arrow_req); + if (direction == GTK_TEXT_DIR_LTR) + arrow_rect.x += arrow_rect.width - arrow_req.width; + arrow_rect.width = arrow_req.width; + + calculate_arrow_rect(gComboBoxArrowWidget, + &arrow_rect, &real_arrow_rect, direction); + + style = gtk_widget_get_style_context(gComboBoxArrowWidget); + gtk_render_arrow(style, cr, ARROW_DOWN, + real_arrow_rect.x, real_arrow_rect.y, + real_arrow_rect.width); + + /* If there is no separator in the theme, there's nothing left to do. */ + if (!gComboBoxSeparatorWidget) + return MOZ_GTK_SUCCESS; + style = gtk_widget_get_style_context(gComboBoxSeparatorWidget); + gtk_widget_style_get(gComboBoxSeparatorWidget, + "wide-separators", &wide_separators, + "separator-width", &separator_width, + NULL); + + if (wide_separators) { + if (direction == GTK_TEXT_DIR_LTR) + arrow_rect.x -= separator_width; + else + arrow_rect.x += arrow_rect.width; + + gtk_render_frame(style, cr, arrow_rect.x, arrow_rect.y, separator_width, arrow_rect.height); + } else { + if (direction == GTK_TEXT_DIR_LTR) { + GtkBorder border; + gtk_style_context_get_border(style, GetStateFlagsFromGtkWidgetState(state), &border); + arrow_rect.x -= border.left; + } + else + arrow_rect.x += arrow_rect.width; + + gtk_render_line(style, cr, + arrow_rect.x, arrow_rect.y, + arrow_rect.x, arrow_rect.y + arrow_rect.height); + } + return MOZ_GTK_SUCCESS; +} + +static gint +moz_gtk_arrow_paint(cairo_t *cr, GdkRectangle* rect, + GdkRectangle* cliprect, GtkWidgetState* state, + GtkArrowType arrow_type, GtkTextDirection direction) +{ + GtkStyleContext* style; + GtkStateFlags state_flags = GetStateFlagsFromGtkWidgetState(state); + GdkRectangle arrow_rect; + gdouble arrow_angle = ARROW_UP; + + ensure_button_arrow_widget(); + style = gtk_widget_get_style_context(gButtonArrowWidget); + gtk_style_context_save(style); + gtk_style_context_set_state(style, state_flags); + gtk_widget_set_direction(gButtonArrowWidget, direction); + + calculate_arrow_rect(gButtonArrowWidget, rect, &arrow_rect, + direction); + + if (direction == GTK_TEXT_DIR_RTL) { + if (arrow_type == GTK_ARROW_LEFT) + arrow_angle = ARROW_RIGHT; + else if (arrow_type == GTK_ARROW_RIGHT) + arrow_angle = ARROW_LEFT; + } else if (arrow_type == GTK_ARROW_DOWN) { + arrow_angle = ARROW_DOWN; + } + if (arrow_type != GTK_ARROW_NONE) + gtk_render_arrow(style, cr, arrow_angle, + arrow_rect.x, arrow_rect.y, arrow_rect.width); + gtk_style_context_restore(style); + return MOZ_GTK_SUCCESS; +} + +static gint +moz_gtk_combo_box_entry_button_paint(cairo_t *cr, GdkRectangle* rect, + GdkRectangle* cliprect, + GtkWidgetState* state, + gboolean input_focus, + GtkTextDirection direction) +{ + gint x_displacement, y_displacement; + GdkRectangle arrow_rect, real_arrow_rect; + GtkStateFlags state_flags = GetStateFlagsFromGtkWidgetState(state); + GtkStyleContext* style; + + ensure_combo_box_entry_widgets(); + + moz_gtk_button_paint(cr, rect, cliprect, state, GTK_RELIEF_NORMAL, + gComboBoxEntryButtonWidget, direction); + + calculate_button_inner_rect(gComboBoxEntryButtonWidget, + rect, &arrow_rect, direction, FALSE); + if (state_flags & GTK_STATE_FLAG_ACTIVE) { + gtk_widget_style_get(gComboBoxEntryButtonWidget, + "child-displacement-x", &x_displacement, + "child-displacement-y", &y_displacement, + NULL); + arrow_rect.x += x_displacement; + arrow_rect.y += y_displacement; + } + + calculate_arrow_rect(gComboBoxEntryArrowWidget, + &arrow_rect, &real_arrow_rect, direction); + + style = gtk_widget_get_style_context(gComboBoxEntryArrowWidget); + + gtk_render_arrow(style, cr, ARROW_DOWN, + real_arrow_rect.x, real_arrow_rect.y, + real_arrow_rect.width); + + return MOZ_GTK_SUCCESS; +} + +static gint +moz_gtk_container_paint(cairo_t *cr, GdkRectangle* rect, + GdkRectangle* cliprect, GtkWidgetState* state, + gboolean isradio, GtkTextDirection direction) +{ + GtkStateFlags state_flags = GetStateFlagsFromGtkWidgetState(state); + GtkStyleContext* style; + GtkWidget *widget; + gboolean interior_focus; + gint focus_width, focus_pad; + + if (isradio) { + ensure_radiobutton_widget(); + widget = gRadiobuttonWidget; + } else { + ensure_checkbox_widget(); + widget = gCheckboxWidget; + } + gtk_widget_set_direction(widget, direction); + + style = gtk_widget_get_style_context(widget); + gtk_style_context_save(style); + moz_gtk_widget_get_focus(widget, &interior_focus, &focus_width, &focus_pad); + gtk_style_context_set_state(style, state_flags); + + /* this is for drawing a prelight box */ + if (state_flags & GTK_STATE_FLAG_PRELIGHT) { + gtk_render_background(style, cr, + rect->x, rect->y, rect->width, rect->height); + } + + if (state->focused && !interior_focus) { + gtk_render_focus(style, cr, + rect->x, rect->y, rect->width, rect->height); + } + gtk_style_context_restore(style); + + return MOZ_GTK_SUCCESS; +} + +static gint +moz_gtk_toggle_label_paint(cairo_t *cr, GdkRectangle* rect, + GdkRectangle* cliprect, GtkWidgetState* state, + gboolean isradio, GtkTextDirection direction) +{ + GtkStyleContext *style; + GtkWidget *widget; + gboolean interior_focus; + + if (!state->focused) + return MOZ_GTK_SUCCESS; + + if (isradio) { + ensure_radiobutton_widget(); + widget = gRadiobuttonWidget; + } else { + ensure_checkbox_widget(); + widget = gCheckboxWidget; + } + style = gtk_widget_get_style_context(widget); + gtk_style_context_save(style); + if (isradio) { + gtk_style_context_add_class(style, GTK_STYLE_CLASS_RADIO); + } else { + gtk_style_context_add_class(style, GTK_STYLE_CLASS_CHECK); + } + gtk_widget_set_direction(widget, direction); + + gtk_widget_style_get(widget, "interior-focus", &interior_focus, NULL); + if (!interior_focus) + return MOZ_GTK_SUCCESS; + + gtk_style_context_set_state(style, GetStateFlagsFromGtkWidgetState(state)); + gtk_render_focus(style, cr, + rect->x, rect->y, rect->width, rect->height); + gtk_style_context_restore(style); + + return MOZ_GTK_SUCCESS; +} + +static gint +moz_gtk_toolbar_paint(cairo_t *cr, GdkRectangle* rect, + GdkRectangle* cliprect, GtkTextDirection direction) +{ + GtkStyleContext* style; + + ensure_toolbar_widget(); + gtk_widget_set_direction(gToolbarWidget, direction); + + style = gtk_widget_get_style_context(gToolbarWidget); + gtk_style_context_save(style); + gtk_style_context_add_class(style, GTK_STYLE_CLASS_TOOLBAR); + + gtk_render_background(style, cr, rect->x, rect->y, rect->width, rect->height); + gtk_render_frame(style, cr, rect->x, rect->y, rect->width, rect->height); + gtk_style_context_restore(style); + + return MOZ_GTK_SUCCESS; +} + +static gint +moz_gtk_toolbar_separator_paint(cairo_t *cr, GdkRectangle* rect, + GdkRectangle* cliprect, + GtkTextDirection direction) +{ + GtkStyleContext* style; + gint separator_width; + gint paint_width; + gboolean wide_separators; + + /* Defined as constants in GTK+ 2.10.14 */ + const double start_fraction = 0.2; + const double end_fraction = 0.8; + + ensure_toolbar_separator_widget(); + gtk_widget_set_direction(gToolbarSeparatorWidget, direction); + + style = gtk_widget_get_style_context(gToolbarSeparatorWidget); + + gtk_widget_style_get(gToolbarWidget, + "wide-separators", &wide_separators, + "separator-width", &separator_width, + NULL); + + if (wide_separators) { + if (separator_width > rect->width) + separator_width = rect->width; + + gtk_render_frame(style, cr, + rect->x + (rect->width - separator_width) / 2, + rect->y + rect->height * start_fraction, + separator_width, + rect->height * (end_fraction - start_fraction)); + } else { + GtkBorder border; + gtk_style_context_get_border(style, 0, &border); + + paint_width = border.left; + + if (paint_width > rect->width) + paint_width = rect->width; + + gtk_render_line(style, cr, + rect->x + (rect->width - paint_width) / 2, + rect->y + rect->height * start_fraction, + rect->x + (rect->width - paint_width) / 2, + rect->y + rect->height * end_fraction); + } + + return MOZ_GTK_SUCCESS; +} + +static gint +moz_gtk_tooltip_paint(cairo_t *cr, GdkRectangle* rect, + GdkRectangle* cliprect, GtkTextDirection direction) +{ + GtkStyleContext* style; + + ensure_tooltip_widget(); + gtk_widget_set_direction(gTooltipWidget, direction); + + style = gtk_widget_get_style_context(gTooltipWidget); + gtk_style_context_save(style); + gtk_style_context_add_class(style, GTK_STYLE_CLASS_TOOLTIP); + gtk_render_background(style, cr, rect->x, rect->y, rect->width, rect->height); + gtk_render_frame(style, cr, rect->x, rect->y, rect->width, rect->height); + gtk_style_context_restore(style); + return MOZ_GTK_SUCCESS; +} + +static gint +moz_gtk_resizer_paint(cairo_t *cr, GdkRectangle* rect, + GdkRectangle* cliprect, GtkWidgetState* state, + GtkTextDirection direction) +{ + GtkStyleContext* style; + + ensure_frame_widget(); + gtk_widget_set_direction(gStatusbarWidget, direction); + + style = gtk_widget_get_style_context(gStatusbarWidget); + gtk_style_context_save(style); + gtk_style_context_add_class(style, GTK_STYLE_CLASS_GRIP); + gtk_style_context_set_state(style, GetStateFlagsFromGtkWidgetState(state)); + + gtk_render_handle(style, cr, rect->x, rect->y, rect->width, rect->height); + gtk_style_context_restore(style); + + return MOZ_GTK_SUCCESS; +} + +static gint +moz_gtk_frame_paint(cairo_t *cr, GdkRectangle* rect, + GdkRectangle* cliprect, GtkTextDirection direction) +{ + GtkStyleContext* style; + + ensure_frame_widget(); + gtk_widget_set_direction(gFrameWidget, direction); + style = gtk_widget_get_style_context(gFrameWidget); + gtk_style_context_save(style); + gtk_style_context_add_class(style, GTK_STYLE_CLASS_FRAME); + + gtk_render_frame(style, cr, rect->x, rect->y, rect->width, rect->height); + gtk_style_context_restore(style); + return MOZ_GTK_SUCCESS; +} + +static gint +moz_gtk_progressbar_paint(cairo_t *cr, GdkRectangle* rect, + GdkRectangle* cliprect, GtkTextDirection direction) +{ + GtkStyleContext* style; + + ensure_progress_widget(); + gtk_widget_set_direction(gProgressWidget, direction); + + style = gtk_widget_get_style_context(gProgressWidget); + gtk_style_context_save(style); + gtk_style_context_add_class(style, GTK_STYLE_CLASS_TROUGH); + + gtk_render_background(style, cr, rect->x, rect->y, rect->width, rect->height); + gtk_render_frame(style, cr, rect->x, rect->y, rect->width, rect->height); + gtk_style_context_restore(style); + + return MOZ_GTK_SUCCESS; +} + +static gint +moz_gtk_progress_chunk_paint(cairo_t *cr, GdkRectangle* rect, + GdkRectangle* cliprect, GtkTextDirection direction, + GtkThemeWidgetType widget) +{ + GtkStyleContext* style; + + ensure_progress_widget(); + gtk_widget_set_direction(gProgressWidget, direction); + + style = gtk_widget_get_style_context(gProgressWidget); + gtk_style_context_save(style); + gtk_style_context_add_class(style, GTK_STYLE_CLASS_PROGRESSBAR); + + if (widget == MOZ_GTK_PROGRESS_CHUNK_INDETERMINATE || + widget == MOZ_GTK_PROGRESS_CHUNK_VERTICAL_INDETERMINATE) { + /** + * The bar's size and the bar speed are set depending of the progress' + * size. These could also be constant for all progress bars easily. + */ + gboolean vertical = (widget == MOZ_GTK_PROGRESS_CHUNK_VERTICAL_INDETERMINATE); + + /* The size of the dimension we are going to use for the animation. */ + const gint progressSize = vertical ? rect->height : rect->width; + + /* The bar is using a fifth of the element size, based on GtkProgressBar + * activity-blocks property. */ + const gint barSize = MAX(1, progressSize / 5); + + /* Represents the travel that has to be done for a complete cycle. */ + const gint travel = 2 * (progressSize - barSize); + + /* period equals to travel / pixelsPerMillisecond + * where pixelsPerMillisecond equals progressSize / 1000.0. + * This is equivalent to 1600. */ + static const guint period = 1600; + const gint t = PR_IntervalToMilliseconds(PR_IntervalNow()) % period; + const gint dx = travel * t / period; + + if (vertical) { + rect->y += (dx < travel / 2) ? dx : travel - dx; + rect->height = barSize; + } else { + rect->x += (dx < travel / 2) ? dx : travel - dx; + rect->width = barSize; + } + } + + gtk_render_background(style, cr, rect->x, rect->y, rect->width, rect->height); + gtk_render_activity(style, cr, rect->x, rect->y, rect->width, rect->height); + gtk_style_context_restore(style); + + return MOZ_GTK_SUCCESS; +} + +gint +moz_gtk_get_tab_thickness(void) +{ + GtkBorder border; + + ensure_tab_widget(); + GtkStyleContext * style = gtk_widget_get_style_context(gTabWidget); + gtk_style_context_add_class(style, GTK_STYLE_CLASS_NOTEBOOK); + gtk_style_context_get_border(style, 0, &border); + + if (border.top < 2) + return 2; /* some themes don't set ythickness correctly */ + + return border.top; +} + +/* actual small tabs */ +static gint +moz_gtk_tab_paint(cairo_t *cr, GdkRectangle* rect, + GdkRectangle* cliprect, GtkWidgetState* state, + GtkTabFlags flags, GtkTextDirection direction) +{ + /* When the tab isn't selected, we just draw a notebook extension. + * When it is selected, we overwrite the adjacent border of the tabpanel + * touching the tab with a pierced border (called "the gap") to make the + * tab appear physically attached to the tabpanel; see details below. */ + + GtkStyleContext* style; + GdkRectangle focusRect; + + ensure_tab_widget(); + gtk_widget_set_direction(gTabWidget, direction); + + style = gtk_widget_get_style_context(gTabWidget); + focusRect = *rect; + + gtk_style_context_save(style); + + if ((flags & MOZ_GTK_TAB_SELECTED) == 0) { + /* Only draw the tab */ + gtk_style_context_set_state(style, GTK_STATE_FLAG_NORMAL); + gtk_render_extension(style, cr, + rect->x, rect->y, rect->width, rect->height, + (flags & MOZ_GTK_TAB_BOTTOM) ? + GTK_POS_TOP : GTK_POS_BOTTOM ); + } else { + /* Draw the tab and the gap + * We want the gap to be positioned exactly on the tabpanel top + * border; since tabbox.css may set a negative margin so that the tab + * frame rect already overlaps the tabpanel frame rect, we need to take + * that into account when drawing. To that effect, nsNativeThemeGTK + * passes us this negative margin (bmargin in the graphic below) in the + * lowest bits of |flags|. We use it to set gap_voffset, the distance + * between the top of the gap and the bottom of the tab (resp. the + * bottom of the gap and the top of the tab when we draw a bottom tab), + * while ensuring that the gap always touches the border of the tab, + * i.e. 0 <= gap_voffset <= gap_height, to avoid surprinsing results + * with big negative or positive margins. + * Here is a graphical explanation in the case of top tabs: + * ___________________________ + * / \ + * | T A B | + * ----------|. . . . . . . . . . . . . . .|----- top of tabpanel + * : ^ bmargin : ^ + * : | (-negative margin, : | + * bottom : v passed in flags) : | gap_height + * of -> :.............................: | (the size of the + * the tab . part of the gap . | tabpanel top border) + * . outside of the tab . v + * ---------------------------------------------- + * + * To draw the gap, we use gtk_paint_box_gap(), see comment in + * moz_gtk_tabpanels_paint(). This box_gap is made 3 * gap_height tall, + * which should suffice to ensure that the only visible border is the + * pierced one. If the tab is in the middle, we make the box_gap begin + * a bit to the left of the tab and end a bit to the right, adjusting + * the gap position so it still is under the tab, because we want the + * rendering of a gap in the middle of a tabpanel. This is the role of + * the gints gap_{l,r}_offset. On the contrary, if the tab is the + * first, we align the start border of the box_gap with the start + * border of the tab (left if LTR, right if RTL), by setting the + * appropriate offset to 0.*/ + gint gap_loffset, gap_roffset, gap_voffset, gap_height; + + /* Get height needed by the gap */ + gap_height = moz_gtk_get_tab_thickness(); + + /* Extract gap_voffset from the first bits of flags */ + gap_voffset = flags & MOZ_GTK_TAB_MARGIN_MASK; + if (gap_voffset > gap_height) + gap_voffset = gap_height; + + /* Set gap_{l,r}_offset to appropriate values */ + gap_loffset = gap_roffset = 20; /* should be enough */ + if (flags & MOZ_GTK_TAB_FIRST) { + if (direction == GTK_TEXT_DIR_RTL) + gap_roffset = 0; + else + gap_loffset = 0; + } + + gtk_style_context_set_state(style, GTK_STATE_FLAG_ACTIVE); + + /* Adwaita theme engine crashes without it (rhbz#713764) */ + gtk_style_context_add_region(style, GTK_STYLE_REGION_TAB, 0); + + if (flags & MOZ_GTK_TAB_BOTTOM) { + /* Draw the tab on bottom */ + focusRect.y += gap_voffset; + focusRect.height -= gap_voffset; + + gtk_render_extension(style, cr, + rect->x, rect->y + gap_voffset, rect->width, + rect->height - gap_voffset, GTK_POS_TOP); + + /* Draw the gap; erase with background color before painting in + * case theme does not */ + gtk_render_background(style, cr, + rect->x, + rect->y + gap_voffset + - gap_height, + rect->width, gap_height); + gtk_render_frame_gap(style, cr, + rect->x - gap_loffset, + rect->y + gap_voffset - 3 * gap_height, + rect->width + gap_loffset + gap_roffset, + 3 * gap_height, GTK_POS_BOTTOM, + gap_loffset, gap_loffset + rect->width); + + } else { + /* Draw the tab on top */ + focusRect.height -= gap_voffset; + gtk_render_extension(style, cr, + rect->x, rect->y, rect->width, + rect->height - gap_voffset, GTK_POS_BOTTOM); + + /* Draw the gap; erase with background color before painting in + * case theme does not */ + gtk_render_background(style, cr, + rect->x, + rect->y + rect->height + - gap_voffset, + rect->width, gap_height); + gtk_render_frame_gap(style, cr, + rect->x - gap_loffset, + rect->y + rect->height - gap_voffset, + rect->width + gap_loffset + gap_roffset, + 3 * gap_height, GTK_POS_TOP, + gap_loffset, gap_loffset + rect->width); + } + } + + if (state->focused) { + /* Paint the focus ring */ + GtkBorder border; + gtk_style_context_get_border(style, GetStateFlagsFromGtkWidgetState(state), &border); + + focusRect.x += border.left; + focusRect.width -= (border.left + border.right); + focusRect.y += border.top; + focusRect.height -= (border.top + border.bottom); + + gtk_render_focus(style, cr, + focusRect.x, focusRect.y, focusRect.width, focusRect.height); + } + + gtk_style_context_restore(style); + + return MOZ_GTK_SUCCESS; +} + +/* tab area*/ +static gint +moz_gtk_tabpanels_paint(cairo_t *cr, GdkRectangle* rect, + GdkRectangle* cliprect, GtkTextDirection direction) +{ + GtkStyleContext* style; + + ensure_tab_widget(); + gtk_widget_set_direction(gTabWidget, direction); + + style = gtk_widget_get_style_context(gTabWidget); + gtk_style_context_save(style); + + gtk_render_background(style, cr, rect->x, rect->y, + rect->width, rect->height); + /* + * The gap size is not needed in moz_gtk_tabpanels_paint because + * the gap will be painted with the foreground tab in moz_gtk_tab_paint. + * + * However, if moz_gtk_tabpanels_paint just uses gtk_render_frame(), + * the theme will think that there are no tabs and may draw something + * different.Hence the trick of using two clip regions, and drawing the + * gap outside each clip region, to get the correct frame for + * a tabpanel with tabs. + */ + /* left side */ + cairo_save(cr); + cairo_rectangle(rect->x, rect->y, + rect->x + rect->width / 2, + rect->y + rect->height) + cairo_clip(cr); + gtk_render_frame_gap(style, cr, + rect->x, rect->y, + rect->width, rect->height, + GTK_POS_TOP, rect->width - 1, rect->width); + cairo_restore(cr); + + /* right side */ + cairo_save(cr); + cairo_rectangle(rect->x + rect->width / 2, rect->y, + rect->x + rect->width, + rect->y + rect->height) + cairo_clip(cr); + gtk_render_frame_gap(style, cr, + rect->x, rect->y, + rect->width, rect->height, + GTK_POS_TOP, 0, 1); + cairo_restore(cr); + + gtk_style_context_restore(style); + return MOZ_GTK_SUCCESS; +} + +static gint +moz_gtk_tab_scroll_arrow_paint(cairo_t *cr, GdkRectangle* rect, + GdkRectangle* cliprect, GtkWidgetState* state, + GtkArrowType arrow_type, + GtkTextDirection direction) +{ + GtkStateFlags state_flags = GetStateFlagsFromGtkWidgetState(state); + GtkStyleContext* style; + gdouble arrow_angle; + gint arrow_size = MIN(rect->width, rect->height); + gint x = rect->x + (rect->width - arrow_size) / 2; + gint y = rect->y + (rect->height - arrow_size) / 2; + + ensure_tab_widget(); + + style = gtk_widget_get_style_context(gTabWidget); + gtk_style_context_save(style); + if (direction == GTK_TEXT_DIR_RTL) { + arrow_type = (arrow_type == GTK_ARROW_LEFT) ? + GTK_ARROW_RIGHT : GTK_ARROW_LEFT; + } + switch (arrow_type) { + case GTK_ARROW_LEFT: + arrow_angle = ARROW_LEFT; + break; + case GTK_ARROW_RIGHT: + arrow_angle = ARROW_RIGHT; + break; + case GTK_ARROW_DOWN: + arrow_angle = ARROW_DOWN; + break; + default: + arrow_angle = ARROW_UP; + break; + } + if (arrow_type != GTK_ARROW_NONE) { + gtk_style_context_add_class(style, GTK_STYLE_CLASS_NOTEBOOK); /* TODO TEST */ + gtk_style_context_set_state(style, state_flags); + gtk_render_arrow(style, cr, arrow_angle, + x, y, arrow_size); + } + gtk_style_context_restore(style); + return MOZ_GTK_SUCCESS; +} + +static gint +moz_gtk_menu_bar_paint(cairo_t *cr, GdkRectangle* rect, + GdkRectangle* cliprect, GtkTextDirection direction) +{ + GtkStyleContext* style; + + ensure_menu_bar_widget(); + gtk_widget_set_direction(gMenuBarWidget, direction); + + style = gtk_widget_get_style_context(gMenuBarWidget); + gtk_style_context_save(style); + gtk_style_context_add_class(style, GTK_STYLE_CLASS_MENUBAR); + gtk_render_background(style, cr, rect->x, rect->y, rect->width, rect->height); + gtk_render_frame(style, cr, rect->x, rect->y, rect->width, rect->height); + gtk_style_context_restore(style); + + return MOZ_GTK_SUCCESS; +} + +static gint +moz_gtk_menu_popup_paint(cairo_t *cr, GdkRectangle* rect, + GdkRectangle* cliprect, GtkTextDirection direction) +{ + GtkStyleContext* style; + + ensure_menu_popup_widget(); + gtk_widget_set_direction(gMenuPopupWidget, direction); + + style = gtk_widget_get_style_context(gMenuPopupWidget); + gtk_style_context_save(style); + gtk_style_context_add_class(style, GTK_STYLE_CLASS_MENU); + + gtk_render_background(style, cr, rect->x, rect->y, rect->width, rect->height); + gtk_render_frame(style, cr, rect->x, rect->y, rect->width, rect->height); + gtk_style_context_restore(style); + + return MOZ_GTK_SUCCESS; +} + +static gint +moz_gtk_menu_separator_paint(cairo_t *cr, GdkRectangle* rect, + GdkRectangle* cliprect, GtkTextDirection direction) +{ + GtkStyleContext* style; + gboolean wide_separators; + gint separator_height; + guint horizontal_padding; + gint paint_height; + GtkBorder border; + + ensure_menu_separator_widget(); + gtk_widget_set_direction(gMenuSeparatorWidget, direction); + + style = gtk_widget_get_style_context(gMenuSeparatorWidget); + + gtk_style_context_save(style); + + gtk_widget_style_get(gMenuSeparatorWidget, + "wide-separators", &wide_separators, + "separator-height", &separator_height, + "horizontal-padding", &horizontal_padding, + NULL); + + gtk_style_context_get_border(style, 0, &border); + + if (wide_separators) { + if (separator_height > rect->height) + separator_height = rect->height; + + gtk_render_frame(style, cr, + rect->x + horizontal_padding + border.left, + rect->y + (rect->height - separator_height - border.top) / 2, + rect->width - 2 * (horizontal_padding + border.left), + separator_height); + } else { + paint_height = border.top; + if (paint_height > rect->height) + paint_height = rect->height; + + gtk_render_line(style, cr, + rect->x + horizontal_padding + border.left, + rect->y + (rect->height - border.top) / 2, + rect->x + rect->width - horizontal_padding - border.left - 1, + rect->y + (rect->height - border.top) / 2); + } + + gtk_style_context_restore(style); + return MOZ_GTK_SUCCESS; +} + +static gint +moz_gtk_menu_item_paint(cairo_t *cr, GdkRectangle* rect, + GdkRectangle* cliprect, GtkWidgetState* state, + gint flags, GtkTextDirection direction) +{ + GtkStyleContext* style; + GtkWidget* item_widget; + + if (state->inHover && !state->disabled) { + gtk_style_context_save(style); + style = gtk_widget_get_style_context(item_widget); + + if (flags & MOZ_TOPLEVEL_MENU_ITEM) { + ensure_menu_bar_item_widget(); + item_widget = gMenuBarItemWidget; + gtk_style_context_add_class(style, GTK_STYLE_CLASS_MENUBAR); + } else { + ensure_menu_item_widget(); + item_widget = gMenuItemWidget; + } + + gtk_widget_set_direction(item_widget, direction); + gtk_style_context_add_class(style, GTK_STYLE_CLASS_MENUITEM); + gtk_style_context_set_state(style, GetStateFlagsFromGtkWidgetState(state)); + + gtk_render_background(style, cr, rect->x, rect->y, rect->width, rect->height); + gtk_render_frame(style, cr, rect->x, rect->y, rect->width, rect->height); + gtk_style_context_restore(style); + } + + return MOZ_GTK_SUCCESS; +} + +static gint +moz_gtk_menu_arrow_paint(cairo_t *cr, GdkRectangle* rect, + GdkRectangle* cliprect, GtkWidgetState* state, + GtkTextDirection direction) +{ + GtkStyleContext* style; + GtkStateFlags state_flags = GetStateFlagsFromGtkWidgetState(state); + + ensure_menu_item_widget(); + gtk_widget_set_direction(gMenuItemWidget, direction); + + style = gtk_widget_get_style_context(gMenuItemWidget); + gtk_style_context_save(style); + gtk_style_context_add_class(style, GTK_STYLE_CLASS_MENUITEM); + gtk_style_context_set_state(style, state_flags); + gtk_render_arrow(style, cr, + (direction == GTK_TEXT_DIR_LTR) ? ARROW_RIGHT : ARROW_LEFT, + rect->x, rect->y, rect->width); + gtk_style_context_restore(style); + + return MOZ_GTK_SUCCESS; +} + +static gint +moz_gtk_check_menu_item_paint(cairo_t *cr, GdkRectangle* rect, + GdkRectangle* cliprect, GtkWidgetState* state, + gboolean checked, gboolean isradio, + GtkTextDirection direction) +{ + GtkStateFlags state_flags = GetStateFlagsFromGtkWidgetState(state); + GtkStyleContext* style; + GtkBorder border; + gint offset; + gint indicator_size, horizontal_padding; + gint x, y; + + moz_gtk_menu_item_paint(cr, rect, cliprect, state, FALSE, direction); + + ensure_check_menu_item_widget(); + gtk_widget_set_direction(gCheckMenuItemWidget, direction); + + gtk_widget_style_get (gCheckMenuItemWidget, + "indicator-size", &indicator_size, + "horizontal-padding", &horizontal_padding, + NULL); + + style = gtk_widget_get_style_context(gCheckMenuItemWidget); + gtk_style_context_save(style); + if (isradio) { + gtk_style_context_add_class(style, GTK_STYLE_CLASS_RADIO); + } else { + gtk_style_context_add_class(style, GTK_STYLE_CLASS_CHECK); + } + + if (checked) + state_flags |= GTK_STATE_FLAG_ACTIVE; + + gtk_style_context_set_state(style, state_flags); + gtk_style_context_get_border(style, state_flags, &border); + + offset = gtk_container_get_border_width(GTK_CONTAINER(gCheckMenuItemWidget)) + + border.left + 2; + + x = (direction == GTK_TEXT_DIR_RTL) ? + rect->width - indicator_size - offset - horizontal_padding: rect->x + offset + horizontal_padding; + y = rect->y + (rect->height - indicator_size) / 2; + + if (isradio) { + gtk_render_option(style, cr, x, y, indicator_size, indicator_size); + } else { + gtk_render_check(style, cr, x, y, indicator_size, indicator_size); + } + gtk_style_context_restore(style); + + return MOZ_GTK_SUCCESS; +} + +static gint +moz_gtk_window_paint(cairo_t *cr, GdkRectangle* rect, + GdkRectangle* cliprect, GtkTextDirection direction) +{ + GtkStyleContext* style; + + ensure_window_widget(); + gtk_widget_set_direction(gProtoWindow, direction); + + style = gtk_widget_get_style_context(gProtoWindow); + gtk_style_context_save(style); + gtk_style_context_add_class(style, GTK_STYLE_CLASS_BACKGROUND); + gtk_render_background(style, cr, rect->x, rect->y, rect->width, rect->height); + gtk_style_context_restore(style); + + return MOZ_GTK_SUCCESS; +} + +gint +moz_gtk_get_widget_border(GtkThemeWidgetType widget, gint* left, gint* top, + gint* right, gint* bottom, GtkTextDirection direction, + gboolean inhtml) +{ + GtkWidget* w; + GtkStyleContext* style; + GtkBorder border; + + switch (widget) { + case MOZ_GTK_BUTTON: + { + GtkBorder inner_border; + gboolean interior_focus; + gint focus_width, focus_pad; + + ensure_button_widget(); + *left = *top = *right = *bottom = gtk_container_get_border_width(GTK_CONTAINER(gButtonWidget)); + + /* Don't add this padding in HTML, otherwise the buttons will + become too big and stuff the layout. */ + if (!inhtml) { + moz_gtk_widget_get_focus(gButtonWidget, &interior_focus, &focus_width, &focus_pad); + moz_gtk_button_get_inner_border(gButtonWidget, &inner_border); + *left += focus_width + focus_pad + inner_border.left; + *right += focus_width + focus_pad + inner_border.right; + *top += focus_width + focus_pad + inner_border.top; + *bottom += focus_width + focus_pad + inner_border.bottom; + } + + style = gtk_widget_get_style_context(gButtonWidget); + gtk_style_context_get_border(style, 0, &border); + + *left += border.left; + *right += border.right; + *top += border.top; + *bottom += border.bottom; + return MOZ_GTK_SUCCESS; + } + case MOZ_GTK_ENTRY: + ensure_entry_widget(); + w = gEntryWidget; + break; + case MOZ_GTK_TREEVIEW: + ensure_tree_view_widget(); + w = gTreeViewWidget; + break; + case MOZ_GTK_TREE_HEADER_CELL: + { + /* A Tree Header in GTK is just a different styled button + * It must be placed in a TreeView for getting the correct style + * assigned. + * That is why the following code is the same as for MOZ_GTK_BUTTON. + * */ + + GtkBorder inner_border; + gboolean interior_focus; + gint focus_width, focus_pad; + + ensure_tree_header_cell_widget(); + *left = *top = *right = *bottom = gtk_container_get_border_width(GTK_CONTAINER(gTreeHeaderCellWidget)); + + moz_gtk_widget_get_focus(gTreeHeaderCellWidget, &interior_focus, &focus_width, &focus_pad); + moz_gtk_button_get_inner_border(gTreeHeaderCellWidget, &inner_border); + *left += focus_width + focus_pad + inner_border.left; + *right += focus_width + focus_pad + inner_border.right; + *top += focus_width + focus_pad + inner_border.top; + *bottom += focus_width + focus_pad + inner_border.bottom; + + style = gtk_widget_get_style_context(gTreeHeaderCellWidget); + gtk_style_context_get_border(style, 0, &border); + + *left += border.left; + *right += border.right; + *top += border.top; + *bottom += border.bottom; + return MOZ_GTK_SUCCESS; + } + case MOZ_GTK_TREE_HEADER_SORTARROW: + ensure_tree_header_cell_widget(); + w = gTreeHeaderSortArrowWidget; + break; + case MOZ_GTK_DROPDOWN_ENTRY: + ensure_combo_box_entry_widgets(); + w = gComboBoxEntryTextareaWidget; + break; + case MOZ_GTK_DROPDOWN_ARROW: + ensure_combo_box_entry_widgets(); + w = gComboBoxEntryButtonWidget; + break; + case MOZ_GTK_DROPDOWN: + { + /* We need to account for the arrow on the dropdown, so text + * doesn't come too close to the arrow, or in some cases spill + * into the arrow. */ + gboolean ignored_interior_focus, wide_separators; + gint focus_width, focus_pad, separator_width; + GtkRequisition arrow_req; + + ensure_combo_box_widgets(); + + *left = gtk_container_get_border_width(GTK_CONTAINER(gComboBoxButtonWidget)); + + if (!inhtml) { + moz_gtk_widget_get_focus(gComboBoxButtonWidget, + &ignored_interior_focus, + &focus_width, &focus_pad); + *left += focus_width + focus_pad; + } + + style = gtk_widget_get_style_context(gComboBoxButtonWidget); + gtk_style_context_get_border(style, 0, &border); + + *top = *left + border.top; + *left += border.left; + + *right = *left; *bottom = *top; + + /* If there is no separator, don't try to count its width. */ + separator_width = 0; + if (gComboBoxSeparatorWidget) { + gtk_widget_style_get(gComboBoxSeparatorWidget, + "wide-separators", &wide_separators, + "separator-width", &separator_width, + NULL); + + if (!wide_separators) { + style = gtk_widget_get_style_context(gComboBoxSeparatorWidget); + gtk_style_context_get_border(style, 0, &border); + separator_width = border.left; + } + } + + gtk_widget_size_request(gComboBoxArrowWidget, &arrow_req); + + if (direction == GTK_TEXT_DIR_RTL) + *left += separator_width + arrow_req.width; + else + *right += separator_width + arrow_req.width; + + return MOZ_GTK_SUCCESS; + } + case MOZ_GTK_TABPANELS: + ensure_tab_widget(); + w = gTabWidget; + break; + case MOZ_GTK_PROGRESSBAR: + ensure_progress_widget(); + w = gProgressWidget; + break; + case MOZ_GTK_SPINBUTTON_ENTRY: + case MOZ_GTK_SPINBUTTON_UP: + case MOZ_GTK_SPINBUTTON_DOWN: + ensure_spin_widget(); + w = gSpinWidget; + break; + case MOZ_GTK_SCALE_HORIZONTAL: + ensure_scale_widget(); + w = gHScaleWidget; + break; + case MOZ_GTK_SCALE_VERTICAL: + ensure_scale_widget(); + w = gVScaleWidget; + break; + case MOZ_GTK_FRAME: + ensure_frame_widget(); + w = gFrameWidget; + break; + case MOZ_GTK_CHECKBUTTON_LABEL: + case MOZ_GTK_RADIOBUTTON_LABEL: + { + gboolean interior_focus; + gint focus_width, focus_pad; + + /* If the focus is interior, then the label has a border of + (focus_width + focus_pad). */ + if (widget == MOZ_GTK_CHECKBUTTON_LABEL) { + ensure_checkbox_widget(); + moz_gtk_widget_get_focus(gCheckboxWidget, &interior_focus, + &focus_width, &focus_pad); + } + else { + ensure_radiobutton_widget(); + moz_gtk_widget_get_focus(gRadiobuttonWidget, &interior_focus, + &focus_width, &focus_pad); + } + + if (interior_focus) + *left = *top = *right = *bottom = (focus_width + focus_pad); + else + *left = *top = *right = *bottom = 0; + + return MOZ_GTK_SUCCESS; + } + + case MOZ_GTK_CHECKBUTTON_CONTAINER: + case MOZ_GTK_RADIOBUTTON_CONTAINER: + { + gboolean interior_focus; + gint focus_width, focus_pad; + + /* If the focus is _not_ interior, then the container has a border + of (focus_width + focus_pad). */ + if (widget == MOZ_GTK_CHECKBUTTON_CONTAINER) { + ensure_checkbox_widget(); + moz_gtk_widget_get_focus(gCheckboxWidget, &interior_focus, + &focus_width, &focus_pad); + w = gCheckboxWidget; + } else { + ensure_radiobutton_widget(); + moz_gtk_widget_get_focus(gRadiobuttonWidget, &interior_focus, + &focus_width, &focus_pad); + w = gRadiobuttonWidget; + } + + *left = *top = *right = *bottom = gtk_container_get_border_width(GTK_CONTAINER(w)); + + if (!interior_focus) { + *left += (focus_width + focus_pad); + *right += (focus_width + focus_pad); + *top += (focus_width + focus_pad); + *bottom += (focus_width + focus_pad); + } + + return MOZ_GTK_SUCCESS; + } + case MOZ_GTK_MENUPOPUP: + ensure_menu_popup_widget(); + w = gMenuPopupWidget; + break; + case MOZ_GTK_MENUITEM: + ensure_menu_item_widget(); + ensure_menu_bar_item_widget(); + w = gMenuItemWidget; + break; + case MOZ_GTK_CHECKMENUITEM: + case MOZ_GTK_RADIOMENUITEM: + ensure_check_menu_item_widget(); + w = gCheckMenuItemWidget; + break; + case MOZ_GTK_TAB: + ensure_tab_widget(); + w = gTabWidget; + break; + /* These widgets have no borders, since they are not containers. */ + case MOZ_GTK_SPLITTER_HORIZONTAL: + case MOZ_GTK_SPLITTER_VERTICAL: + case MOZ_GTK_CHECKBUTTON: + case MOZ_GTK_RADIOBUTTON: + case MOZ_GTK_SCROLLBAR_BUTTON: + case MOZ_GTK_SCROLLBAR_TRACK_HORIZONTAL: + case MOZ_GTK_SCROLLBAR_TRACK_VERTICAL: + case MOZ_GTK_SCROLLBAR_THUMB_HORIZONTAL: + case MOZ_GTK_SCROLLBAR_THUMB_VERTICAL: + case MOZ_GTK_SCALE_THUMB_HORIZONTAL: + case MOZ_GTK_SCALE_THUMB_VERTICAL: + case MOZ_GTK_GRIPPER: + case MOZ_GTK_PROGRESS_CHUNK: + case MOZ_GTK_PROGRESS_CHUNK_INDETERMINATE: + case MOZ_GTK_PROGRESS_CHUNK_VERTICAL_INDETERMINATE: + case MOZ_GTK_EXPANDER: + case MOZ_GTK_TREEVIEW_EXPANDER: + case MOZ_GTK_TOOLBAR_SEPARATOR: + case MOZ_GTK_MENUSEPARATOR: + /* These widgets have no borders.*/ + case MOZ_GTK_SPINBUTTON: + case MOZ_GTK_TOOLTIP: + case MOZ_GTK_WINDOW: + case MOZ_GTK_RESIZER: + case MOZ_GTK_MENUARROW: + case MOZ_GTK_TOOLBARBUTTON_ARROW: + case MOZ_GTK_TOOLBAR: + case MOZ_GTK_MENUBAR: + case MOZ_GTK_TAB_SCROLLARROW: + case MOZ_GTK_ENTRY_CARET: + *left = *top = *right = *bottom = 0; + return MOZ_GTK_SUCCESS; + default: + g_warning("Unsupported widget type: %d", widget); + return MOZ_GTK_UNKNOWN_WIDGET; + } + /* TODO - we're still missing some widget implementations */ + if (!w) { + *right = *left = 0; + *bottom = *top = 0; + } else { + style = gtk_widget_get_style_context(w); + gtk_style_context_get_border(style, 0, &border); + *left = border.left; + *right = border.right; + *top = border.top; + *bottom = border.bottom; + } + return MOZ_GTK_SUCCESS; +} + +gint +moz_gtk_get_combo_box_entry_button_size(gint* width, gint* height) +{ + /* + * We get the requisition of the drop down button, which includes + * all padding, border and focus line widths the button uses, + * as well as the minimum arrow size and its padding + * */ + GtkRequisition requisition; + ensure_combo_box_entry_widgets(); + + gtk_widget_size_request(gComboBoxEntryButtonWidget, &requisition); + *width = requisition.width; + *height = requisition.height; + + return MOZ_GTK_SUCCESS; +} + +gint +moz_gtk_get_tab_scroll_arrow_size(gint* width, gint* height) +{ + gint arrow_size; + + ensure_tab_widget(); + gtk_widget_style_get(gTabWidget, + "scroll-arrow-hlength", &arrow_size, + NULL); + + *height = *width = arrow_size; + + return MOZ_GTK_SUCCESS; +} + +gint +moz_gtk_get_arrow_size(gint* width, gint* height) +{ + GtkRequisition requisition; + ensure_button_arrow_widget(); + + gtk_widget_size_request(gButtonArrowWidget, &requisition); + *width = requisition.width; + *height = requisition.height; + + return MOZ_GTK_SUCCESS; +} + +gint +moz_gtk_get_toolbar_separator_width(gint* size) +{ + gboolean wide_separators; + gint separator_width; + GtkStyleContext* style; + GtkBorder border; + + ensure_toolbar_widget(); + style = gtk_widget_get_style_context(gToolbarWidget); + + gtk_widget_style_get(gToolbarWidget, + "space-size", size, + "wide-separators", &wide_separators, + "separator-width", &separator_width, + NULL); + /* Just in case... */ + gtk_style_context_get_border(style, 0, &border); + *size = MAX(*size, (wide_separators ? separator_width : border.left)); + return MOZ_GTK_SUCCESS; +} + +gint +moz_gtk_get_expander_size(gint* size) +{ + ensure_expander_widget(); + gtk_widget_style_get(gExpanderWidget, + "expander-size", size, + NULL); + + return MOZ_GTK_SUCCESS; +} + +gint +moz_gtk_get_treeview_expander_size(gint* size) +{ + ensure_tree_view_widget(); + gtk_widget_style_get(gTreeViewWidget, + "expander-size", size, + NULL); + + return MOZ_GTK_SUCCESS; +} + +gint +moz_gtk_get_menu_separator_height(gint *size) +{ + gboolean wide_separators; + gint separator_height; + GtkBorder border; + GtkStyleContext* style; + + ensure_menu_separator_widget(); + + gtk_widget_style_get(gMenuSeparatorWidget, + "wide-separators", &wide_separators, + "separator-height", &separator_height, + NULL); + + style = gtk_widget_get_style_context(gMenuSeparatorWidget); + gtk_style_context_get_border(style, 0, &border); + + if (wide_separators) + *size = separator_height + border.top; + else + *size = border.top + border.bottom; + + return MOZ_GTK_SUCCESS; +} + +gint +moz_gtk_get_scalethumb_metrics(GtkOrientation orient, gint* thumb_length, gint* thumb_height) +{ + GtkWidget* widget; + + ensure_scale_widget(); + widget = ((orient == GTK_ORIENTATION_HORIZONTAL) ? gHScaleWidget : gVScaleWidget); + + gtk_widget_style_get (widget, + "slider_length", thumb_length, + "slider_width", thumb_height, + NULL); + + return MOZ_GTK_SUCCESS; +} + +gint +moz_gtk_get_scrollbar_metrics(MozGtkScrollbarMetrics *metrics) +{ + ensure_scrollbar_widget(); + + gtk_widget_style_get (gHorizScrollbarWidget, + "slider_width", &metrics->slider_width, + "trough_border", &metrics->trough_border, + "stepper_size", &metrics->stepper_size, + "stepper_spacing", &metrics->stepper_spacing, + NULL); + + metrics->min_slider_size = + gtk_range_get_min_slider_size(GTK_RANGE(gHorizScrollbarWidget)); + + return MOZ_GTK_SUCCESS; +} + +gboolean +moz_gtk_images_in_menus() +{ + gboolean result; + GtkSettings* settings; + + ensure_image_menu_item_widget(); + settings = gtk_widget_get_settings(gImageMenuItemWidget); + + g_object_get(settings, "gtk-menu-images", &result, NULL); + return result; +} + +gboolean +moz_gtk_images_in_buttons() +{ + gboolean result; + GtkSettings* settings; + + ensure_button_widget(); + settings = gtk_widget_get_settings(gButtonWidget); + + g_object_get(settings, "gtk-button-images", &result, NULL); + return result; +} + +/* cairo_t *cr argument has to be a system-cairo. */ +/* TODO: GdkRectangle* cliprect is unused, shall we remove it? */ +gint +moz_gtk_widget_paint(GtkThemeWidgetType widget, cairo_t *cr, + GdkRectangle* rect, GdkRectangle* cliprect, + GtkWidgetState* state, gint flags, + GtkTextDirection direction) +{ + switch (widget) { + case MOZ_GTK_BUTTON: + if (state->depressed) { + ensure_toggle_button_widget(); + return moz_gtk_button_paint(cr, rect, cliprect, state, + (GtkReliefStyle) flags, + gToggleButtonWidget, direction); + } + ensure_button_widget(); + return moz_gtk_button_paint(cr, rect, cliprect, state, + (GtkReliefStyle) flags, gButtonWidget, + direction); + break; + case MOZ_GTK_CHECKBUTTON: + case MOZ_GTK_RADIOBUTTON: + return moz_gtk_toggle_paint(cr, rect, cliprect, state, + !!(flags & MOZ_GTK_WIDGET_CHECKED), + !!(flags & MOZ_GTK_WIDGET_INCONSISTENT), + (widget == MOZ_GTK_RADIOBUTTON), + direction); + break; + case MOZ_GTK_SCROLLBAR_BUTTON: + return moz_gtk_scrollbar_button_paint(cr, rect, cliprect, state, + (GtkScrollbarButtonFlags) flags, + direction); + break; + case MOZ_GTK_SCROLLBAR_TRACK_HORIZONTAL: + case MOZ_GTK_SCROLLBAR_TRACK_VERTICAL: + return moz_gtk_scrollbar_trough_paint(widget, cr, rect, + cliprect, state, direction); + break; + case MOZ_GTK_SCROLLBAR_THUMB_HORIZONTAL: + case MOZ_GTK_SCROLLBAR_THUMB_VERTICAL: + return moz_gtk_scrollbar_thumb_paint(widget, cr, rect, + cliprect, state, direction); + break; + case MOZ_GTK_SCALE_HORIZONTAL: + case MOZ_GTK_SCALE_VERTICAL: + return moz_gtk_scale_paint(cr, rect, cliprect, state, + (GtkOrientation) flags, direction); + break; + case MOZ_GTK_SCALE_THUMB_HORIZONTAL: + case MOZ_GTK_SCALE_THUMB_VERTICAL: + return moz_gtk_scale_thumb_paint(cr, rect, cliprect, state, + (GtkOrientation) flags, direction); + break; + case MOZ_GTK_SPINBUTTON: + return moz_gtk_spin_paint(cr, rect, direction); + break; + case MOZ_GTK_SPINBUTTON_UP: + case MOZ_GTK_SPINBUTTON_DOWN: + return moz_gtk_spin_updown_paint(cr, rect, + (widget == MOZ_GTK_SPINBUTTON_DOWN), + state, direction); + break; + case MOZ_GTK_SPINBUTTON_ENTRY: + ensure_spin_widget(); + return moz_gtk_entry_paint(cr, rect, cliprect, state, + gSpinWidget, direction); + break; + case MOZ_GTK_GRIPPER: + return moz_gtk_gripper_paint(cr, rect, cliprect, state, + direction); + break; + case MOZ_GTK_TREEVIEW: + return moz_gtk_treeview_paint(cr, rect, cliprect, state, + direction); + break; + case MOZ_GTK_TREE_HEADER_CELL: + return moz_gtk_tree_header_cell_paint(cr, rect, cliprect, state, + flags, direction); + break; + case MOZ_GTK_TREE_HEADER_SORTARROW: + return moz_gtk_tree_header_sort_arrow_paint(cr, rect, cliprect, + state, + (GtkArrowType) flags, + direction); + break; + case MOZ_GTK_TREEVIEW_EXPANDER: + return moz_gtk_treeview_expander_paint(cr, rect, cliprect, state, + (GtkExpanderStyle) flags, direction); + break; + case MOZ_GTK_EXPANDER: + return moz_gtk_expander_paint(cr, rect, cliprect, state, + (GtkExpanderStyle) flags, direction); + break; + case MOZ_GTK_ENTRY: + ensure_entry_widget(); + return moz_gtk_entry_paint(cr, rect, cliprect, state, + gEntryWidget, direction); + break; + case MOZ_GTK_ENTRY_CARET: + return moz_gtk_caret_paint(cr, rect, cliprect, direction); + break; + case MOZ_GTK_DROPDOWN: + return moz_gtk_combo_box_paint(cr, rect, cliprect, state, + (gboolean) flags, direction); + break; + case MOZ_GTK_DROPDOWN_ARROW: + return moz_gtk_combo_box_entry_button_paint(cr, rect, cliprect, + state, flags, direction); + break; + case MOZ_GTK_DROPDOWN_ENTRY: + ensure_combo_box_entry_widgets(); + return moz_gtk_entry_paint(cr, rect, cliprect, state, + gComboBoxEntryTextareaWidget, direction); + break; + case MOZ_GTK_CHECKBUTTON_CONTAINER: + case MOZ_GTK_RADIOBUTTON_CONTAINER: + return moz_gtk_container_paint(cr, rect, cliprect, state, + (widget == MOZ_GTK_RADIOBUTTON_CONTAINER), + direction); + break; + case MOZ_GTK_CHECKBUTTON_LABEL: + case MOZ_GTK_RADIOBUTTON_LABEL: + return moz_gtk_toggle_label_paint(cr, rect, cliprect, state, + (widget == MOZ_GTK_RADIOBUTTON_LABEL), + direction); + break; + case MOZ_GTK_TOOLBAR: + return moz_gtk_toolbar_paint(cr, rect, cliprect, direction); + break; + case MOZ_GTK_TOOLBAR_SEPARATOR: + return moz_gtk_toolbar_separator_paint(cr, rect, cliprect, + direction); + break; + case MOZ_GTK_TOOLTIP: + return moz_gtk_tooltip_paint(cr, rect, cliprect, direction); + break; + case MOZ_GTK_FRAME: + return moz_gtk_frame_paint(cr, rect, cliprect, direction); + break; + case MOZ_GTK_RESIZER: + return moz_gtk_resizer_paint(cr, rect, cliprect, state, + direction); + break; + case MOZ_GTK_PROGRESSBAR: + return moz_gtk_progressbar_paint(cr, rect, cliprect, direction); + break; + case MOZ_GTK_PROGRESS_CHUNK: + case MOZ_GTK_PROGRESS_CHUNK_INDETERMINATE: + case MOZ_GTK_PROGRESS_CHUNK_VERTICAL_INDETERMINATE: + return moz_gtk_progress_chunk_paint(cr, rect, cliprect, + direction, widget); + break; + case MOZ_GTK_TAB: + return moz_gtk_tab_paint(cr, rect, cliprect, state, + (GtkTabFlags) flags, direction); + break; + case MOZ_GTK_TABPANELS: + return moz_gtk_tabpanels_paint(cr, rect, cliprect, direction); + break; + case MOZ_GTK_TAB_SCROLLARROW: + return moz_gtk_tab_scroll_arrow_paint(cr, rect, cliprect, state, + (GtkArrowType) flags, direction); + break; + case MOZ_GTK_MENUBAR: + return moz_gtk_menu_bar_paint(cr, rect, cliprect, direction); + break; + case MOZ_GTK_MENUPOPUP: + return moz_gtk_menu_popup_paint(cr, rect, cliprect, direction); + break; + case MOZ_GTK_MENUSEPARATOR: + return moz_gtk_menu_separator_paint(cr, rect, cliprect, + direction); + break; + case MOZ_GTK_MENUITEM: + return moz_gtk_menu_item_paint(cr, rect, cliprect, state, flags, + direction); + break; + case MOZ_GTK_MENUARROW: + return moz_gtk_menu_arrow_paint(cr, rect, cliprect, state, + direction); + break; + case MOZ_GTK_TOOLBARBUTTON_ARROW: + return moz_gtk_arrow_paint(cr, rect, cliprect, state, + (GtkArrowType) flags, direction); + break; + case MOZ_GTK_CHECKMENUITEM: + case MOZ_GTK_RADIOMENUITEM: + return moz_gtk_check_menu_item_paint(cr, rect, cliprect, state, + (gboolean) flags, + (widget == MOZ_GTK_RADIOMENUITEM), + direction); + break; + case MOZ_GTK_SPLITTER_HORIZONTAL: + return moz_gtk_vpaned_paint(cr, rect, cliprect, state); + break; + case MOZ_GTK_SPLITTER_VERTICAL: + return moz_gtk_hpaned_paint(cr, rect, cliprect, state); + break; + case MOZ_GTK_WINDOW: + return moz_gtk_window_paint(cr, rect, cliprect, direction); + break; + default: + g_warning("Unknown widget type: %d", widget); + } + + return MOZ_GTK_UNKNOWN_WIDGET; +} + +GtkWidget* moz_gtk_get_scrollbar_widget(void) +{ + NS_ASSERTION(is_initialized, "Forgot to call moz_gtk_init()"); + ensure_scrollbar_widget(); + return gHorizScrollbarWidget; +} + +gint +moz_gtk_shutdown() +{ + GtkWidgetClass *entry_class; + + if (gTooltipWidget) + gtk_widget_destroy(gTooltipWidget); + /* This will destroy all of our widgets */ + if (gProtoWindow) + gtk_widget_destroy(gProtoWindow); + + gProtoWindow = NULL; + gProtoLayout = NULL; + gButtonWidget = NULL; + gToggleButtonWidget = NULL; + gButtonArrowWidget = NULL; + gCheckboxWidget = NULL; + gRadiobuttonWidget = NULL; + gHorizScrollbarWidget = NULL; + gVertScrollbarWidget = NULL; + gSpinWidget = NULL; + gHScaleWidget = NULL; + gVScaleWidget = NULL; + gEntryWidget = NULL; + gComboBoxWidget = NULL; + gComboBoxButtonWidget = NULL; + gComboBoxSeparatorWidget = NULL; + gComboBoxArrowWidget = NULL; + gComboBoxEntryWidget = NULL; + gComboBoxEntryButtonWidget = NULL; + gComboBoxEntryArrowWidget = NULL; + gComboBoxEntryTextareaWidget = NULL; + gHandleBoxWidget = NULL; + gToolbarWidget = NULL; + gStatusbarWidget = NULL; + gFrameWidget = NULL; + gProgressWidget = NULL; + gTabWidget = NULL; + gTooltipWidget = NULL; + gMenuBarWidget = NULL; + gMenuBarItemWidget = NULL; + gMenuPopupWidget = NULL; + gMenuItemWidget = NULL; + gImageMenuItemWidget = NULL; + gCheckMenuItemWidget = NULL; + gTreeViewWidget = NULL; + gMiddleTreeViewColumn = NULL; + gTreeHeaderCellWidget = NULL; + gTreeHeaderSortArrowWidget = NULL; + gExpanderWidget = NULL; + gToolbarSeparatorWidget = NULL; + gMenuSeparatorWidget = NULL; + gHPanedWidget = NULL; + gVPanedWidget = NULL; + gScrolledWindowWidget = NULL; + + entry_class = g_type_class_peek(GTK_TYPE_ENTRY); + g_type_class_unref(entry_class); + + is_initialized = FALSE; + + return MOZ_GTK_SUCCESS; +} diff --git a/widget/gtk2/gtkdrawing.h b/widget/gtk2/gtkdrawing.h index f81752a0c443..346ab5875fb3 100644 --- a/widget/gtk2/gtkdrawing.h +++ b/widget/gtk2/gtkdrawing.h @@ -246,12 +246,15 @@ gint moz_gtk_enable_style_props(style_prop_t styleGetProp); */ gint moz_gtk_shutdown(); +#if defined(MOZ_WIDGET_GTK2) /** * Retrieves the colormap to use for drawables passed to moz_gtk_widget_paint. */ GdkColormap* moz_gtk_widget_get_colormap(); +#endif /*** Widget drawing ***/ +#if defined(MOZ_WIDGET_GTK2) /** * Paint a widget in the current theme. * widget: a constant giving the widget to paint @@ -268,6 +271,13 @@ moz_gtk_widget_paint(GtkThemeWidgetType widget, GdkDrawable* drawable, GdkRectangle* rect, GdkRectangle* cliprect, GtkWidgetState* state, gint flags, GtkTextDirection direction); +#else +gint +moz_gtk_widget_paint(GtkThemeWidgetType widget, cairo_t *cr, + GdkRectangle* rect, GdkRectangle* cliprect, + GtkWidgetState* state, gint flags, + GtkTextDirection direction); +#endif /*** Widget metrics ***/ From 47cdc25a033d3fed64e85844f7bcfa225c867f9a Mon Sep 17 00:00:00 2001 From: Josh Aas Date: Fri, 10 Feb 2012 08:39:40 -0500 Subject: [PATCH 12/34] Bug 723217: Fix click-to-play support for plugins on Android. r=snorp --- content/base/src/nsObjectLoadingContent.cpp | 68 +++++++++------------ content/base/src/nsObjectLoadingContent.h | 14 ++--- dom/plugins/base/nsPluginHost.cpp | 25 ++------ dom/plugins/base/nsPluginHost.h | 5 +- layout/build/nsContentDLF.cpp | 2 +- 5 files changed, 42 insertions(+), 72 deletions(-) diff --git a/content/base/src/nsObjectLoadingContent.cpp b/content/base/src/nsObjectLoadingContent.cpp index a951bf776422..0dcd53ac1bf7 100644 --- a/content/base/src/nsObjectLoadingContent.cpp +++ b/content/base/src/nsObjectLoadingContent.cpp @@ -484,16 +484,18 @@ IsSupportedImage(const nsCString& aMimeType) return NS_SUCCEEDED(rv) && supported; } -static bool -IsSupportedPlugin(const nsCString& aMIMEType, bool aShouldPlay) +nsresult nsObjectLoadingContent::IsPluginEnabledForType(const nsCString& aMIMEType) { + if (!mShouldPlay) { + return NS_ERROR_PLUGIN_CLICKTOPLAY; + } + nsCOMPtr pluginHostCOM(do_GetService(MOZ_PLUGIN_HOST_CONTRACTID)); nsPluginHost *pluginHost = static_cast(pluginHostCOM.get()); if (!pluginHost) { return false; } - nsresult rv = pluginHost->IsPluginEnabledForType(aMIMEType.get(), aShouldPlay); - return NS_SUCCEEDED(rv); + return pluginHost->IsPluginEnabledForType(aMIMEType.get()); } static void @@ -517,9 +519,12 @@ GetExtensionFromURI(nsIURI* uri, nsCString& ext) * Checks whether a plugin exists and is enabled for the extension * in the given URI. The MIME type is returned in the mimeType out parameter. */ -static bool -IsPluginEnabledByExtension(nsIURI* uri, nsCString& mimeType, bool aShouldPlay) +bool nsObjectLoadingContent::IsPluginEnabledByExtension(nsIURI* uri, nsCString& mimeType) { + if (!mShouldPlay) { + return false; + } + nsCAutoString ext; GetExtensionFromURI(uri, ext); @@ -534,8 +539,7 @@ IsPluginEnabledByExtension(nsIURI* uri, nsCString& mimeType, bool aShouldPlay) } const char* typeFromExt; - if (NS_SUCCEEDED(pluginHost->IsPluginEnabledForExtension(ext.get(), typeFromExt, - aShouldPlay))) { + if (NS_SUCCEEDED(pluginHost->IsPluginEnabledForExtension(ext.get(), typeFromExt))) { mimeType = typeFromExt; return true; } @@ -568,6 +572,10 @@ nsObjectLoadingContent::~nsObjectLoadingContent() nsresult nsObjectLoadingContent::InstantiatePluginInstance(const char* aMimeType, nsIURI* aURI) { + if (!mShouldPlay) { + return NS_ERROR_PLUGIN_CLICKTOPLAY; + } + // Don't do anything if we already have an active instance. if (mInstanceOwner) { return NS_OK; @@ -586,11 +594,6 @@ nsObjectLoadingContent::InstantiatePluginInstance(const char* aMimeType, nsIURI* nsCOMPtr kungFuDeathGrip = this; nsCOMPtr thisContent = do_QueryInterface(static_cast(this)); - nsCString typeToUse(aMimeType); - if (typeToUse.IsEmpty() && aURI) { - IsPluginEnabledByExtension(aURI, typeToUse, mShouldPlay); - } - nsCOMPtr baseURI; if (!aURI) { // We need some URI. If we have nothing else, use the base URI. @@ -730,10 +733,10 @@ nsObjectLoadingContent::OnStartRequest(nsIRequest *aRequest, if ((channelType.EqualsASCII(APPLICATION_OCTET_STREAM) && !mContentType.IsEmpty() && GetTypeOfContent(mContentType) != eType_Document) || - // Need to check IsSupportedPlugin() in addition to GetTypeOfContent() + // Need to check IsPluginEnabledForType() in addition to GetTypeOfContent() // because otherwise the default plug-in's catch-all behavior would // confuse things. - (IsSupportedPlugin(mContentType, mShouldPlay) && + (NS_SUCCEEDED(IsPluginEnabledForType(mContentType)) && GetTypeOfContent(mContentType) == eType_Plugin)) { // Set the type we'll use for dispatch on the channel. Otherwise we could // end up trying to dispatch to a nsFrameLoader, which will complain that @@ -752,7 +755,7 @@ nsObjectLoadingContent::OnStartRequest(nsIRequest *aRequest, if (mContentType.EqualsASCII(APPLICATION_OCTET_STREAM)) { nsCAutoString extType; - if (IsPluginEnabledByExtension(uri, extType, mShouldPlay)) { + if (IsPluginEnabledByExtension(uri, extType)) { mContentType = extType; chan->SetContentType(extType); } @@ -1297,8 +1300,8 @@ nsObjectLoadingContent::LoadObject(nsIURI* aURI, nsCAutoString overrideType; if ((caps & eOverrideServerType) && - ((!aTypeHint.IsEmpty() && IsSupportedPlugin(aTypeHint, mShouldPlay)) || - (aURI && IsPluginEnabledByExtension(aURI, overrideType, mShouldPlay)))) { + ((!aTypeHint.IsEmpty() && NS_SUCCEEDED(IsPluginEnabledForType(aTypeHint))) || + (aURI && IsPluginEnabledByExtension(aURI, overrideType)))) { ObjectType newType; if (overrideType.IsEmpty()) { newType = GetTypeOfContent(aTypeHint); @@ -1434,7 +1437,7 @@ nsObjectLoadingContent::LoadObject(nsIURI* aURI, return NS_OK; } - if (IsSupportedPlugin(aTypeHint, mShouldPlay)) { + if (NS_SUCCEEDED(IsPluginEnabledForType(aTypeHint))) { mType = eType_Plugin; } else { rv = NS_ERROR_NOT_AVAILABLE; @@ -1744,7 +1747,7 @@ nsObjectLoadingContent::GetTypeOfContent(const nsCString& aMIMEType) return eType_Document; } - if ((caps & eSupportPlugins) && IsSupportedPlugin(aMIMEType, mShouldPlay)) { + if ((caps & eSupportPlugins) && NS_SUCCEEDED(IsPluginEnabledForType(aMIMEType))) { return eType_Plugin; } @@ -1755,16 +1758,10 @@ nsresult nsObjectLoadingContent::TypeForClassID(const nsAString& aClassID, nsACString& aType) { - nsCOMPtr pluginHostCOM(do_GetService(MOZ_PLUGIN_HOST_CONTRACTID)); - nsPluginHost *pluginHost = static_cast(pluginHostCOM.get()); - if (!pluginHost) { - return NS_ERROR_NOT_AVAILABLE; - } - if (StringBeginsWith(aClassID, NS_LITERAL_STRING("java:"))) { // Supported if we have a java plugin aType.AssignLiteral("application/x-java-vm"); - nsresult rv = pluginHost->IsPluginEnabledForType("application/x-java-vm"); + nsresult rv = IsPluginEnabledForType(NS_LITERAL_CSTRING("application/x-java-vm")); return NS_SUCCEEDED(rv) ? NS_OK : NS_ERROR_NOT_AVAILABLE; } @@ -1772,11 +1769,11 @@ nsObjectLoadingContent::TypeForClassID(const nsAString& aClassID, if (StringBeginsWith(aClassID, NS_LITERAL_STRING("clsid:"), nsCaseInsensitiveStringComparator())) { // Check if we have a plugin for that - if (NS_SUCCEEDED(pluginHost->IsPluginEnabledForType("application/x-oleobject"))) { + if (NS_SUCCEEDED(IsPluginEnabledForType(NS_LITERAL_CSTRING("application/x-oleobject")))) { aType.AssignLiteral("application/x-oleobject"); return NS_OK; } - if (NS_SUCCEEDED(pluginHost->IsPluginEnabledForType("application/oleobject"))) { + if (NS_SUCCEEDED(IsPluginEnabledForType(NS_LITERAL_CSTRING("application/oleobject")))) { aType.AssignLiteral("application/oleobject"); return NS_OK; } @@ -1832,7 +1829,7 @@ nsObjectLoadingContent::HandleBeingBlockedByContentPolicy(nsresult aStatus, } } -/* static */ PluginSupportState +PluginSupportState nsObjectLoadingContent::GetPluginSupportState(nsIContent* aContent, const nsCString& aContentType) { @@ -1866,16 +1863,10 @@ nsObjectLoadingContent::GetPluginSupportState(nsIContent* aContent, GetPluginDisabledState(aContentType); } -/* static */ PluginSupportState +PluginSupportState nsObjectLoadingContent::GetPluginDisabledState(const nsCString& aContentType) { - nsCOMPtr pluginHostCOM(do_GetService(MOZ_PLUGIN_HOST_CONTRACTID)); - nsPluginHost *pluginHost = static_cast(pluginHostCOM.get()); - if (!pluginHost) { - return ePluginUnsupported; - } - - nsresult rv = pluginHost->IsPluginEnabledForType(aContentType.get()); + nsresult rv = IsPluginEnabledForType(aContentType); if (rv == NS_ERROR_PLUGIN_DISABLED) return ePluginDisabled; if (rv == NS_ERROR_PLUGIN_CLICKTOPLAY) @@ -2117,6 +2108,7 @@ nsObjectLoadingContent::PlayPlugin() if (!nsContentUtils::IsCallerChrome()) return NS_OK; + mSrcStreamLoadInitiated = false; mShouldPlay = true; return LoadObject(mURI, true, mContentType, true); } diff --git a/content/base/src/nsObjectLoadingContent.h b/content/base/src/nsObjectLoadingContent.h index 3d92646864c6..bfa394b82aab 100644 --- a/content/base/src/nsObjectLoadingContent.h +++ b/content/base/src/nsObjectLoadingContent.h @@ -328,9 +328,7 @@ class nsObjectLoadingContent : public nsImageLoadingContent * * This should only be called if the type of this content is eType_Null. */ - static PluginSupportState - GetPluginSupportState(nsIContent* aContent, - const nsCString& aContentType); + PluginSupportState GetPluginSupportState(nsIContent* aContent, const nsCString& aContentType); /** * If the plugin for aContentType is disabled, return ePluginDisabled. @@ -339,17 +337,17 @@ class nsObjectLoadingContent : public nsImageLoadingContent * * This should only be called if the type of this content is eType_Null. */ - static PluginSupportState - GetPluginDisabledState(const nsCString& aContentType); + PluginSupportState GetPluginDisabledState(const nsCString& aContentType); /** * When there is no usable plugin available this will send UI events and * update the AutoFallback object appropriate to the reason for there being * no plugin available. */ - static void - UpdateFallbackState(nsIContent* aContent, AutoFallback& fallback, - const nsCString& aTypeHint); + void UpdateFallbackState(nsIContent* aContent, AutoFallback& fallback, const nsCString& aTypeHint); + + nsresult IsPluginEnabledForType(const nsCString& aMIMEType); + bool IsPluginEnabledByExtension(nsIURI* uri, nsCString& mimeType); /** * The final listener to ship the data to (imagelib, uriloader, etc) diff --git a/dom/plugins/base/nsPluginHost.cpp b/dom/plugins/base/nsPluginHost.cpp index 1f6437830531..eeefca0e6902 100644 --- a/dom/plugins/base/nsPluginHost.cpp +++ b/dom/plugins/base/nsPluginHost.cpp @@ -1367,18 +1367,10 @@ nsPluginHost::TrySetUpPluginInstance(const char *aMimeType, nsresult nsPluginHost::IsPluginEnabledForType(const char* aMimeType) -{ - // If plugins.click_to_play is false, plugins should always play - return IsPluginEnabledForType(aMimeType, - !Preferences::GetBool("plugins.click_to_play", false)); -} - -nsresult -nsPluginHost::IsPluginEnabledForType(const char* aMimeType, bool aShouldPlay) { nsPluginTag *plugin = FindPluginForType(aMimeType, true); if (plugin) - return aShouldPlay ? NS_OK : NS_ERROR_PLUGIN_CLICKTOPLAY; + return NS_OK; // Pass false as the second arg so we can return NS_ERROR_PLUGIN_DISABLED // for disabled plug-ins. @@ -1393,7 +1385,7 @@ nsPluginHost::IsPluginEnabledForType(const char* aMimeType, bool aShouldPlay) return NS_ERROR_PLUGIN_DISABLED; } - return aShouldPlay ? NS_OK : NS_ERROR_PLUGIN_CLICKTOPLAY; + return NS_OK; } // check comma delimitered extensions @@ -1421,22 +1413,13 @@ static int CompareExtensions(const char *aExtensionList, const char *aExtension) return PL_strcasecmp(pExt, aExtension); } -nsresult -nsPluginHost::IsPluginEnabledForExtension(const char* aExtension, const char* &aMimeType) -{ - // If plugins.click_to_play is false, plugins should always play - return IsPluginEnabledForExtension(aExtension, aMimeType, - !Preferences::GetBool("plugins.click_to_play", false)); -} - nsresult nsPluginHost::IsPluginEnabledForExtension(const char* aExtension, - const char* &aMimeType, - bool aShouldPlay) + const char* &aMimeType) { nsPluginTag *plugin = FindPluginEnabledForExtension(aExtension, aMimeType); if (plugin) - return aShouldPlay ? NS_OK : NS_ERROR_PLUGIN_CLICKTOPLAY; + return NS_OK; return NS_ERROR_FAILURE; } diff --git a/dom/plugins/base/nsPluginHost.h b/dom/plugins/base/nsPluginHost.h index d4bf57b78e47..4e1d19fba1ae 100644 --- a/dom/plugins/base/nsPluginHost.h +++ b/dom/plugins/base/nsPluginHost.h @@ -120,11 +120,8 @@ public: nsIURI *aURL, nsIPluginInstanceOwner *aOwner); nsresult IsPluginEnabledForType(const char* aMimeType); - nsresult IsPluginEnabledForType(const char* aMimeType, - bool aShouldPlay); nsresult IsPluginEnabledForExtension(const char* aExtension, const char* &aMimeType); - nsresult IsPluginEnabledForExtension(const char* aExtension, const char* &aMimeType, - bool aShouldPlay); + nsresult GetPluginCount(PRUint32* aPluginCount); nsresult GetPlugins(PRUint32 aPluginCount, nsIDOMPlugin** aPluginArray); diff --git a/layout/build/nsContentDLF.cpp b/layout/build/nsContentDLF.cpp index b88818ee8538..1e25531a130d 100644 --- a/layout/build/nsContentDLF.cpp +++ b/layout/build/nsContentDLF.cpp @@ -310,7 +310,7 @@ nsContentDLF::CreateInstance(const char* aCommand, nsCOMPtr pluginHostCOM(do_GetService(MOZ_PLUGIN_HOST_CONTRACTID)); nsPluginHost *pluginHost = static_cast(pluginHostCOM.get()); if(pluginHost && - NS_SUCCEEDED(pluginHost->IsPluginEnabledForType(aContentType, true))) { + NS_SUCCEEDED(pluginHost->IsPluginEnabledForType(aContentType))) { return CreateDocument(aCommand, aChannel, aLoadGroup, aContainer, kPluginDocumentCID, From 026a9927ea11e2b7c3226f949b19e6d36394dbfe Mon Sep 17 00:00:00 2001 From: Mark Finkle Date: Fri, 10 Feb 2012 09:44:06 -0500 Subject: [PATCH 13/34] Bug 702281 - Telemetry prompt on mobile should be tri-state r=bnicholson --- mobile/android/chrome/content/browser.js | 31 +++++++++++++++++------- 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/mobile/android/chrome/content/browser.js b/mobile/android/chrome/content/browser.js index 574ca985a996..61ecae478b83 100644 --- a/mobile/android/chrome/content/browser.js +++ b/mobile/android/chrome/content/browser.js @@ -353,29 +353,43 @@ var BrowserApp = { }, _showTelemetryPrompt: function _showTelemetryPrompt() { - let telemetryPrompted = false; + const PREF_TELEMETRY_PROMPTED = "toolkit.telemetry.prompted"; + const PREF_TELEMETRY_ENABLED = "toolkit.telemetry.enabled"; + const PREF_TELEMETRY_REJECTED = "toolkit.telemetry.rejected"; + + // This is used to reprompt users when privacy message changes + const TELEMETRY_PROMPT_REV = 2; + + let telemetryPrompted = null; try { - telemetryPrompted = Services.prefs.getBoolPref("toolkit.telemetry.prompted"); + telemetryPrompted = Services.prefs.getIntPref(PREF_TELEMETRY_PROMPTED); } catch (e) { /* Optional */ } - if (telemetryPrompted) + + // If the user has seen the latest telemetry prompt, do not prompt again + // else clear old prefs and reprompt + if (telemetryPrompted === TELEMETRY_PROMPT_REV) return; + Services.prefs.clearUserPref(PREF_TELEMETRY_PROMPTED); + Services.prefs.clearUserPref(PREF_TELEMETRY_ENABLED); + let buttons = [ { label: Strings.browser.GetStringFromName("telemetry.optin.yes"), callback: function () { - Services.prefs.setBoolPref("toolkit.telemetry.prompted", true); - Services.prefs.setBoolPref("toolkit.telemetry.enabled", true); + Services.prefs.setIntPref(PREF_TELEMETRY_PROMPTED, TELEMETRY_PROMPT_REV); + Services.prefs.setBoolPref(PREF_TELEMETRY_ENABLED, true); } }, { label: Strings.browser.GetStringFromName("telemetry.optin.no"), callback: function () { - Services.prefs.setBoolPref("toolkit.telemetry.prompted", true); - Services.prefs.setBoolPref("toolkit.telemetry.enabled", false); + Services.prefs.setIntPref(PREF_TELEMETRY_PROMPTED, TELEMETRY_PROMPT_REV); + Services.prefs.setBoolPref(PREF_TELEMETRY_REJECTED, true); } } ]; + let brandShortName = Strings.brand.GetStringFromName("brandShortName"); let message = Strings.browser.formatStringFromName("telemetry.optin.message", [brandShortName], 1); NativeWindow.doorhanger.show(message, "telemetry-optin", buttons); @@ -4165,7 +4179,6 @@ var CharacterEncoding = { let docCharset = browser.docShell.QueryInterface(Ci.nsIDocCharset); docCharset.charset = aEncoding; browser.reload(Ci.nsIWebNavigation.LOAD_FLAGS_CHARSET_CHANGE); - }, - + } }; From 820b159a4b72f252ae1a47f7732b462ab180b876 Mon Sep 17 00:00:00 2001 From: Mark Finkle Date: Fri, 10 Feb 2012 09:44:06 -0500 Subject: [PATCH 14/34] Bug 725787 - Robotium: loadUrl should be callable more than one time r=gbrown --- mobile/android/base/tests/BaseTest.java.in | 2 -- mobile/android/base/tests/testAwesomebar.java.in | 2 ++ mobile/android/base/tests/testAxisLocking.java.in | 2 ++ mobile/android/base/tests/testBookmark.java.in | 3 +++ mobile/android/base/tests/testCheck.java.in | 3 +++ mobile/android/base/tests/testFlingCorrectness.java.in | 2 ++ mobile/android/base/tests/testLoad.java.in | 2 ++ mobile/android/base/tests/testOverscroll.java.in | 2 ++ mobile/android/base/tests/testPan.java.in | 2 ++ mobile/android/base/tests/testPanCorrectness.java.in | 2 ++ mobile/android/base/tests/test_bug720538.java.in | 2 ++ 11 files changed, 22 insertions(+), 2 deletions(-) diff --git a/mobile/android/base/tests/BaseTest.java.in b/mobile/android/base/tests/BaseTest.java.in index 483c0cc07fec..bf6976bc939c 100644 --- a/mobile/android/base/tests/BaseTest.java.in +++ b/mobile/android/base/tests/BaseTest.java.in @@ -104,8 +104,6 @@ abstract class BaseTest extends ActivityInstrumentationTestCase2 { } protected final void enterUrl(String url) { - mActions.expectGeckoEvent("Gecko:Ready").blockForEvent(); - Activity awesomeBarActivity = clickOnAwesomeBar(); Element urlbar = mDriver.findElement(awesomeBarActivity, "awesomebar_text"); mActions.sendKeys(url); diff --git a/mobile/android/base/tests/testAwesomebar.java.in b/mobile/android/base/tests/testAwesomebar.java.in index 6754194d84c0..26726cd4694b 100644 --- a/mobile/android/base/tests/testAwesomebar.java.in +++ b/mobile/android/base/tests/testAwesomebar.java.in @@ -7,6 +7,8 @@ public class testAwesomebar extends BaseTest { public void testAwesomebar() { setTestType("mochitest"); + mActions.expectGeckoEvent("Gecko:Ready").blockForEvent(); + String url = getAbsoluteUrl("/robocop/robocop_blank_01.html"); loadUrl(url); diff --git a/mobile/android/base/tests/testAxisLocking.java.in b/mobile/android/base/tests/testAxisLocking.java.in index 9b37528aed52..cf1ddc61453a 100644 --- a/mobile/android/base/tests/testAxisLocking.java.in +++ b/mobile/android/base/tests/testAxisLocking.java.in @@ -19,6 +19,8 @@ public class testAxisLocking extends PixelTest { MotionEventHelper meh = new MotionEventHelper(getInstrumentation(), mDriver.getGeckoLeft(), mDriver.getGeckoTop()); + mActions.expectGeckoEvent("Gecko:Ready").blockForEvent(); + // load page and check we're at 0,0 loadAndVerifyBoxes(url); diff --git a/mobile/android/base/tests/testBookmark.java.in b/mobile/android/base/tests/testBookmark.java.in index fa6459f41271..f2539b4c38b7 100644 --- a/mobile/android/base/tests/testBookmark.java.in +++ b/mobile/android/base/tests/testBookmark.java.in @@ -12,6 +12,9 @@ public class testBookmark extends BaseTest { public void testBookmark() { setTestType("mochitest"); + + mActions.expectGeckoEvent("Gecko:Ready").blockForEvent(); + String url = getAbsoluteUrl("/robocop/robocop_blank_02.html"); enterUrl(url); diff --git a/mobile/android/base/tests/testCheck.java.in b/mobile/android/base/tests/testCheck.java.in index 157955980a1d..60494c03ab91 100644 --- a/mobile/android/base/tests/testCheck.java.in +++ b/mobile/android/base/tests/testCheck.java.in @@ -15,6 +15,9 @@ public class testCheck extends PixelTest { public void testCheck() { setTestType("talos"); String url = getAbsoluteUrl("/startup_test/fennecmark/wikipedia.html"); + + mActions.expectGeckoEvent("Gecko:Ready").blockForEvent(); + loadAndPaint(url); mDriver.setupScrollHandling(); diff --git a/mobile/android/base/tests/testFlingCorrectness.java.in b/mobile/android/base/tests/testFlingCorrectness.java.in index 3dbe8ab49fd4..5d2ff67eb65d 100644 --- a/mobile/android/base/tests/testFlingCorrectness.java.in +++ b/mobile/android/base/tests/testFlingCorrectness.java.in @@ -17,6 +17,8 @@ public class testFlingCorrectness extends PixelTest { MotionEventHelper meh = new MotionEventHelper(getInstrumentation(), mDriver.getGeckoLeft(), mDriver.getGeckoTop()); + mActions.expectGeckoEvent("Gecko:Ready").blockForEvent(); + // load page and check we're at 0,0 loadAndVerifyBoxes(url); diff --git a/mobile/android/base/tests/testLoad.java.in b/mobile/android/base/tests/testLoad.java.in index 6c77e010c3fe..e4f34edc7d32 100644 --- a/mobile/android/base/tests/testLoad.java.in +++ b/mobile/android/base/tests/testLoad.java.in @@ -14,6 +14,8 @@ public class testLoad extends PixelTest { setTestType("mochitest"); String url = getAbsoluteUrl("/robocop/robocop_boxes.html"); + mActions.expectGeckoEvent("Gecko:Ready").blockForEvent(); + loadAndVerifyBoxes(url); verifyUrl(url); diff --git a/mobile/android/base/tests/testOverscroll.java.in b/mobile/android/base/tests/testOverscroll.java.in index 885a229df175..205d06531b88 100644 --- a/mobile/android/base/tests/testOverscroll.java.in +++ b/mobile/android/base/tests/testOverscroll.java.in @@ -17,6 +17,8 @@ public class testOverscroll extends PixelTest { MotionEventHelper meh = new MotionEventHelper(getInstrumentation(), mDriver.getGeckoLeft(), mDriver.getGeckoTop()); + mActions.expectGeckoEvent("Gecko:Ready").blockForEvent(); + // load page and check we're at 0,0 loadAndVerifyBoxes(url); diff --git a/mobile/android/base/tests/testPan.java.in b/mobile/android/base/tests/testPan.java.in index e2b2a8586bd8..79e6a9098af8 100644 --- a/mobile/android/base/tests/testPan.java.in +++ b/mobile/android/base/tests/testPan.java.in @@ -14,6 +14,8 @@ public class testPan extends PixelTest { setTestType("talos"); String url = getAbsoluteUrl("/startup_test/fennecmark/wikipedia.html"); + mActions.expectGeckoEvent("Gecko:Ready").blockForEvent(); + loadAndPaint(url); mDriver.setupScrollHandling(); diff --git a/mobile/android/base/tests/testPanCorrectness.java.in b/mobile/android/base/tests/testPanCorrectness.java.in index 42505f0778dd..131c82c45084 100644 --- a/mobile/android/base/tests/testPanCorrectness.java.in +++ b/mobile/android/base/tests/testPanCorrectness.java.in @@ -17,6 +17,8 @@ public class testPanCorrectness extends PixelTest { MotionEventHelper meh = new MotionEventHelper(getInstrumentation(), mDriver.getGeckoLeft(), mDriver.getGeckoTop()); + mActions.expectGeckoEvent("Gecko:Ready").blockForEvent(); + // load page and check we're at 0,0 loadAndVerifyBoxes(url); diff --git a/mobile/android/base/tests/test_bug720538.java.in b/mobile/android/base/tests/test_bug720538.java.in index 5b970aba1f66..59019a03d7be 100644 --- a/mobile/android/base/tests/test_bug720538.java.in +++ b/mobile/android/base/tests/test_bug720538.java.in @@ -9,6 +9,8 @@ public class test_bug720538 extends PixelTest { setTestType("mochitest"); String url = getAbsoluteUrl("/robocop/test_bug720538.html"); + mActions.expectGeckoEvent("Gecko:Ready").blockForEvent(); + /* * for this test, we load the associated test_bug720538.html file. this file has two * iframes (painted completely blue - #0000FF) and the rest of the page is the background From 72ed3d882d55b4e03e95db68975da61b6dfb31e0 Mon Sep 17 00:00:00 2001 From: Aryeh Gregor Date: Wed, 8 Feb 2012 14:36:16 -0500 Subject: [PATCH 15/34] Bug 725426 - Incorrect getBoundingClientRect() for transform-style: flat. r=roc --- layout/base/nsLayoutUtils.cpp | 3 +++ layout/base/tests/Makefile.in | 1 + layout/base/tests/test_bug725426.html | 23 +++++++++++++++++++++++ 3 files changed, 27 insertions(+) create mode 100644 layout/base/tests/test_bug725426.html diff --git a/layout/base/nsLayoutUtils.cpp b/layout/base/nsLayoutUtils.cpp index 384458b20c4d..cf6670d18ad0 100644 --- a/layout/base/nsLayoutUtils.cpp +++ b/layout/base/nsLayoutUtils.cpp @@ -1218,6 +1218,9 @@ nsLayoutUtils::GetTransformToAncestor(nsIFrame *aFrame, nsIFrame *aAncestor) nsIFrame* parent; gfx3DMatrix ctm = aFrame->GetTransformMatrix(aAncestor, &parent); while (parent && parent != aAncestor) { + if (!parent->Preserves3DChildren()) { + ctm.ProjectTo2D(); + } ctm = ctm * parent->GetTransformMatrix(aAncestor, &parent); } return ctm; diff --git a/layout/base/tests/Makefile.in b/layout/base/tests/Makefile.in index d99c96562bd2..4f4ed0fd20b3 100644 --- a/layout/base/tests/Makefile.in +++ b/layout/base/tests/Makefile.in @@ -183,6 +183,7 @@ _TEST_FILES = \ test_bug646757.html \ test_bug718809.html \ test_font_inflation_reftests.html \ + test_bug725426.html \ $(NULL) # Tests for bugs 441782, 467672 and 570378 don't pass reliably on Windows, because of bug 469208 diff --git a/layout/base/tests/test_bug725426.html b/layout/base/tests/test_bug725426.html new file mode 100644 index 000000000000..f02030362741 --- /dev/null +++ b/layout/base/tests/test_bug725426.html @@ -0,0 +1,23 @@ + + +Test for bug 725426 + + + +
+
+
+ +Mozilla Bug 725426 +
+
+
From c2f12057d0711b809d6d78998bac72227381a765 Mon Sep 17 00:00:00 2001 From: Panagiotis Koutsourakis Date: Fri, 10 Feb 2012 16:06:37 +0100 Subject: [PATCH 16/34] Bug 716661 - Convert observers in nsDownloadManager to weak observers. r=mak Make nsDownloadManager inherit from nsSupportsWeakReference, expose the new interface, and change the last argument of the addObserver calls to true to signify that we are adding a weak observer. --- .../downloads/nsDownloadManager.cpp | 29 +++++++++---------- .../components/downloads/nsDownloadManager.h | 4 ++- 2 files changed, 16 insertions(+), 17 deletions(-) diff --git a/toolkit/components/downloads/nsDownloadManager.cpp b/toolkit/components/downloads/nsDownloadManager.cpp index 17c9dcb39993..cb1f1f6099f3 100644 --- a/toolkit/components/downloads/nsDownloadManager.cpp +++ b/toolkit/components/downloads/nsDownloadManager.cpp @@ -111,11 +111,12 @@ static const PRInt64 gUpdateInterval = 400 * PR_USEC_PER_MSEC; //////////////////////////////////////////////////////////////////////////////// //// nsDownloadManager -NS_IMPL_ISUPPORTS3( +NS_IMPL_ISUPPORTS4( nsDownloadManager , nsIDownloadManager , nsINavHistoryObserver , nsIObserver +, nsISupportsWeakReference ) nsDownloadManager *nsDownloadManager::gDownloadManagerService = nsnull; @@ -886,23 +887,19 @@ nsDownloadManager::Init() // completely initialized), but the observerservice would still keep a reference // to us and notify us about shutdown, which may cause crashes. // failure to add an observer is not critical - // - // These observers will be cleaned up automatically at app shutdown. We do - // not bother explicitly breaking the observers because we are a singleton - // that lives for the duration of the app. - (void)mObserverService->AddObserver(this, "quit-application", false); - (void)mObserverService->AddObserver(this, "quit-application-requested", false); - (void)mObserverService->AddObserver(this, "offline-requested", false); - (void)mObserverService->AddObserver(this, "sleep_notification", false); - (void)mObserverService->AddObserver(this, "wake_notification", false); - (void)mObserverService->AddObserver(this, "profile-before-change", false); - (void)mObserverService->AddObserver(this, NS_IOSERVICE_GOING_OFFLINE_TOPIC, false); - (void)mObserverService->AddObserver(this, NS_IOSERVICE_OFFLINE_STATUS_TOPIC, false); - (void)mObserverService->AddObserver(this, NS_PRIVATE_BROWSING_REQUEST_TOPIC, false); - (void)mObserverService->AddObserver(this, NS_PRIVATE_BROWSING_SWITCH_TOPIC, false); + (void)mObserverService->AddObserver(this, "quit-application", true); + (void)mObserverService->AddObserver(this, "quit-application-requested", true); + (void)mObserverService->AddObserver(this, "offline-requested", true); + (void)mObserverService->AddObserver(this, "sleep_notification", true); + (void)mObserverService->AddObserver(this, "wake_notification", true); + (void)mObserverService->AddObserver(this, "profile-before-change", true); + (void)mObserverService->AddObserver(this, NS_IOSERVICE_GOING_OFFLINE_TOPIC, true); + (void)mObserverService->AddObserver(this, NS_IOSERVICE_OFFLINE_STATUS_TOPIC, true); + (void)mObserverService->AddObserver(this, NS_PRIVATE_BROWSING_REQUEST_TOPIC, true); + (void)mObserverService->AddObserver(this, NS_PRIVATE_BROWSING_SWITCH_TOPIC, true); if (history) - (void)history->AddObserver(this, false); + (void)history->AddObserver(this, true); return NS_OK; } diff --git a/toolkit/components/downloads/nsDownloadManager.h b/toolkit/components/downloads/nsDownloadManager.h index 54312e400494..2750db9fd341 100644 --- a/toolkit/components/downloads/nsDownloadManager.h +++ b/toolkit/components/downloads/nsDownloadManager.h @@ -58,6 +58,7 @@ #include "nsIObserverService.h" #include "nsIStringBundle.h" #include "nsISupportsPrimitives.h" +#include "nsWeakReference.h" #include "nsITimer.h" #include "nsString.h" @@ -76,7 +77,8 @@ class nsDownload; class nsDownloadManager : public nsIDownloadManager, public nsINavHistoryObserver, - public nsIObserver + public nsIObserver, + public nsSupportsWeakReference { public: NS_DECL_ISUPPORTS From fc78edad0ae1bd15c7f7f5574d4e65afa74b7b06 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Str=C3=A1nsk=C3=BD?= Date: Fri, 10 Feb 2012 16:07:41 +0100 Subject: [PATCH 17/34] Bug 725655 - gcc 4.7 build failures (missing headers). r=benjamin --- ipc/chromium/src/base/file_util_linux.cc | 3 +++ ipc/chromium/src/base/message_pump_libevent.cc | 3 +++ ipc/chromium/src/base/time_posix.cc | 3 +++ 3 files changed, 9 insertions(+) diff --git a/ipc/chromium/src/base/file_util_linux.cc b/ipc/chromium/src/base/file_util_linux.cc index cca706f06f42..171e44f8ed10 100644 --- a/ipc/chromium/src/base/file_util_linux.cc +++ b/ipc/chromium/src/base/file_util_linux.cc @@ -5,6 +5,9 @@ #include "base/file_util.h" #include +#if defined(ANDROID) || defined(OS_POSIX) +#include +#endif #include #include diff --git a/ipc/chromium/src/base/message_pump_libevent.cc b/ipc/chromium/src/base/message_pump_libevent.cc index 6194f79da3fd..9f31dbbfbde9 100644 --- a/ipc/chromium/src/base/message_pump_libevent.cc +++ b/ipc/chromium/src/base/message_pump_libevent.cc @@ -6,6 +6,9 @@ #include #include +#if defined(ANDROID) || defined(OS_POSIX) +#include +#endif #include "eintr_wrapper.h" #include "base/logging.h" diff --git a/ipc/chromium/src/base/time_posix.cc b/ipc/chromium/src/base/time_posix.cc index 8d1a1d5c4987..abf2a56be920 100644 --- a/ipc/chromium/src/base/time_posix.cc +++ b/ipc/chromium/src/base/time_posix.cc @@ -13,6 +13,9 @@ #else #include #endif +#if defined(ANDROID) || defined(OS_POSIX) +#include +#endif #include From 81ea428b0a1b8f3e9109f318aaceff975d37001d Mon Sep 17 00:00:00 2001 From: Matt Brubeck Date: Fri, 10 Feb 2012 07:40:41 -0800 Subject: [PATCH 18/34] Bug 724795 - Update the add-on list when a search engine is added or removed [r=mfinkle] --- .../android/chrome/content/aboutAddons.xhtml | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/mobile/android/chrome/content/aboutAddons.xhtml b/mobile/android/chrome/content/aboutAddons.xhtml index 5ad6e6dac29b..613dffb223b6 100644 --- a/mobile/android/chrome/content/aboutAddons.xhtml +++ b/mobile/android/chrome/content/aboutAddons.xhtml @@ -140,12 +140,14 @@ function init() { window.addEventListener("popstate", onPopState, false); + Services.obs.addObserver(Addons, "browser-search-engine-modified", false); AddonManager.addInstallListener(Addons); Addons.getAddons(); } function uninit() { + Services.obs.removeObserver(Addons, "browser-search-engine-modified"); AddonManager.removeInstallListener(Addons); } @@ -490,8 +492,8 @@ // visible if the user later re-adds it (works around bug 341833) detailItem.addon.engine.hidden = false; Services.search.removeEngine(detailItem.addon.engine); - // the search-engine-modified observer in browser.js will take care of - // updating the list + // the search-engine-modified observer will take care of updating the list + history.back(); } else { detailItem.addon.uninstall(); let opType = this._getOpTypeForOperations(detailItem.addon.pendingOperations); @@ -554,6 +556,18 @@ element.setAttribute("opType", "needs-restart"); }, + observe: function observe(aSubject, aTopic, aData) { + if (aTopic == "browser-search-engine-modified") { + switch (aData) { + case "engine-added": + case "engine-removed": + case "engine-changed": + this.getAddons(); + break; + } + } + }, + onInstallFailed: function(aInstall) { }, From e0a3ced213cda408b90ce60683b5552d1563a618 Mon Sep 17 00:00:00 2001 From: Scott Johnson Date: Fri, 10 Feb 2012 11:06:23 -0600 Subject: [PATCH 19/34] Bug 718516: Replace call of FinishReflowWithAbsoluteFrames() with FinishAndStoreOverflow() for nsColumnSetFrame to prevent crash. [r=ehsan] --- layout/generic/nsColumnSetFrame.cpp | 6 +++++- layout/reftests/abs-pos/reftest.list | 4 +++- layout/reftests/bugs/reftest.list | 12 +++++++----- 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/layout/generic/nsColumnSetFrame.cpp b/layout/generic/nsColumnSetFrame.cpp index 7e29e1026269..a42caa865c35 100644 --- a/layout/generic/nsColumnSetFrame.cpp +++ b/layout/generic/nsColumnSetFrame.cpp @@ -1083,7 +1083,11 @@ nsColumnSetFrame::Reflow(nsPresContext* aPresContext, CheckInvalidateSizeChange(aDesiredSize); - FinishReflowWithAbsoluteFrames(aPresContext, aDesiredSize, aReflowState, aStatus); + // XXXjwir3: This call should be replaced with FinishWithAbsoluteFrames + // when bug 724978 is fixed and nsColumnSetFrame is a full absolute + // container. + FinishAndStoreOverflow(&aDesiredSize); + aDesiredSize.mCarriedOutBottomMargin = carriedOutBottomMargin; NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize); diff --git a/layout/reftests/abs-pos/reftest.list b/layout/reftests/abs-pos/reftest.list index 4795848faf94..c5285d44a92f 100644 --- a/layout/reftests/abs-pos/reftest.list +++ b/layout/reftests/abs-pos/reftest.list @@ -13,6 +13,8 @@ fails-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)&&!layersGPUAccelerated) == au == select-1-dynamic.html select-1-ref.html == select-2.html select-2-ref.html == select-3.html select-3-ref.html -== multi-column-1.html multi-column-1-ref.html + +# Fails due to bug 724978. Should be re-enabled once this is fixed. +fails == multi-column-1.html multi-column-1-ref.html == button-1.html button-1-ref.html == button-2.html button-2-ref.html diff --git a/layout/reftests/bugs/reftest.list b/layout/reftests/bugs/reftest.list index 5868dcee87a0..92886094b786 100644 --- a/layout/reftests/bugs/reftest.list +++ b/layout/reftests/bugs/reftest.list @@ -683,11 +683,13 @@ fails-if(Android) != 376532-3.html 376532-3-ref.html == 379316-1.html 379316-1-ref.html fails-if(Android) random-if(cocoaWidget) random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == 379316-2.html 379316-2-ref.html # bug 379786 == 379328-1.html 379328-1-ref.html -== 379349-1a.xhtml 379349-1-ref.xhtml -== 379349-1b.xhtml 379349-1-ref.xhtml -== 379349-1c.xhtml 379349-1-ref.xhtml -== 379349-2a.xhtml 379349-2-ref.xhtml -== 379349-2b.xhtml 379349-2-ref.xhtml +# The next set of reftests all fail until bug 724978 has been fixed, and the +# overflow container ability of nsColumnSetFrame is restored. +fails == 379349-1a.xhtml 379349-1-ref.xhtml +fails == 379349-1b.xhtml 379349-1-ref.xhtml +fails == 379349-1c.xhtml 379349-1-ref.xhtml +fails == 379349-2a.xhtml 379349-2-ref.xhtml +fails == 379349-2b.xhtml 379349-2-ref.xhtml == 379349-3a.xhtml 379349-3-ref.xhtml == 379349-3b.xhtml 379349-3-ref.xhtml == 379361-1.html 379361-1-ref.html From 03040ac2310e129680fec0e147342e0937cab8ae Mon Sep 17 00:00:00 2001 From: Andrzej Skalski Date: Sat, 11 Feb 2012 03:25:48 +0900 Subject: [PATCH 20/34] Bug 706134 - ARIA listitem shouldn't expose selectable state and pick up aria-selected and aria-checked, r=surkov --- accessible/src/base/nsARIAMap.cpp | 7 ++-- .../tests/mochitest/focus/test_takeFocus.html | 6 ++-- .../tests/mochitest/selectable/test_aria.html | 34 +++---------------- .../mochitest/test_aria_token_attrs.html | 22 ++++++------ 4 files changed, 21 insertions(+), 48 deletions(-) diff --git a/accessible/src/base/nsARIAMap.cpp b/accessible/src/base/nsARIAMap.cpp index f308c40298eb..d6bf7bcf897b 100644 --- a/accessible/src/base/nsARIAMap.cpp +++ b/accessible/src/base/nsARIAMap.cpp @@ -235,8 +235,7 @@ nsRoleMapEntry nsARIAMap::gWAIRoleMap[] = eNoValue, eNoAction, eNoLiveAttr, - states::READONLY, - eARIAMultiSelectable + states::READONLY }, { "listbox", @@ -256,9 +255,7 @@ nsRoleMapEntry nsARIAMap::gWAIRoleMap[] = eNoValue, eNoAction, // XXX: should depend on state, parent accessible eNoLiveAttr, - states::READONLY, - eARIASelectable, - eARIACheckedMixed + states::READONLY }, { "log", diff --git a/accessible/tests/mochitest/focus/test_takeFocus.html b/accessible/tests/mochitest/focus/test_takeFocus.html index 343968842024..157fc2434678 100644 --- a/accessible/tests/mochitest/focus/test_takeFocus.html +++ b/accessible/tests/mochitest/focus/test_takeFocus.html @@ -96,9 +96,9 @@ link
-
item1
-
item2
-
item3
+
item1
+
item2
+
item3
diff --git a/accessible/tests/mochitest/selectable/test_aria.html b/accessible/tests/mochitest/selectable/test_aria.html index 53dea07d9f1c..2b4db6f3ff41 100644 --- a/accessible/tests/mochitest/selectable/test_aria.html +++ b/accessible/tests/mochitest/selectable/test_aria.html @@ -36,25 +36,6 @@ function doTest() { - ////////////////////////////////////////////////////////////////////////// - // role="list" - - var id = "list1"; - ok(isAccessible(id, [nsIAccessibleSelectable]), - "No selectable accessible for " + id); - - testSelectableSelection(id, [ ]); - - var select = getAccessible(id, [nsIAccessibleSelectable]); - select.addChildToSelection(0); - testSelectableSelection(id, [ ]); - select.removeChildFromSelection(0); - testSelectableSelection(id, [ ]); - select.selectAllSelection(); - testSelectableSelection(id, [ ]); - select.clearSelection(); - testSelectableSelection(id, [ ]); - ////////////////////////////////////////////////////////////////////////// // role="listbox" @@ -82,7 +63,7 @@ testSelectableSelection(id, [ "listbox2_item1", "listbox2_item2" ]); select.clearSelection(); testSelectableSelection(id, [ ]); - + ////////////////////////////////////////////////////////////////////////// // role="grid" @@ -152,19 +133,14 @@
   
-
-
item1
-
item2
-
-
-
item1
-
item2
+
item1
+
item2
-
item1
-
item2
+
item1
+
item2
diff --git a/accessible/tests/mochitest/test_aria_token_attrs.html b/accessible/tests/mochitest/test_aria_token_attrs.html index 4dcf12ede616..7967b9c660fc 100644 --- a/accessible/tests/mochitest/test_aria_token_attrs.html +++ b/accessible/tests/mochitest/test_aria_token_attrs.html @@ -89,12 +89,12 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=452388 testStates("listbox_multiselectable_undefined", 0, 0, STATE_MULTISELECTABLE | STATE_EXTSELECTABLE); testStates("listbox_multiselectable_absent", 0, 0, STATE_MULTISELECTABLE | STATE_EXTSELECTABLE); - // test (listitem) checkable and checked states - testStates("listitem_checked_true", (STATE_CHECKABLE | STATE_CHECKED)); - testStates("listitem_checked_false", STATE_CHECKABLE, 0, STATE_CHECKED); - testStates("listitem_checked_empty", 0 , 0, STATE_CHECKABLE | STATE_CHECKED); - testStates("listitem_checked_undefined", 0, 0, STATE_CHECKABLE | STATE_CHECKED); - testStates("listitem_checked_absent", 0, 0, STATE_CHECKABLE | STATE_CHECKED); + // test (option) checkable and checked states + testStates("option_checked_true", (STATE_CHECKABLE | STATE_CHECKED)); + testStates("option_checked_false", STATE_CHECKABLE, 0, STATE_CHECKED); + testStates("option_checked_empty", 0 , 0, STATE_CHECKABLE | STATE_CHECKED); + testStates("option_checked_undefined", 0, 0, STATE_CHECKABLE | STATE_CHECKED); + testStates("option_checked_absent", 0, 0, STATE_CHECKABLE | STATE_CHECKED); // test (menuitem) checkable and checked states testStates("menuitem_checked_true", (STATE_CHECKABLE | STATE_CHECKED)); @@ -239,19 +239,19 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=452388
-
item
+
item
-
item
+
item
-
item
+
item
-
item
+
item
-
item
+
item
From 412adf88e6a9c3e66b58352edc147df357396149 Mon Sep 17 00:00:00 2001 From: Wes Johnston Date: Fri, 10 Feb 2012 10:23:22 -0800 Subject: [PATCH 21/34] Bug 725858 - Don't load sqlite libraries for migration unless we're migrating. r=gcp --- mobile/android/base/GeckoApp.java | 10 +++++----- mobile/android/base/ProfileMigrator.java | 1 + 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/mobile/android/base/GeckoApp.java b/mobile/android/base/GeckoApp.java index ca8ad2775fb5..36793b1066e9 100644 --- a/mobile/android/base/GeckoApp.java +++ b/mobile/android/base/GeckoApp.java @@ -2321,22 +2321,22 @@ abstract public class GeckoApp } private void checkMigrateProfile() { + long currentTime = SystemClock.uptimeMillis(); + Log.i(LOGTAG, "checking profile migration in: " + profileDir.getAbsolutePath()); + File profileDir = getProfileDir(); if (profileDir != null) { - long currentTime = SystemClock.uptimeMillis(); - Log.i(LOGTAG, "checking profile migration in: " + profileDir.getAbsolutePath()); final GeckoApp app = GeckoApp.mAppContext; final SetupScreen setupScreen = new SetupScreen(app); // don't show unless we take a while setupScreen.showDelayed(mMainHandler); - GeckoAppShell.ensureSQLiteLibsLoaded(app.getApplication().getPackageResourcePath()); ProfileMigrator profileMigrator = new ProfileMigrator(app.getContentResolver(), profileDir); profileMigrator.launch(); setupScreen.dismiss(); - long timeDiff = SystemClock.uptimeMillis() - currentTime; - Log.i(LOGTAG, "Profile migration took " + timeDiff + " ms"); } + long timeDiff = SystemClock.uptimeMillis() - currentTime; + Log.i(LOGTAG, "Profile migration took " + timeDiff + " ms"); } private SynchronousQueue mFilePickerResult = new SynchronousQueue(); diff --git a/mobile/android/base/ProfileMigrator.java b/mobile/android/base/ProfileMigrator.java index b3b769de2cd6..1e444a53034a 100644 --- a/mobile/android/base/ProfileMigrator.java +++ b/mobile/android/base/ProfileMigrator.java @@ -280,6 +280,7 @@ public class ProfileMigrator { File dbFileShm = new File(dbPathShm); SQLiteBridge db = null; + GeckoAppShell.ensureSQLiteLibsLoaded(GeckoApp.mAppContext.getApplication().getPackageResourcePath()); try { db = new SQLiteBridge(dbPath); migrateBookmarks(db); From d0d5850eddb5fef75304655a1d1978c26e0c32ad Mon Sep 17 00:00:00 2001 From: Brian Nicholson Date: Fri, 10 Feb 2012 10:40:05 -0800 Subject: [PATCH 22/34] Bug 720509 - Add null check for URI scheme in options menu. r=mfinkle --- mobile/android/base/GeckoApp.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mobile/android/base/GeckoApp.java b/mobile/android/base/GeckoApp.java index 36793b1066e9..cf13f828f2a4 100644 --- a/mobile/android/base/GeckoApp.java +++ b/mobile/android/base/GeckoApp.java @@ -457,8 +457,8 @@ abstract public class GeckoApp // Disable share menuitem for about:, chrome: and file: URIs String scheme = Uri.parse(tab.getURL()).getScheme(); - boolean enabled = !(scheme.equals("about") || scheme.equals("chrome") || - scheme.equals("file")); + boolean enabled = scheme != null && !(scheme.equals("about") || scheme.equals("chrome") || + scheme.equals("file")); share.setEnabled(enabled); // Disable save as PDF for about:home and xul pages From b583f57abf0730524d43a352928518d73c1bdada Mon Sep 17 00:00:00 2001 From: Robert Strong Date: Fri, 10 Feb 2012 10:43:32 -0800 Subject: [PATCH 23/34] Bug 725876 - Rename MOZ_UTILS_LDFLAGS to MOZ_GLUE_LDFLAGS and MOZ_UTILS_PROGRAM_LDFLAGS to MOZ_GLUE_PROGRAM_LDFLAGS. r=bbondy --- toolkit/components/maintenanceservice/Makefile.in | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/toolkit/components/maintenanceservice/Makefile.in b/toolkit/components/maintenanceservice/Makefile.in index d9d418724892..7b7c5d30dc9e 100644 --- a/toolkit/components/maintenanceservice/Makefile.in +++ b/toolkit/components/maintenanceservice/Makefile.in @@ -57,9 +57,10 @@ CPPSRCS = \ PROGRAM = maintenanceservice$(BIN_SUFFIX) DIST_PROGRAM = maintenanceservice$(BIN_SUFFIX) -# Don't link the maintenanceservice against libmozutils. See bug 687139 -MOZ_UTILS_LDFLAGS = -MOZ_UTILS_PROGRAM_LDFLAGS = +# Don't link the maintenanceservice against mozglue.dll. See bug 687139 and +# bug 725876 +MOZ_GLUE_LDFLAGS = +MOZ_GLUE_PROGRAM_LDFLAGS = LIBS += \ ../../mozapps/update/common/$(LIB_PREFIX)updatecommon.$(LIB_SUFFIX) \ From 49f758310576196b67ddb3c8c1cd92e7b442dc2b Mon Sep 17 00:00:00 2001 From: Wes Johnston Date: Fri, 10 Feb 2012 10:48:48 -0800 Subject: [PATCH 24/34] backout 83e4a240abc0 --- mobile/android/base/GeckoApp.java | 10 +++++----- mobile/android/base/ProfileMigrator.java | 1 - 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/mobile/android/base/GeckoApp.java b/mobile/android/base/GeckoApp.java index cf13f828f2a4..222090e8baf3 100644 --- a/mobile/android/base/GeckoApp.java +++ b/mobile/android/base/GeckoApp.java @@ -2321,22 +2321,22 @@ abstract public class GeckoApp } private void checkMigrateProfile() { - long currentTime = SystemClock.uptimeMillis(); - Log.i(LOGTAG, "checking profile migration in: " + profileDir.getAbsolutePath()); - File profileDir = getProfileDir(); if (profileDir != null) { + long currentTime = SystemClock.uptimeMillis(); + Log.i(LOGTAG, "checking profile migration in: " + profileDir.getAbsolutePath()); final GeckoApp app = GeckoApp.mAppContext; final SetupScreen setupScreen = new SetupScreen(app); // don't show unless we take a while setupScreen.showDelayed(mMainHandler); + GeckoAppShell.ensureSQLiteLibsLoaded(app.getApplication().getPackageResourcePath()); ProfileMigrator profileMigrator = new ProfileMigrator(app.getContentResolver(), profileDir); profileMigrator.launch(); setupScreen.dismiss(); + long timeDiff = SystemClock.uptimeMillis() - currentTime; + Log.i(LOGTAG, "Profile migration took " + timeDiff + " ms"); } - long timeDiff = SystemClock.uptimeMillis() - currentTime; - Log.i(LOGTAG, "Profile migration took " + timeDiff + " ms"); } private SynchronousQueue mFilePickerResult = new SynchronousQueue(); diff --git a/mobile/android/base/ProfileMigrator.java b/mobile/android/base/ProfileMigrator.java index 1e444a53034a..b3b769de2cd6 100644 --- a/mobile/android/base/ProfileMigrator.java +++ b/mobile/android/base/ProfileMigrator.java @@ -280,7 +280,6 @@ public class ProfileMigrator { File dbFileShm = new File(dbPathShm); SQLiteBridge db = null; - GeckoAppShell.ensureSQLiteLibsLoaded(GeckoApp.mAppContext.getApplication().getPackageResourcePath()); try { db = new SQLiteBridge(dbPath); migrateBookmarks(db); From cd90c75d3b9a84e9a50400bb02a8545c283bbf7f Mon Sep 17 00:00:00 2001 From: Brad Lassey Date: Sat, 4 Feb 2012 01:48:26 -0500 Subject: [PATCH 25/34] Bug 724210 - Stop using canvas to take screenshots. r=kats --- embedding/android/GeckoAppShell.java | 5 +++ mobile/android/base/GeckoApp.java | 12 ++++-- mobile/android/base/GeckoAppShell.java | 11 ++++++ mobile/android/base/Tabs.java | 8 ---- mobile/android/chrome/content/browser.js | 19 +-------- widget/android/AndroidBridge.cpp | 49 ++++++++++++++++++++++++ widget/android/AndroidBridge.h | 3 ++ widget/android/nsIAndroidBridge.idl | 3 ++ 8 files changed, 81 insertions(+), 29 deletions(-) diff --git a/embedding/android/GeckoAppShell.java b/embedding/android/GeckoAppShell.java index 5561f8f196f8..499eed4f80b0 100644 --- a/embedding/android/GeckoAppShell.java +++ b/embedding/android/GeckoAppShell.java @@ -603,6 +603,11 @@ public class GeckoAppShell imm, text, start, end, newEnd); } + public static void notifyScreenShot(ByteBuffer data, int tabId, int width, int height) { + // this stub is never called in XUL Fennec, but we need it so that the JNI code + // shared between XUL and Native Fennec doesn't die. + } + private static CountDownLatch sGeckoPendingAcks = null; // Block the current thread until the Gecko event loop is caught up diff --git a/mobile/android/base/GeckoApp.java b/mobile/android/base/GeckoApp.java index 222090e8baf3..47f02b82120b 100644 --- a/mobile/android/base/GeckoApp.java +++ b/mobile/android/base/GeckoApp.java @@ -622,8 +622,8 @@ abstract public class GeckoApp message.put("source", source); JSONObject destination = new JSONObject(); - source.put("width", dw); - source.put("height", dh); + destination.put("width", dw); + destination.put("height", dh); message.put("destination", destination); String json = message.toString(); @@ -635,8 +635,14 @@ abstract public class GeckoApp } void processThumbnail(Tab thumbnailTab, Bitmap bitmap, byte[] compressed) { - if (Tabs.getInstance().isSelectedTab(thumbnailTab)) + if (Tabs.getInstance().isSelectedTab(thumbnailTab)) { + if (compressed == null) { + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + bitmap.compress(Bitmap.CompressFormat.PNG, 0, bos); + compressed = bos.toByteArray(); + } mLastScreen = compressed; + } if (thumbnailTab.getURL().equals("about:home")) { thumbnailTab.updateThumbnail(null); return; diff --git a/mobile/android/base/GeckoAppShell.java b/mobile/android/base/GeckoAppShell.java index 1ac7748ad7f2..1d0fa011f179 100644 --- a/mobile/android/base/GeckoAppShell.java +++ b/mobile/android/base/GeckoAppShell.java @@ -558,6 +558,17 @@ public class GeckoAppShell mInputConnection.notifyIMEChange(text, start, end, newEnd); } + public static void notifyScreenShot(ByteBuffer data, int tabId, int width, int height) { + final Bitmap b = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565); + b.copyPixelsFromBuffer(data); + final Tab tab = Tabs.getInstance().getTab(tabId); + getHandler().post(new Runnable() { + public void run() { + GeckoApp.mAppContext.processThumbnail(tab, b, null); + } + }); + } + private static CountDownLatch sGeckoPendingAcks = null; // Block the current thread until the Gecko event loop is caught up diff --git a/mobile/android/base/Tabs.java b/mobile/android/base/Tabs.java index 407fef725be7..0aff6405f7f0 100644 --- a/mobile/android/base/Tabs.java +++ b/mobile/android/base/Tabs.java @@ -68,7 +68,6 @@ public class Tabs implements GeckoEventListener { GeckoAppShell.registerGeckoEventListener("Tab:Added", this); GeckoAppShell.registerGeckoEventListener("Tab:Close", this); GeckoAppShell.registerGeckoEventListener("Tab:Select", this); - GeckoAppShell.registerGeckoEventListener("Tab:ScreenshotData", this); GeckoAppShell.registerGeckoEventListener("Session:RestoreBegin", this); GeckoAppShell.registerGeckoEventListener("Session:RestoreEnd", this); } @@ -288,13 +287,6 @@ public class Tabs implements GeckoEventListener { closeTab(tab); } else if (event.equals("Tab:Select")) { selectTab(message.getInt("tabID")); - } else if (event.equals("Tab:ScreenshotData")) { - Tab tab = getTab(message.getInt("tabID")); - String data = message.getString("data"); - if (data.length() < 22) - return; - byte[] compressed = GeckoAppShell.decodeBase64(data.substring(22), GeckoAppShell.BASE64_DEFAULT); - GeckoApp.mAppContext.processThumbnail(tab, null, compressed); } else if (event.equals("Session:RestoreBegin")) { mRestoringSession = true; } else if (event.equals("Session:RestoreEnd")) { diff --git a/mobile/android/chrome/content/browser.js b/mobile/android/chrome/content/browser.js index 61ecae478b83..b253b242bc00 100644 --- a/mobile/android/chrome/content/browser.js +++ b/mobile/android/chrome/content/browser.js @@ -1615,24 +1615,7 @@ Tab.prototype = { if (!this.browser || !this.browser.contentWindow) return; - let canvas = document.createElementNS("http://www.w3.org/1999/xhtml", "canvas"); - canvas.setAttribute("width", aDst.width); - canvas.setAttribute("height", aDst.height); - canvas.setAttribute("moz-opaque", "true"); - - let ctx = canvas.getContext("2d"); - let flags = ctx.DRAWWINDOW_DO_NOT_FLUSH; - ctx.drawWindow(this.browser.contentWindow, 0, 0, aSrc.width, aSrc.height, "#fff", flags); - let message = { - gecko: { - type: "Tab:ScreenshotData", - tabID: this.id, - width: aDst.width, - height: aDst.height, - data: canvas.toDataURL() - } - }; - sendMessageToJava(message); + getBridge().takeScreenshot(this.browser.contentWindow, 0, 0, aSrc.width, aSrc.height, aDst.width, aDst.height, this.id); Services.tm.mainThread.dispatch(function() { BrowserApp.doNextScreenshot() }, Ci.nsIThread.DISPATCH_NORMAL); diff --git a/widget/android/AndroidBridge.cpp b/widget/android/AndroidBridge.cpp index c23928bb73d2..af51a6f648a0 100644 --- a/widget/android/AndroidBridge.cpp +++ b/widget/android/AndroidBridge.cpp @@ -51,6 +51,11 @@ #include "nsThreadUtils.h" #include "nsIThreadManager.h" #include "mozilla/dom/sms/PSms.h" +#include "gfxImageSurface.h" +#include "gfxContext.h" +#include "nsPresContext.h" +#include "nsIDocShell.h" +#include "nsPIDOMWindow.h" #ifdef DEBUG #define ALOG_BRIDGE(args...) ALOG(args) @@ -103,6 +108,7 @@ AndroidBridge::Init(JNIEnv *jEnv, jNotifyIME = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "notifyIME", "(II)V"); jNotifyIMEEnabled = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "notifyIMEEnabled", "(ILjava/lang/String;Ljava/lang/String;Z)V"); jNotifyIMEChange = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "notifyIMEChange", "(Ljava/lang/String;III)V"); + jNotifyScreenShot = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "notifyScreenShot", "(Ljava/nio/ByteBuffer;III)V"); jAcknowledgeEventSync = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "acknowledgeEventSync", "()V"); jEnableDeviceMotion = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "enableDeviceMotion", "(Z)V"); @@ -1959,3 +1965,46 @@ AndroidBridge::HideSurface(jobject surface) env->CallStaticVoidMethod(cls, method, surface); #endif } + + +/* void takeScreenshot (in nsIDOMWindow win, in PRInt32 srcX, in PRInt32 srcY, in PRInt32 srcW, in PRInt32 srcH, in PRInt32 dstX, in PRInt32 dstY, in PRInt32 dstW, in PRInt32 dstH, in AString color); */ +NS_IMETHODIMP nsAndroidBridge::TakeScreenshot(nsIDOMWindow *window, PRInt32 srcX, PRInt32 srcY, PRInt32 srcW, PRInt32 srcH, PRInt32 dstW, PRInt32 dstH, PRInt32 tabId) +{ + nsCOMPtr win = do_QueryInterface(window); + if (!win) + return NS_ERROR_FAILURE; + nsRefPtr presContext; + nsIDocShell* docshell = win->GetDocShell(); + if (docshell) { + docshell->GetPresContext(getter_AddRefs(presContext)); + } + if (!presContext) + return NS_ERROR_FAILURE; + nscolor bgColor = NS_RGB(255, 255, 255); + nsIPresShell* presShell = presContext->PresShell(); + PRUint32 renderDocFlags = (nsIPresShell::RENDER_IGNORE_VIEWPORT_SCROLLING | + nsIPresShell::RENDER_DOCUMENT_RELATIVE); + nsRect r(nsPresContext::CSSPixelsToAppUnits(srcX), + nsPresContext::CSSPixelsToAppUnits(srcY), + nsPresContext::CSSPixelsToAppUnits(srcW), + nsPresContext::CSSPixelsToAppUnits(srcH)); + + nsRefPtr surf = new gfxImageSurface(nsIntSize(dstW, dstH), gfxASurface::ImageFormatRGB16_565); + nsRefPtr context = new gfxContext(surf); + nsresult rv = presShell->RenderDocument(r, renderDocFlags, bgColor, context); + NS_ENSURE_SUCCESS(rv, rv); + AndroidBridge::Bridge()->NotifyScreenshot(surf->Data(), surf->GetDataSize(), tabId, dstW, dstH); + return NS_OK; +} + +void AndroidBridge::NotifyScreenshot(unsigned char* data, int size, int tabId, int width, int height) +{ + JNIEnv* jenv = GetJNIEnv(); + if (!jenv) + return; + AutoLocalJNIFrame jniFrame(jenv, 1); + jobject buffer = jenv->NewDirectByteBuffer(data, size); + if (!buffer) + return; + jenv->CallStaticVoidMethod(mGeckoAppShellClass, jNotifyScreenShot, buffer, tabId, width, height); +} diff --git a/widget/android/AndroidBridge.h b/widget/android/AndroidBridge.h index faafc7184192..4cd206a98582 100644 --- a/widget/android/AndroidBridge.h +++ b/widget/android/AndroidBridge.h @@ -156,6 +156,8 @@ public: static void NotifyIMEChange(const PRUnichar *aText, PRUint32 aTextLen, int aStart, int aEnd, int aNewEnd); + void NotifyScreenshot(unsigned char* data, int size, int tabId, int width, int height); + void AcknowledgeEventSync(); void EnableDeviceMotion(bool aEnable); @@ -420,6 +422,7 @@ protected: jmethodID jNotifyIME; jmethodID jNotifyIMEEnabled; jmethodID jNotifyIMEChange; + jmethodID jNotifyScreenShot; jmethodID jAcknowledgeEventSync; jmethodID jEnableDeviceMotion; jmethodID jEnableLocation; diff --git a/widget/android/nsIAndroidBridge.idl b/widget/android/nsIAndroidBridge.idl index e3c860e18f19..c1636f863f67 100644 --- a/widget/android/nsIAndroidBridge.idl +++ b/widget/android/nsIAndroidBridge.idl @@ -1,4 +1,5 @@ #include "nsISupports.idl" +#include "nsIDOMWindow.idl" [scriptable, uuid(38b5c83a-3e8d-45c2-8311-6e36bd5116c0)] interface nsIAndroidDrawMetadataProvider : nsISupports { @@ -16,4 +17,6 @@ interface nsIAndroidBridge : nsISupports { AString handleGeckoMessage(in AString message); void setDrawMetadataProvider(in nsIAndroidDrawMetadataProvider provider); + void takeScreenshot(in nsIDOMWindow win, in PRInt32 srcX, in PRInt32 srcY, in PRInt32 srcW, in PRInt32 srcH, + in PRInt32 dstW, in PRInt32 dstH, in PRInt32 tabId); }; From 16c8366afc9640a7276d7cc360868310d4ffbc11 Mon Sep 17 00:00:00 2001 From: Matt Brubeck Date: Fri, 10 Feb 2012 12:04:13 -0800 Subject: [PATCH 26/34] Bug 723077 - Speed up processing of option elements in FormAssistant [r=wesj] --- mobile/android/chrome/content/browser.js | 39 ++++++++++-------------- 1 file changed, 16 insertions(+), 23 deletions(-) diff --git a/mobile/android/chrome/content/browser.js b/mobile/android/chrome/content/browser.js index b253b242bc00..a3b7936eb1a0 100644 --- a/mobile/android/chrome/content/browser.js +++ b/mobile/android/chrome/content/browser.js @@ -2904,14 +2904,6 @@ var FormAssistant = { return (aElement instanceof HTMLSelectElement); }, - _isOptionElement: function(aElement) { - return aElement instanceof HTMLOptionElement; - }, - - _isOptionGroupElement: function(aElement) { - return aElement instanceof HTMLOptGroupElement; - }, - getListForElement: function(aElement) { let result = { type: "Prompt:Show", @@ -2926,15 +2918,15 @@ var FormAssistant = { ]; } - this.forOptions(aElement, function(aNode, aIndex) { + this.forOptions(aElement, function(aNode, aIndex, aIsGroup, aInGroup) { let item = { label: aNode.text || aNode.label, - isGroup: this._isOptionGroupElement(aNode), - inGroup: this._isOptionGroupElement(aNode.parentNode), + isGroup: aIsGroup, + inGroup: aInGroup, disabled: aNode.disabled, id: aIndex } - if (item.inGroup) + if (aInGroup) item.disabled = item.disabled || aNode.parentNode.disabled; result.listitems[aIndex] = item; @@ -2946,26 +2938,27 @@ var FormAssistant = { forOptions: function(aElement, aFunction) { let optionIndex = 0; let children = aElement.children; + let numChildren = children.length; // if there are no children in this select, we add a dummy row so that at least something appears - if (children.length == 0) + if (numChildren == 0) aFunction.call(this, {label:""}, optionIndex); - for (let i = 0; i < children.length; i++) { + for (let i = 0; i < numChildren; i++) { let child = children[i]; - if (this._isOptionGroupElement(child)) { - aFunction.call(this, child, optionIndex); + if (child instanceof HTMLOptionElement) { + // This is a regular choice under no group. + aFunction.call(this, child, optionIndex, false, false); + optionIndex++; + } else if (child instanceof HTMLOptGroupElement) { + aFunction.call(this, child, optionIndex, true, false); optionIndex++; let subchildren = child.children; - for (let j = 0; j < subchildren.length; j++) { + let numSubchildren = subchildren.length; + for (let j = 0; j < numSubchildren; j++) { let subchild = subchildren[j]; - aFunction.call(this, subchild, optionIndex); + aFunction.call(this, subchild, optionIndex, false, true); optionIndex++; } - - } else if (this._isOptionElement(child)) { - // This is a regular choice under no group. - aFunction.call(this, child, optionIndex); - optionIndex++; } } } From bf4fa201000848dc9754aafaa08507f81f5cdf64 Mon Sep 17 00:00:00 2001 From: Aryeh Gregor Date: Fri, 10 Feb 2012 21:04:59 +0000 Subject: [PATCH 27/34] Bug 719446 - getComputedStyle().MozTransform shouldn't have "px" in it; r=roc --- layout/base/tests/test_bug435293-scale.html | 8 +- layout/base/tests/test_bug435293-skew.html | 28 +++---- layout/style/nsComputedDOMStyle.cpp | 5 +- .../test/test_transitions_per_property.html | 80 +++++++++---------- 4 files changed, 60 insertions(+), 61 deletions(-) diff --git a/layout/base/tests/test_bug435293-scale.html b/layout/base/tests/test_bug435293-scale.html index a1946c01c603..91777af3c7b6 100644 --- a/layout/base/tests/test_bug435293-scale.html +++ b/layout/base/tests/test_bug435293-scale.html @@ -70,15 +70,15 @@ runtests(); function runtests() { var style = window.getComputedStyle(document.getElementById("test1"), ""); - is(style.getPropertyValue("-moz-transform"), "matrix(0.5, 0, 0, 1, 0px, 0px)", + is(style.getPropertyValue("-moz-transform"), "matrix(0.5, 0, 0, 1, 0, 0)", "Scalex proper matrix is applied"); style = window.getComputedStyle(document.getElementById("test2"), ""); - is(style.getPropertyValue("-moz-transform"), "matrix(1, 0, 0, 0.5, 0px, 0px)", + is(style.getPropertyValue("-moz-transform"), "matrix(1, 0, 0, 0.5, 0, 0)", "Scaley proper matrix is applied"); style = window.getComputedStyle(document.getElementById("test3"), ""); - is(style.getPropertyValue("-moz-transform"), "matrix(0.5, 0, 0, 0.5, 0px, 0px)", + is(style.getPropertyValue("-moz-transform"), "matrix(0.5, 0, 0, 0.5, 0, 0)", "Scale proper matrix is applied"); style = window.getComputedStyle(document.getElementById("test4"), ""); @@ -90,7 +90,7 @@ function runtests() { "Percent values in scale should be ignored"); style = window.getComputedStyle(document.getElementById("test6"), ""); - is(style.getPropertyValue("-moz-transform"), "matrix(640000, 0, 0, 1e-19, 0px, 0px)", + is(style.getPropertyValue("-moz-transform"), "matrix(640000, 0, 0, 1e-19, 0, 0)", "Ensure wacky values are accepted"); style = window.getComputedStyle(document.getElementById("test7"), ""); diff --git a/layout/base/tests/test_bug435293-skew.html b/layout/base/tests/test_bug435293-skew.html index 0fab200b3f7a..ef74615d4c9d 100644 --- a/layout/base/tests/test_bug435293-skew.html +++ b/layout/base/tests/test_bug435293-skew.html @@ -91,7 +91,7 @@ runtests(); function runtests() { // For test 1 we need to handle the contingency that different systems may // round differently. We will parse out the values and compare them - // individually. The matrix should be: matrix(1, 0, 0.57735, 1, 0px, 0px) + // individually. The matrix should be: matrix(1, 0, 0.57735, 1, 0, 0) var style = window.getComputedStyle(document.getElementById("test1"), ""); var tformStyle = style.getPropertyValue("-moz-transform"); var tformValues = tformStyle.substring(tformStyle.indexOf('(') + 1, @@ -100,11 +100,11 @@ function runtests() { is((+tformValues[1]), 0, "Test1: skewx: param 1 is 0"); ok(verifyRounded(tformValues[2], 0.57735), "Test1: skewx: Rounded param 2 is in bounds"); is((+tformValues[3]), 1, "Test1: skewx: param 3 is 1"); - is(tformValues[4].trim(), "0px", "Test1: skewx: param 4 is 0px"); - is(tformValues[5].trim(), "0px", "Test1: skewx: param 5 is 0px"); + is((+tformValues[4]), 0, "Test1: skewx: param 4 is 0"); + is((+tformValues[5]), 0, "Test1: skewx: param 5 is 0"); // Again, handle rounding for test 2, proper matrix should be: - // matrix(1, 1.73205, 0, 1, 0px, 0px) + // matrix(1, 1.73205, 0, 1, 0, 0) style = window.getComputedStyle(document.getElementById("test2"), ""); tformStyle = style.getPropertyValue("-moz-transform"); tformValues = tformStyle.substring(tformStyle.indexOf('(') + 1, @@ -113,19 +113,19 @@ function runtests() { ok(verifyRounded(tformValues[1], 1.73205), "Test2: skewy: Rounded param 1 is in bounds"); is((+tformValues[2]), 0, "Test2: skewy: param 2 is 0"); is((+tformValues[3]), 1, "Test2: skewy: param 3 is 1"); - is(tformValues[4].trim(), "0px", "Test2: skewy: param 4 is 0px"); - is(tformValues[5].trim(), "0px", "Test2: skewy: param 5 is 0px"); + is((+tformValues[4]), 0, "Test2: skewy: param 4 is 0"); + is((+tformValues[5]), 0, "Test2: skewy: param 5 is 0"); style = window.getComputedStyle(document.getElementById("test3"), ""); - is(style.getPropertyValue("-moz-transform"), "matrix(1, 1, 1, 1, 0px, 0px)", + is(style.getPropertyValue("-moz-transform"), "matrix(1, 1, 1, 1, 0, 0)", "Test3: Skew proper matrix is applied"); style = window.getComputedStyle(document.getElementById("test4"), ""); - is(style.getPropertyValue("-moz-transform"), "matrix(1, 1, 0, 1, 0px, 0px)", + is(style.getPropertyValue("-moz-transform"), "matrix(1, 1, 0, 1, 0, 0)", "Test4: Skew angle wrap: proper matrix is applied"); style = window.getComputedStyle(document.getElementById("test5"), ""); - is(style.getPropertyValue("-moz-transform"), "matrix(1, -1, 1, 1, 0px, 0px)", + is(style.getPropertyValue("-moz-transform"), "matrix(1, -1, 1, 1, 0, 0)", "Test5: Skew mixing deg and grad"); style = window.getComputedStyle(document.getElementById("test6"), ""); @@ -137,7 +137,7 @@ function runtests() { "Test7: Skew with more invalid units"); // Test 8: skew with negative degrees, here again we must handle rounding. - // The matrix should be: matrix(1, 3.73206, -1, 1, 0px, 0px) + // The matrix should be: matrix(1, 3.73206, -1, 1, 0, 0) style = window.getComputedStyle(document.getElementById("test8"), ""); tformStyle = style.getPropertyValue("-moz-transform"); tformValues = tformStyle.substring(tformStyle.indexOf('(') + 1, @@ -146,19 +146,19 @@ function runtests() { ok(verifyRounded(tformValues[1], 3.73206), "Test8: Rounded param 1 is in bounds"); is((+tformValues[2]), -1, "Test8: param 2 is -1"); is((+tformValues[3]), 1, "Test8: param 3 is 1"); - is(tformValues[4].trim(), "0px", "Test8: param 4 is 0px"); - is(tformValues[5].trim(), "0px", "Test8: param 5 is 0px"); + is((+tformValues[4]), 0, "Test8: param 4 is 0"); + is((+tformValues[5]), 0, "Test8: param 5 is 0"); style = window.getComputedStyle(document.getElementById("test9"), ""); is(style.getPropertyValue("-moz-transform"), "none", "Test9: Skew in 3d should be ignored"); style = window.getComputedStyle(document.getElementById("test10"), ""); - is(style.getPropertyValue("-moz-transform"), "matrix(1, -10000, 1, 1, 0px, 0px)", + is(style.getPropertyValue("-moz-transform"), "matrix(1, -10000, 1, 1, 0, 0)", "Test10: Skew with nearly infinite numbers"); style = window.getComputedStyle(document.getElementById("test11"), ""); - is(style.getPropertyValue("-moz-transform"), "matrix(1, -10000, 10000, 1, 0px, 0px)", + is(style.getPropertyValue("-moz-transform"), "matrix(1, -10000, 10000, 1, 0, 0)", "Test11: Skew with more infinite numbers"); } diff --git a/layout/style/nsComputedDOMStyle.cpp b/layout/style/nsComputedDOMStyle.cpp index f043d51d898e..5a0f3988447d 100644 --- a/layout/style/nsComputedDOMStyle.cpp +++ b/layout/style/nsComputedDOMStyle.cpp @@ -1108,13 +1108,12 @@ nsComputedDOMStyle::DoGetMozTransform() resultString.Append(NS_LITERAL_STRING(", ")); } resultString.AppendFloat(matrix._41); - resultString.Append(NS_LITERAL_STRING("px, ")); + resultString.Append(NS_LITERAL_STRING(", ")); resultString.AppendFloat(matrix._42); - resultString.Append(NS_LITERAL_STRING("px")); if (is3D) { resultString.Append(NS_LITERAL_STRING(", ")); resultString.AppendFloat(matrix._43); - resultString.Append(NS_LITERAL_STRING("px, ")); + resultString.Append(NS_LITERAL_STRING(", ")); resultString.AppendFloat(matrix._44); } resultString.Append(NS_LITERAL_STRING(")")); diff --git a/layout/style/test/test_transitions_per_property.html b/layout/style/test/test_transitions_per_property.html index 7cc54e99ef92..1b763dc3ebe7 100644 --- a/layout/style/test/test_transitions_per_property.html +++ b/layout/style/test/test_transitions_per_property.html @@ -1315,41 +1315,41 @@ function test_transform_transition(prop) { // translate { start: 'translate(20px)', end: 'none', expected_uncomputed: 'translate(15px)', - expected: 'matrix(1, 0, 0, 1, 15px, 0px)' }, + expected: 'matrix(1, 0, 0, 1, 15, 0)' }, { start: 'translate(20px, 12px)', end: 'none', expected_uncomputed: 'translate(15px, 9px)', - expected: 'matrix(1, 0, 0, 1, 15px, 9px)' }, + expected: 'matrix(1, 0, 0, 1, 15, 9)' }, { start: 'translateX(-20px)', end: 'none', expected_uncomputed: 'translateX(-15px)', - expected: 'matrix(1, 0, 0, 1, -15px, 0px)' }, + expected: 'matrix(1, 0, 0, 1, -15, 0)' }, { start: 'translateY(-40px)', end: 'none', expected_uncomputed: 'translateY(-30px)', - expected: 'matrix(1, 0, 0, 1, 0px, -30px)' }, + expected: 'matrix(1, 0, 0, 1, 0, -30)' }, { start: 'translateZ(40px)', end: 'none', expected_uncomputed: 'translateZ(30px)', - expected: 'matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0px, 0px, 30px, 1)', + expected: 'matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 30, 1)', requires_3d: true }, { start: 'none', end: 'translate3D(40px, 60px, -40px)', expected_uncomputed: 'translate3D(10px, 15px, -10px)', - expected: 'matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 10px, 15px, -10px, 1)', + expected: 'matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 10, 15, -10, 1)', requires_3d: true }, // percentages are relative to 300px (width) and 50px (height) // per the prerequisites in property_database.js { start: 'translate(20%)', end: 'none', expected_uncomputed: 'translate(15%)', - expected: 'matrix(1, 0, 0, 1, 45px, 0px)', + expected: 'matrix(1, 0, 0, 1, 45, 0)', round_error_ok: true }, { start: 'translate(20%, 12%)', end: 'none', expected_uncomputed: 'translate(15%, 9%)', - expected: 'matrix(1, 0, 0, 1, 45px, 4.5px)', + expected: 'matrix(1, 0, 0, 1, 45, 4.5)', round_error_ok: true }, { start: 'translateX(-20%)', end: 'none', expected_uncomputed: 'translateX(-15%)', - expected: 'matrix(1, 0, 0, 1, -45px, 0px)', + expected: 'matrix(1, 0, 0, 1, -45, 0)', round_error_ok: true }, { start: 'translateY(-40%)', end: 'none', expected_uncomputed: 'translateY(-30%)', - expected: 'matrix(1, 0, 0, 1, 0px, -15px)', + expected: 'matrix(1, 0, 0, 1, 0, -15)', round_error_ok: true }, { start: 'none', end: 'rotate(90deg) translate(20%, 20%) rotate(-90deg)', expected_uncomputed: 'rotate(22.5deg) translate(5%, 5%) rotate(-22.5deg)', @@ -1360,11 +1360,11 @@ function test_transform_transition(prop) { // test percent translation using matrix decomposition { start: 'rotate(45deg) rotate(-45deg)', end: 'rotate(90deg) translate(20%, 20%) rotate(-90deg)', - expected: 'matrix(1, 0, 0, 1, -2.5px, 15px)', + expected: 'matrix(1, 0, 0, 1, -2.5, 15)', round_error_ok: true }, { start: 'rotate(45deg) rotate(-45deg)', end: 'rotate(-90deg) translate(20%, 20%) rotate(90deg)', - expected: 'matrix(1, 0, 0, 1, 2.5px, -15px)', + expected: 'matrix(1, 0, 0, 1, 2.5, -15)', round_error_ok: true }, // test calc() in translate // Note that font-size: is 20px, and that percentages are relative @@ -1373,42 +1373,42 @@ function test_transform_transition(prop) { { start: 'translateX(20%)', /* 60px */ end: 'translateX(-moz-calc(10% + 1em))', /* 30px + 20px = 50px */ expected_uncomputed: 'translateX(-moz-calc(17.5% + 0.25em))', - expected: 'matrix(1, 0, 0, 1, 57.5px, 0px)' }, + expected: 'matrix(1, 0, 0, 1, 57.5, 0)' }, { start: 'translate(-moz-calc(0.75 * 3em + 1.5 * 10%), -moz-calc(0.5 * 5em + 0.5 * 8%))', /* 90px, 52px */ end: 'rotate(90deg) translateY(20%) rotate(90deg) translateY(-moz-calc(10% + 0.5em)) rotate(180deg)', /* -10px, -15px */ - expected: 'matrix(1, 0, 0, 1, 65px, 35.25px)' }, + expected: 'matrix(1, 0, 0, 1, 65, 35.25)' }, // scale { start: 'scale(2)', end: 'none', expected_uncomputed: 'scale(1.75)', - expected: 'matrix(1.75, 0, 0, 1.75, 0px, 0px)' }, + expected: 'matrix(1.75, 0, 0, 1.75, 0, 0)' }, { start: 'none', end: 'scale(0.4)', expected_uncomputed: 'scale(0.85)', - expected: 'matrix(0.85, 0, 0, 0.85, 0px, 0px)', + expected: 'matrix(0.85, 0, 0, 0.85, 0, 0)', round_error_ok: true }, { start: 'scale(2)', end: 'scale(-2)', expected_uncomputed: 'scale(1)', - expected: 'matrix(1, 0, 0, 1, 0px, 0px)' }, + expected: 'matrix(1, 0, 0, 1, 0, 0)' }, { start: 'scale(2)', end: 'scale(-6)', expected_uncomputed: 'scale(0)', - expected: 'matrix(0, 0, 0, 0, 0px, 0px)' }, + expected: 'matrix(0, 0, 0, 0, 0, 0)' }, { start: 'scale(2, 0.4)', end: 'none', expected_uncomputed: 'scale(1.75, 0.55)', - expected: 'matrix(1.75, 0, 0, 0.55, 0px, 0px)', + expected: 'matrix(1.75, 0, 0, 0.55, 0, 0)', round_error_ok: true }, { start: 'scaleX(3)', end: 'none', expected_uncomputed: 'scaleX(2.5)', - expected: 'matrix(2.5, 0, 0, 1, 0px, 0px)' }, + expected: 'matrix(2.5, 0, 0, 1, 0, 0)' }, { start: 'scaleY(5)', end: 'none', expected_uncomputed: 'scaleY(4)', - expected: 'matrix(1, 0, 0, 4, 0px, 0px)' }, + expected: 'matrix(1, 0, 0, 4, 0, 0)' }, { start: 'scaleZ(5)', end: 'none', expected_uncomputed: 'scaleZ(4)', - expected: 'matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 4, 0, 0px, 0px, 0px, 1)', + expected: 'matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 4, 0, 0, 0, 0, 1)', requires_3d: true }, { start: 'none', end: 'scale3D(5, 5, 5)', expected_uncomputed: 'scale3D(2, 2, 2)', - expected: 'matrix3d(2, 0, 0, 0, 0, 2, 0, 0, 0, 0, 2, 0, 0px, 0px, 0px, 1)', + expected: 'matrix3d(2, 0, 0, 0, 0, 2, 0, 0, 0, 0, 2, 0, 0, 0, 0, 1)', requires_3d: true }, // skew @@ -1428,15 +1428,15 @@ function test_transform_transition(prop) { expected_uncomputed: 'skewY(22.5deg)' }, // matrix : skewX - { start: 'matrix(1, 0, 3, 1, 0px, 0px)', end: 'none', - expected: 'matrix(1, 0, ' + 3 * 0.75 + ', 1, 0px, 0px)', + { start: 'matrix(1, 0, 3, 1, 0, 0)', end: 'none', + expected: 'matrix(1, 0, ' + 3 * 0.75 + ', 1, 0, 0)', round_error_ok: true }, { start: 'skewX(0)', end: 'skewX(-45deg) translate(0)', - expected: 'matrix(1, 0, -0.25, 1, 0px, 0px)', + expected: 'matrix(1, 0, -0.25, 1, 0, 0)', round_error_ok: true }, // matrix : rotate - { start: 'rotate(-30deg)', end: 'matrix(0, 1, -1, 0, 0px, 0px)', - expected: 'matrix(1, 0, 0, 1, 0px, 0px)', + { start: 'rotate(-30deg)', end: 'matrix(0, 1, -1, 0, 0, 0)', + expected: 'matrix(1, 0, 0, 1, 0, 0)', round_error_ok: true }, { start: 'rotate(-30deg) translateX(0)', end: 'translateX(0) rotate(-90deg)', @@ -1456,7 +1456,7 @@ function test_transform_transition(prop) { expected: c('rotate(135deg)') }, { start: 'scale(-1)', end: 'none', expected_uncomputed: 'scale(-0.5)', - expected: 'matrix(-0.5, 0, 0, -0.5, 0px, 0px)' }, + expected: 'matrix(-0.5, 0, 0, -0.5, 0, 0)' }, { start: 'rotate(180deg)', end: 'none', expected_uncomputed: 'rotate(135deg)' }, { start: 'rotate(-180deg)', end: 'none', @@ -1466,7 +1466,7 @@ function test_transform_transition(prop) { // matrix followed by scale { start: 'matrix(2, 0, 0, 2, 10px, 20px) scale(2)', end: 'none', - expected: 'matrix(3.0625, 0, 0, 3.0625, 7.5px, 15px)' }, + expected: 'matrix(3.0625, 0, 0, 3.0625, 7.5, 15)' }, // ... and a bunch of similar possibilities. The spec isn't settled // here; there are multiple options. See: @@ -1505,42 +1505,42 @@ function test_transform_transition(prop) { { start: 'none', end: 'matrix(1, 0, 1.5, 1, 0pt, 0pt)', /* skewX(atan(1.5)) */ - expected: 'matrix(1, 0, ' + 1.5 * 0.25 + ', 1, 0px, 0px)', + expected: 'matrix(1, 0, ' + 1.5 * 0.25 + ', 1, 0, 0)', round_error_ok: true }, { start: 'none', end: 'matrix(-1, 0, 2, -1, 0pt, 0pt)', /* rotate(180deg) skewX(atan(-2)) */ - expected: c('rotate(45deg) matrix(1, 0, ' + -2 * 0.25 + ', 1, 0px, 0px)'), + expected: c('rotate(45deg) matrix(1, 0, ' + -2 * 0.25 + ', 1, 0, 0)'), round_error_ok: true }, { start: 'none', end: 'matrix(0, -1, 1, -3, 0pt, 0pt)', /* rotate(-90deg) skewX(atan(3)) */ - expected: c('rotate(-22.5deg) matrix(1, 0, ' + 3 * 0.25 + ', 1, 0px, 0px)'), + expected: c('rotate(-22.5deg) matrix(1, 0, ' + 3 * 0.25 + ', 1, 0, 0)'), round_error_ok: true }, { start: 'none', end: 'matrix(0, 1, -1, 4, 0pt, 0pt)', /* rotate(90deg) skewX(atan(4)) */ - expected: c('rotate(22.5deg) matrix(1, 0, ' + 4 * 0.25 + ', 1, 0px, 0px)'), + expected: c('rotate(22.5deg) matrix(1, 0, ' + 4 * 0.25 + ', 1, 0, 0)'), round_error_ok: true }, // and then four with negative determinants { start: 'none', end: 'matrix(1, 0, 1, -1, 0pt, 0pt)', /* rotate(-180deg) skewX(atan(-1)) scaleX(-1) */ - expected: c('rotate(-45deg) matrix(1, 0, ' + -1 * 0.25 + ', 1, 0px, 0px) scaleX(0.5)'), + expected: c('rotate(-45deg) matrix(1, 0, ' + -1 * 0.25 + ', 1, 0, 0) scaleX(0.5)'), round_error_ok: true }, { start: 'none', end: 'matrix(-1, 0, -1, 1, 0pt, 0pt)', /* skewX(atan(-1)) scaleX(-1) */ - expected: c('matrix(1, 0, ' + -1 * 0.25 + ', 1, 0px, 0px) scaleX(0.5)') }, + expected: c('matrix(1, 0, ' + -1 * 0.25 + ', 1, 0, 0) scaleX(0.5)') }, { start: 'none', end: 'matrix(0, 1, 1, -2, 0pt, 0pt)', /* rotate(-90deg) skewX(atan(2)) scaleX(-1) */ - expected: c('rotate(-22.5deg) matrix(1, 0, ' + 2 * 0.25 + ', 1, 0px, 0px) scaleX(0.5)'), + expected: c('rotate(-22.5deg) matrix(1, 0, ' + 2 * 0.25 + ', 1, 0, 0) scaleX(0.5)'), round_error_ok: true }, { start: 'none', end: 'matrix(0, -1, -1, 0.5, 0pt, 0pt)', /* rotate(90deg) skewX(atan(0.5)) scaleX(-1) */ - expected: c('rotate(22.5deg) matrix(1, 0, ' + 0.5 * 0.25 + ', 1, 0px, 0px) scaleX(0.5)'), + expected: c('rotate(22.5deg) matrix(1, 0, ' + 0.5 * 0.25 + ', 1, 0, 0) scaleX(0.5)'), round_error_ok: true }, // lists vs. matrix decomposition @@ -1552,7 +1552,7 @@ function test_transform_transition(prop) { expected_uncomputed: 'skewY(22.5deg) rotate(90deg)' }, { start: 'skewY(45deg) rotate(90deg) translate(0)', end: 'skewY(-45deg) rotate(90deg)', - expected: 'matrix(0, 1, -1, -0.5, 0px, 0px)', + expected: 'matrix(0, 1, -1, -0.5, 0, 0)', round_error_ok: true }, { start: 'skewX(45deg) rotate(90deg)', end: 'skewX(-45deg) rotate(90deg)', @@ -1563,7 +1563,7 @@ function test_transform_transition(prop) { round_error_ok: true }, ]; - var matrix_re = /^matrix\(([^,]*), ([^,]*), ([^,]*), ([^,]*), ([^,]*)px, ([^,]*)px\)$/; + var matrix_re = /^matrix\(([^,]*), ([^,]*), ([^,]*), ([^,]*), ([^,]*), ([^,]*)\)$/; for (var i in tests) { var test = tests[i]; if (!("expected" in test)) { From 2c1f3999235a71cad3be61931ee9c40842a7a38d Mon Sep 17 00:00:00 2001 From: Aryeh Gregor Date: Fri, 10 Feb 2012 21:05:00 +0000 Subject: [PATCH 28/34] Bug 722777 - Tables with 'transform' property set don't act as abs-pos/fixed-pos containers; r=roc --HG-- rename : layout/reftests/transform/abspos-1a.html => layout/reftests/transform/abspos-1f.html rename : layout/reftests/transform/abspos-1b.html => layout/reftests/transform/abspos-1g.html --- layout/reftests/transform/abspos-1f.html | 12 ++++++++++++ layout/reftests/transform/abspos-1g.html | 12 ++++++++++++ layout/reftests/transform/reftest.list | 8 ++++++++ layout/reftests/transform/table-1-ref.html | 7 +++++++ layout/reftests/transform/table-1a.html | 5 +++++ layout/reftests/transform/table-1b.html | 5 +++++ layout/reftests/transform/table-1c.html | 7 +++++++ layout/reftests/transform/table-2-ref.html | 6 ++++++ layout/reftests/transform/table-2a.html | 5 +++++ layout/reftests/transform/table-2b.html | 5 +++++ layout/style/ua.css | 3 +++ layout/tables/nsTableFrame.cpp | 4 ++++ 12 files changed, 79 insertions(+) create mode 100644 layout/reftests/transform/abspos-1f.html create mode 100644 layout/reftests/transform/abspos-1g.html create mode 100644 layout/reftests/transform/table-1-ref.html create mode 100644 layout/reftests/transform/table-1a.html create mode 100644 layout/reftests/transform/table-1b.html create mode 100644 layout/reftests/transform/table-1c.html create mode 100644 layout/reftests/transform/table-2-ref.html create mode 100644 layout/reftests/transform/table-2a.html create mode 100644 layout/reftests/transform/table-2b.html diff --git a/layout/reftests/transform/abspos-1f.html b/layout/reftests/transform/abspos-1f.html new file mode 100644 index 000000000000..2b9d954e60fa --- /dev/null +++ b/layout/reftests/transform/abspos-1f.html @@ -0,0 +1,12 @@ + + + + +
+ A B C D E F G H I J K L M N O P Q R S T U V W X Y Z +
+ 0 1 2 3 4 5 6 7 8 9 +
+
+ + diff --git a/layout/reftests/transform/abspos-1g.html b/layout/reftests/transform/abspos-1g.html new file mode 100644 index 000000000000..32cf19e0cba6 --- /dev/null +++ b/layout/reftests/transform/abspos-1g.html @@ -0,0 +1,12 @@ + + + + +
+ A B C D E F G H I J K L M N O P Q R S T U V W X Y Z +
+ 0 1 2 3 4 5 6 7 8 9 +
+
+ + diff --git a/layout/reftests/transform/reftest.list b/layout/reftests/transform/reftest.list index 5d5da5a804e0..b57672abf0ae 100644 --- a/layout/reftests/transform/reftest.list +++ b/layout/reftests/transform/reftest.list @@ -66,6 +66,8 @@ random == rotate-1f.html rotate-1-ref.html == abspos-1c.html abspos-1-ref.html == abspos-1d.html abspos-1-ref.html != abspos-1e.html abspos-1-ref.html +== abspos-1f.html abspos-1-ref.html +== abspos-1g.html abspos-1-ref.html # Origin can use "top" "right" etc. == origin-name-1a.html origin-name-1-ref.html == origin-name-1b.html origin-name-1-ref.html @@ -110,3 +112,9 @@ fails-if(Android) == stresstest-1.html stresstest-1-ref.html # Bugs == 601894-1.html 601894-ref.html == 601894-2.html 601894-ref.html +# Bug 722777 +== table-1a.html table-1-ref.html +== table-1b.html table-1-ref.html +== table-1c.html table-1-ref.html +== table-2a.html table-2-ref.html +== table-2b.html table-2-ref.html diff --git a/layout/reftests/transform/table-1-ref.html b/layout/reftests/transform/table-1-ref.html new file mode 100644 index 000000000000..ca213123b528 --- /dev/null +++ b/layout/reftests/transform/table-1-ref.html @@ -0,0 +1,7 @@ + +
+ + +
Hello
there! +
+
diff --git a/layout/reftests/transform/table-1a.html b/layout/reftests/transform/table-1a.html new file mode 100644 index 000000000000..ce7458c8db38 --- /dev/null +++ b/layout/reftests/transform/table-1a.html @@ -0,0 +1,5 @@ + + + +
Hello
there! +
diff --git a/layout/reftests/transform/table-1b.html b/layout/reftests/transform/table-1b.html new file mode 100644 index 000000000000..ad045a3af4ea --- /dev/null +++ b/layout/reftests/transform/table-1b.html @@ -0,0 +1,5 @@ + + + +
Hello
there! +
diff --git a/layout/reftests/transform/table-1c.html b/layout/reftests/transform/table-1c.html new file mode 100644 index 000000000000..50f4d1add59f --- /dev/null +++ b/layout/reftests/transform/table-1c.html @@ -0,0 +1,7 @@ + +
+ + +
Hello
there! +
+
diff --git a/layout/reftests/transform/table-2-ref.html b/layout/reftests/transform/table-2-ref.html new file mode 100644 index 000000000000..60e7bbb294a6 --- /dev/null +++ b/layout/reftests/transform/table-2-ref.html @@ -0,0 +1,6 @@ + +
+ + +
there!
Hello +
diff --git a/layout/reftests/transform/table-2a.html b/layout/reftests/transform/table-2a.html new file mode 100644 index 000000000000..6e7f91ee5781 --- /dev/null +++ b/layout/reftests/transform/table-2a.html @@ -0,0 +1,5 @@ + + + +
there!
Hello +
diff --git a/layout/reftests/transform/table-2b.html b/layout/reftests/transform/table-2b.html new file mode 100644 index 000000000000..3d94dcf97b0c --- /dev/null +++ b/layout/reftests/transform/table-2b.html @@ -0,0 +1,5 @@ + + + +
there!
Hello +
diff --git a/layout/style/ua.css b/layout/style/ua.css index c0edf782480e..edfb8582d35a 100644 --- a/layout/style/ua.css +++ b/layout/style/ua.css @@ -74,6 +74,9 @@ page-break-after: inherit; vertical-align: inherit; /* needed for inline-table */ line-height: inherit; /* needed for vertical-align on inline-table */ + /* Bug 722777 */ + -moz-transform: inherit; + -moz-transform-origin: inherit; } *|*::-moz-table-row { diff --git a/layout/tables/nsTableFrame.cpp b/layout/tables/nsTableFrame.cpp index c4dc86bd85a8..0893fda82eec 100644 --- a/layout/tables/nsTableFrame.cpp +++ b/layout/tables/nsTableFrame.cpp @@ -213,6 +213,10 @@ nsTableFrame::Init(nsIContent* aContent, const nsStyleTableBorder* tableStyle = GetStyleTableBorder(); bool borderCollapse = (NS_STYLE_BORDER_COLLAPSE == tableStyle->mBorderCollapse); SetBorderCollapse(borderCollapse); + + // Transforms need to affect the outer frame, not the inner frame (bug 722777) + mState &= ~NS_FRAME_MAY_BE_TRANSFORMED; + // Create the cell map if this frame is the first-in-flow. if (!aPrevInFlow) { mCellMap = new nsTableCellMap(*this, borderCollapse); From 6004ad6221b75c0515a4ed9e07162f31e6525f8d Mon Sep 17 00:00:00 2001 From: Panagiotis Koutsourakis Date: Fri, 10 Feb 2012 21:06:56 +0000 Subject: [PATCH 29/34] Bug 702388 - Convert some more Makefiles to use |TEST_DIRS += foo|; r=khuey --- build/win32/Makefile.in | 8 ++++---- dom/sms/Makefile.in | 2 +- embedding/Makefile.in | 2 +- toolkit/components/startup/Makefile.in | 4 +--- toolkit/mozapps/shared/Makefile.in | 3 ++- toolkit/mozapps/update/Makefile.in | 8 +++----- 6 files changed, 12 insertions(+), 15 deletions(-) diff --git a/build/win32/Makefile.in b/build/win32/Makefile.in index ad7dea45730b..034fa7c8f563 100644 --- a/build/win32/Makefile.in +++ b/build/win32/Makefile.in @@ -44,18 +44,18 @@ include $(DEPTH)/config/autoconf.mk NO_PROFILE_GUIDED_OPTIMIZE = 1 -ifdef ENABLE_TESTS - ifdef _MSC_VER ifneq ($(OS_TEST),x86_64) -DIRS += vmwarerecordinghelper +TEST_DIRS += vmwarerecordinghelper endif endif -DIRS += \ +TEST_DIRS += \ crashinjectdll \ $(NULL) +ifdef ENABLE_TESTS + PROGRAM = crashinject$(BIN_SUFFIX) USE_STATIC_LIBS = 1 CPPSRCS = crashinject.cpp diff --git a/dom/sms/Makefile.in b/dom/sms/Makefile.in index b445e811dca1..4f1d3f11b7e0 100644 --- a/dom/sms/Makefile.in +++ b/dom/sms/Makefile.in @@ -45,8 +45,8 @@ include $(DEPTH)/config/autoconf.mk PARALLEL_DIRS = interfaces src +TEST_DIRS += tests ifdef ENABLE_TESTS -DIRS += tests XPCSHELL_TESTS = tests endif diff --git a/embedding/Makefile.in b/embedding/Makefile.in index ff0747e58157..7420969cbb78 100644 --- a/embedding/Makefile.in +++ b/embedding/Makefile.in @@ -48,9 +48,9 @@ MODULE = embed DIRS = base components browser +TEST_DIRS += test ifdef ENABLE_TESTS XPCSHELL_TESTS = tests/unit -DIRS += test endif ifeq ($(MOZ_WIDGET_TOOLKIT),android) diff --git a/toolkit/components/startup/Makefile.in b/toolkit/components/startup/Makefile.in index 861d8790a4e5..1069463178b4 100644 --- a/toolkit/components/startup/Makefile.in +++ b/toolkit/components/startup/Makefile.in @@ -73,10 +73,8 @@ endif XPCSHELL_TESTS = tests/unit -ifdef ENABLE_TESTS ifneq (mobile,$(MOZ_BUILD_APP)) -DIRS += tests/browser -endif +TEST_DIRS += tests/browser endif include $(topsrcdir)/config/rules.mk diff --git a/toolkit/mozapps/shared/Makefile.in b/toolkit/mozapps/shared/Makefile.in index 244085f1b9f2..e9cbb8fb6941 100644 --- a/toolkit/mozapps/shared/Makefile.in +++ b/toolkit/mozapps/shared/Makefile.in @@ -50,8 +50,9 @@ EXTRA_PP_JS_MODULES = \ FileUtils.jsm \ $(NULL) +TEST_DIRS += test/chrome + ifdef ENABLE_TESTS -DIRS += test/chrome XPCSHELL_TESTS = test/unit endif diff --git a/toolkit/mozapps/update/Makefile.in b/toolkit/mozapps/update/Makefile.in index a143f15334bb..752647bbad05 100644 --- a/toolkit/mozapps/update/Makefile.in +++ b/toolkit/mozapps/update/Makefile.in @@ -77,14 +77,12 @@ endif endif endif -ifdef ENABLE_TESTS -DIRS += test_timermanager +TEST_DIRS += test_timermanager # Update tests require the updater binary ifdef MOZ_UPDATER -DIRS += test +TEST_DIRS += test ifdef MOZ_MAINTENANCE_SERVICE -DIRS += test_svc -endif +TEST_DIRS += test_svc endif endif From f16639be0acd683ba0ec6e2cd55e7ec6c238cda4 Mon Sep 17 00:00:00 2001 From: Matt Brubeck Date: Fri, 10 Feb 2012 13:21:32 -0800 Subject: [PATCH 30/34] Bug 723156 - Fix the back button for new windows opened by frames [r=mfinkle] --- mobile/android/chrome/content/browser.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mobile/android/chrome/content/browser.js b/mobile/android/chrome/content/browser.js index a3b7936eb1a0..d819ab0d6726 100644 --- a/mobile/android/chrome/content/browser.js +++ b/mobile/android/chrome/content/browser.js @@ -1379,7 +1379,7 @@ nsBrowserAccess.prototype = { let parentId = -1; if (newTab && !isExternal) { - let parent = BrowserApp.getTabForBrowser(BrowserApp.getBrowserForWindow(aOpener)); + let parent = BrowserApp.getTabForBrowser(BrowserApp.getBrowserForWindow(aOpener.top)); if (parent) parentId = parent.id; } From 79c7218755455fd00bca7c12ab2dea172106b144 Mon Sep 17 00:00:00 2001 From: Trevor Saunders Date: Fri, 10 Feb 2012 16:39:20 -0500 Subject: [PATCH 31/34] bug 672507 - fix review nits r=davidb --- accessible/src/base/nsAccessNode.h | 6 ------ 1 file changed, 6 deletions(-) diff --git a/accessible/src/base/nsAccessNode.h b/accessible/src/base/nsAccessNode.h index 839b96f430e3..6153953f75e9 100644 --- a/accessible/src/base/nsAccessNode.h +++ b/accessible/src/base/nsAccessNode.h @@ -161,12 +161,6 @@ public: */ virtual bool IsPrimaryForNode() const; - /** - * Return the string bundle - */ - static nsIStringBundle* GetStringBundle() - { return gStringBundle; } - /** * Interface methods on nsIAccessible shared with ISimpleDOM. */ From 5f37d215709b71f3d9536d27fdc254ffc4b0bb15 Mon Sep 17 00:00:00 2001 From: Wes Johnston Date: Fri, 10 Feb 2012 14:01:44 -0800 Subject: [PATCH 32/34] Bug 725858 - Don't load sqlite for migration if we're not migrating. r=gcp --- mobile/android/base/GeckoApp.java | 8 ++++---- mobile/android/base/ProfileMigrator.java | 1 + 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/mobile/android/base/GeckoApp.java b/mobile/android/base/GeckoApp.java index 47f02b82120b..875f554aee5a 100644 --- a/mobile/android/base/GeckoApp.java +++ b/mobile/android/base/GeckoApp.java @@ -2328,21 +2328,21 @@ abstract public class GeckoApp private void checkMigrateProfile() { File profileDir = getProfileDir(); + long currentTime = SystemClock.uptimeMillis(); + if (profileDir != null) { - long currentTime = SystemClock.uptimeMillis(); Log.i(LOGTAG, "checking profile migration in: " + profileDir.getAbsolutePath()); final GeckoApp app = GeckoApp.mAppContext; final SetupScreen setupScreen = new SetupScreen(app); // don't show unless we take a while setupScreen.showDelayed(mMainHandler); - GeckoAppShell.ensureSQLiteLibsLoaded(app.getApplication().getPackageResourcePath()); ProfileMigrator profileMigrator = new ProfileMigrator(app.getContentResolver(), profileDir); profileMigrator.launch(); setupScreen.dismiss(); - long timeDiff = SystemClock.uptimeMillis() - currentTime; - Log.i(LOGTAG, "Profile migration took " + timeDiff + " ms"); } + long timeDiff = SystemClock.uptimeMillis() - currentTime; + Log.i(LOGTAG, "Profile migration took " + timeDiff + " ms"); } private SynchronousQueue mFilePickerResult = new SynchronousQueue(); diff --git a/mobile/android/base/ProfileMigrator.java b/mobile/android/base/ProfileMigrator.java index b3b769de2cd6..1e444a53034a 100644 --- a/mobile/android/base/ProfileMigrator.java +++ b/mobile/android/base/ProfileMigrator.java @@ -280,6 +280,7 @@ public class ProfileMigrator { File dbFileShm = new File(dbPathShm); SQLiteBridge db = null; + GeckoAppShell.ensureSQLiteLibsLoaded(GeckoApp.mAppContext.getApplication().getPackageResourcePath()); try { db = new SQLiteBridge(dbPath); migrateBookmarks(db); From 6da5005271741a5e6c5f3ab0682246f4e1d76198 Mon Sep 17 00:00:00 2001 From: Oleg Romashin Date: Fri, 10 Feb 2012 11:22:21 -0800 Subject: [PATCH 33/34] Bug 725925 - ShadowableThebesLayer does useless extra composite into 1x1 fake surface. r=cjones --HG-- extra : rebase_source : 517e8624b3da7f83fbb786c10acb45e02f7b5be9 --- gfx/layers/basic/BasicLayers.cpp | 28 ++++++++++++++++++---------- widget/xpwidgets/PuppetWidget.cpp | 2 ++ 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/gfx/layers/basic/BasicLayers.cpp b/gfx/layers/basic/BasicLayers.cpp index 3a8252f2f28c..6334e4b6d7b4 100644 --- a/gfx/layers/basic/BasicLayers.cpp +++ b/gfx/layers/basic/BasicLayers.cpp @@ -763,7 +763,9 @@ BasicThebesLayer::PaintThebes(gfxContext* aContext, if (BasicManager()->IsTransactionIncomplete()) return; - if (!IsHidden()) { + gfxRect clipExtents; + clipExtents = aContext->GetClipExtents(); + if (!IsHidden() && clipExtents.IsEmpty()) { AutoSetOperator setOperator(aContext, GetOperator()); mBuffer.DrawTo(this, aContext, opacity); } @@ -1946,16 +1948,22 @@ BasicLayerManager::PaintLayer(gfxContext* aTarget, NS_ABORT_IF_FALSE(untransformedSurface, "We should always allocate an untransformed surface with 3d transforms!"); - gfxPoint offset; - bool dontBlit = needsClipToVisibleRegion || mTransactionIncomplete || - aLayer->GetEffectiveOpacity() != 1.0f; - nsRefPtr result = - Transform3D(untransformedSurface, aTarget, bounds, - effectiveTransform, offset, dontBlit); + // Temporary fast fix for bug 725886 + // Revert these changes when 725886 is ready + gfxRect clipExtents; + clipExtents = aTarget->GetClipExtents(); + if (!clipExtents.IsEmpty()) { + gfxPoint offset; + bool dontBlit = needsClipToVisibleRegion || mTransactionIncomplete || + aLayer->GetEffectiveOpacity() != 1.0f; + nsRefPtr result = + Transform3D(untransformedSurface, aTarget, bounds, + effectiveTransform, offset, dontBlit); - blitComplete = !result; - if (result) { - aTarget->SetSource(result, offset); + blitComplete = !result; + if (result) { + aTarget->SetSource(result, offset); + } } } // If we're doing our own double-buffering, we need to avoid drawing diff --git a/widget/xpwidgets/PuppetWidget.cpp b/widget/xpwidgets/PuppetWidget.cpp index 9327c6deff9a..1657802dfb9e 100644 --- a/widget/xpwidgets/PuppetWidget.cpp +++ b/widget/xpwidgets/PuppetWidget.cpp @@ -530,6 +530,8 @@ PuppetWidget::DispatchPaintEvent() DispatchEvent(&event, status); } else { nsRefPtr ctx = new gfxContext(mSurface); + ctx->Rectangle(gfxRect(0,0,0,0)); + ctx->Clip(); AutoLayerManagerSetup setupLayerManager(this, ctx, BasicLayerManager::BUFFER_NONE); DispatchEvent(&event, status); From 07729f9d3d98225a41f46f67c1975392b3779cae Mon Sep 17 00:00:00 2001 From: Ed Morley Date: Fri, 10 Feb 2012 23:23:16 +0000 Subject: [PATCH 34/34] Backout b43f4d9f38da (bug 725925) for reftest failures --- gfx/layers/basic/BasicLayers.cpp | 28 ++++++++++------------------ widget/xpwidgets/PuppetWidget.cpp | 2 -- 2 files changed, 10 insertions(+), 20 deletions(-) diff --git a/gfx/layers/basic/BasicLayers.cpp b/gfx/layers/basic/BasicLayers.cpp index 6334e4b6d7b4..3a8252f2f28c 100644 --- a/gfx/layers/basic/BasicLayers.cpp +++ b/gfx/layers/basic/BasicLayers.cpp @@ -763,9 +763,7 @@ BasicThebesLayer::PaintThebes(gfxContext* aContext, if (BasicManager()->IsTransactionIncomplete()) return; - gfxRect clipExtents; - clipExtents = aContext->GetClipExtents(); - if (!IsHidden() && clipExtents.IsEmpty()) { + if (!IsHidden()) { AutoSetOperator setOperator(aContext, GetOperator()); mBuffer.DrawTo(this, aContext, opacity); } @@ -1948,22 +1946,16 @@ BasicLayerManager::PaintLayer(gfxContext* aTarget, NS_ABORT_IF_FALSE(untransformedSurface, "We should always allocate an untransformed surface with 3d transforms!"); - // Temporary fast fix for bug 725886 - // Revert these changes when 725886 is ready - gfxRect clipExtents; - clipExtents = aTarget->GetClipExtents(); - if (!clipExtents.IsEmpty()) { - gfxPoint offset; - bool dontBlit = needsClipToVisibleRegion || mTransactionIncomplete || - aLayer->GetEffectiveOpacity() != 1.0f; - nsRefPtr result = - Transform3D(untransformedSurface, aTarget, bounds, - effectiveTransform, offset, dontBlit); + gfxPoint offset; + bool dontBlit = needsClipToVisibleRegion || mTransactionIncomplete || + aLayer->GetEffectiveOpacity() != 1.0f; + nsRefPtr result = + Transform3D(untransformedSurface, aTarget, bounds, + effectiveTransform, offset, dontBlit); - blitComplete = !result; - if (result) { - aTarget->SetSource(result, offset); - } + blitComplete = !result; + if (result) { + aTarget->SetSource(result, offset); } } // If we're doing our own double-buffering, we need to avoid drawing diff --git a/widget/xpwidgets/PuppetWidget.cpp b/widget/xpwidgets/PuppetWidget.cpp index 1657802dfb9e..9327c6deff9a 100644 --- a/widget/xpwidgets/PuppetWidget.cpp +++ b/widget/xpwidgets/PuppetWidget.cpp @@ -530,8 +530,6 @@ PuppetWidget::DispatchPaintEvent() DispatchEvent(&event, status); } else { nsRefPtr ctx = new gfxContext(mSurface); - ctx->Rectangle(gfxRect(0,0,0,0)); - ctx->Clip(); AutoLayerManagerSetup setupLayerManager(this, ctx, BasicLayerManager::BUFFER_NONE); DispatchEvent(&event, status);