b=429915, color mismatch with 1x1 images (SetColor API broken) ; r=stuart, a=damon
authorvladimir@pobox.com
Mon, 28 Apr 2008 14:27:05 -0700
changeset 14741 0144e86f24bb3606fe198ce2f3971f724a402b16
parent 14740 1191accca3ee77f8102bdb8483caf4d6b03d20bf
child 14742 a9427f4d2aae5deae8881cd0bfd878c26af592af
push idunknown
push userunknown
push dateunknown
reviewersstuart, damon
bugs429915
milestone1.9pre
b=429915, color mismatch with 1x1 images (SetColor API broken) ; r=stuart, a=damon
gfx/src/thebes/nsThebesImage.cpp
gfx/src/thebes/nsThebesRenderingContext.cpp
gfx/thebes/public/gfxContext.h
gfx/thebes/src/gfxContext.cpp
gfx/thebes/src/gfxFont.cpp
gfx/thebes/src/gfxFontMissingGlyphs.cpp
--- a/gfx/src/thebes/nsThebesImage.cpp
+++ b/gfx/src/thebes/nsThebesImage.cpp
@@ -374,17 +374,17 @@ nsThebesImage::LockImagePixels(PRBool aM
         // Recover the pixels
         mImageSurface = new gfxImageSurface(gfxIntSize(mWidth, mHeight),
                                             gfxImageSurface::ImageFormatARGB32);
         if (!mImageSurface || mImageSurface->CairoStatus())
             return NS_ERROR_OUT_OF_MEMORY;
         gfxContext context(mImageSurface);
         context.SetOperator(gfxContext::OPERATOR_SOURCE);
         if (mSinglePixel)
-            context.SetColor(mSinglePixelColor);
+            context.SetDeviceColor(mSinglePixelColor);
         else
             context.SetSource(mOptSurface);
         context.Paint();
 
 #ifdef XP_WIN
         mWinSurface = nsnull;
 #endif
 #ifdef XP_MACOSX
@@ -436,17 +436,17 @@ nsThebesImage::Draw(nsIRenderingContext 
         if (mSinglePixelColor.a == 0.0)
             return NS_OK;
 
         // otherwise
         gfxContext::GraphicsOperator op = ctx->CurrentOperator();
         if (op == gfxContext::OPERATOR_OVER && mSinglePixelColor.a == 1.0)
             ctx->SetOperator(gfxContext::OPERATOR_SOURCE);
 
-        ctx->SetColor(mSinglePixelColor);
+        ctx->SetDeviceColor(mSinglePixelColor);
         ctx->NewPath();
         ctx->Rectangle(aDestRect, PR_TRUE);
         ctx->Fill();
         ctx->SetOperator(op);
         return NS_OK;
     }
 
     gfxFloat xscale = aDestRect.size.width / aSourceRect.size.width;
@@ -605,17 +605,17 @@ nsThebesImage::Draw(nsIRenderingContext 
         ctx->SetOperator(gfxContext::OPERATOR_SOURCE);
 
     ctx->NewPath();
     ctx->SetPattern(pat);
     ctx->Rectangle(destRect);
     ctx->Fill();
 
     ctx->SetOperator(op);
-    ctx->SetColor(gfxRGBA(0,0,0,0));
+    ctx->SetDeviceColor(gfxRGBA(0,0,0,0));
 
     return NS_OK;
 }
 
 nsresult
 nsThebesImage::ThebesDrawTile(gfxContext *thebesContext,
                               nsIDeviceContext* dx,
                               const gfxPoint& offset,
@@ -635,17 +635,17 @@ nsThebesImage::ThebesDrawTile(gfxContext
 
     PRBool doSnap = !(thebesContext->CurrentMatrix().HasNonTranslation());
     PRBool hasPadding = ((xPadding != 0) || (yPadding != 0));
     gfxImageSurface::gfxImageFormat format = mFormat;
     
     gfxPoint tmpOffset = offset;
 
     if (mSinglePixel && !hasPadding) {
-        thebesContext->SetColor(mSinglePixelColor);
+        thebesContext->SetDeviceColor(mSinglePixelColor);
     } else {
         nsRefPtr<gfxASurface> surface;
         PRInt32 width, height;
 
         if (hasPadding) {
             /* Ugh we have padding; create a temporary surface that's the size of the surface + pad area,
              * and render the image into it first.  Then we'll tile that surface. */
             width = mWidth + xPadding;
@@ -659,17 +659,17 @@ nsThebesImage::ThebesDrawTile(gfxContext
             surface = gfxPlatform::GetPlatform()->CreateOffscreenSurface(
                     gfxIntSize(width, height), format);
             if (!surface || surface->CairoStatus()) {
                 return NS_ERROR_OUT_OF_MEMORY;
             }
 
             gfxContext tmpContext(surface);
             if (mSinglePixel) {
-                tmpContext.SetColor(mSinglePixelColor);
+                tmpContext.SetDeviceColor(mSinglePixelColor);
             } else {
                 tmpContext.SetSource(ThebesSurface());
             }
             tmpContext.SetOperator(gfxContext::OPERATOR_SOURCE);
             tmpContext.Rectangle(gfxRect(0, 0, mWidth, mHeight));
             tmpContext.Fill();
         } else {
             width = mWidth;
@@ -797,17 +797,17 @@ nsThebesImage::ThebesDrawTile(gfxContext
     if (op == gfxContext::OPERATOR_OVER && format == gfxASurface::ImageFormatRGB24)
         thebesContext->SetOperator(gfxContext::OPERATOR_SOURCE);
 
     thebesContext->NewPath();
     thebesContext->Rectangle(targetRect, doSnap);
     thebesContext->Fill();
 
     thebesContext->SetOperator(op);
-    thebesContext->SetColor(gfxRGBA(0,0,0,0));
+    thebesContext->SetDeviceColor(gfxRGBA(0,0,0,0));
 
     return NS_OK;
 }
 
 PRBool
 nsThebesImage::ShouldUseImageSurfaces()
 {
 #ifdef XP_WIN
--- a/gfx/src/thebes/nsThebesRenderingContext.cpp
+++ b/gfx/src/thebes/nsThebesRenderingContext.cpp
@@ -343,16 +343,19 @@ nsThebesRenderingContext::SetLineStyle(n
     return NS_OK;
 }
 
 
 NS_IMETHODIMP
 nsThebesRenderingContext::SetColor(nscolor aColor)
 {
     PR_LOG(gThebesGFXLog, PR_LOG_DEBUG, ("## %p nsTRC::SetColor 0x%08x\n", this, aColor));
+    /* This sets the color assuming the sRGB color space, since that's what all
+     * CSS colors are defined to be in by the spec.
+     */
     mThebes->SetColor(gfxRGBA(aColor));
     
     mColor = aColor;
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsThebesRenderingContext::GetColor(nscolor &aColor) const
--- a/gfx/thebes/public/gfxContext.h
+++ b/gfx/thebes/public/gfxContext.h
@@ -309,26 +309,34 @@ public:
      */
     void PixelSnappedRectangleAndSetPattern(const gfxRect& rect, gfxPattern *pattern);
 
     /**
      ** Painting sources
      **/
 
     /**
-     * Uses a solid color for drawing.
+     * Set a solid color to use for drawing.  This color is in the device color space
+     * and is not transformed.
      */
-    void SetColor(const gfxRGBA& c);
+    void SetDeviceColor(const gfxRGBA& c);
 
     /**
-     * Gets the current color.
+     * Gets the current color.  It's returned in the device color space.
      * returns PR_FALSE if there is something other than a color
      *         set as the current source (pattern, surface, etc)
      */
-    PRBool GetColor(gfxRGBA& c);
+    PRBool GetDeviceColor(gfxRGBA& c);
+
+    /**
+     * Set a solid color in the sRGB color space to use for drawing.
+     * If CMS is not enabled, the color is treated as a device-space color
+     * and this call is identical to SetDeviceColor().
+     */
+    void SetColor(const gfxRGBA& c);
 
     /**
      * Uses a surface for drawing. This is a shorthand for creating a
      * pattern and setting it.
      *
      * @param offset ?
      */
     void SetSource(gfxASurface *surface, const gfxPoint& offset = gfxPoint(0.0, 0.0));
--- a/gfx/thebes/src/gfxContext.cpp
+++ b/gfx/thebes/src/gfxContext.cpp
@@ -640,18 +640,24 @@ gfxContext::SetColor(const gfxRGBA& c)
             cairo_set_source_rgba(mCairo, cms.r, cms.g, cms.b, cms.a);
             return;
         }
     }
 
     cairo_set_source_rgba(mCairo, c.r, c.g, c.b, c.a);
 }
 
+void
+gfxContext::SetDeviceColor(const gfxRGBA& c)
+{
+    cairo_set_source_rgba(mCairo, c.r, c.g, c.b, c.a);
+}
+
 PRBool
-gfxContext::GetColor(gfxRGBA& c)
+gfxContext::GetDeviceColor(gfxRGBA& c)
 {
     return cairo_pattern_get_rgba(cairo_get_source(mCairo),
                                   &c.r,
                                   &c.g,
                                   &c.b,
                                   &c.a) == CAIRO_STATUS_SUCCESS;
 }
 
--- a/gfx/thebes/src/gfxFont.cpp
+++ b/gfx/thebes/src/gfxFont.cpp
@@ -1395,17 +1395,17 @@ HasSyntheticBold(gfxTextRun *aRun, PRUin
     return PR_FALSE;
 }
 
 // returns true if color is non-opaque (i.e. alpha != 1.0) or completely transparent, false otherwise
 // if true, color is set on output
 static PRBool
 HasNonOpaqueColor(gfxContext *aContext, gfxRGBA& aCurrentColor)
 {
-    if (aContext->GetColor(aCurrentColor)) {
+    if (aContext->GetDeviceColor(aCurrentColor)) {
         if (aCurrentColor.a < 1.0 && aCurrentColor.a > 0.0) {
             return PR_TRUE;
         }
     }
         
     return PR_FALSE;
 }
 
--- a/gfx/thebes/src/gfxFontMissingGlyphs.cpp
+++ b/gfx/thebes/src/gfxFontMissingGlyphs.cpp
@@ -195,17 +195,17 @@ DrawHexChar(gfxContext *aContext, const 
 
 void
 gfxFontMissingGlyphs::DrawMissingGlyph(gfxContext *aContext, const gfxRect& aRect,
                                        PRUint32 aChar)
 {
     aContext->Save();
 
     gfxRGBA currentColor;
-    if (!aContext->GetColor(currentColor)) {
+    if (!aContext->GetDeviceColor(currentColor)) {
         // We're currently drawing with some kind of pattern... Just draw
         // the missing-glyph data in black.
         currentColor = gfxRGBA(0,0,0,1);
     }
 
     // Stroke a rectangle so that the stroke's left edge is inset one pixel
     // from the left edge of the glyph box and the stroke's right edge
     // is inset one pixel from the right edge of the glyph box.
@@ -216,46 +216,46 @@ gfxFontMissingGlyphs::DrawMissingGlyph(g
                              borderRight - borderLeft, aRect.Height() - 2*halfBorderWidth);
     if (!borderStrokeRect.IsEmpty()) {
         aContext->SetLineWidth(BOX_BORDER_WIDTH);
         aContext->SetDash(gfxContext::gfxLineSolid);
         aContext->SetLineCap(gfxContext::LINE_CAP_SQUARE);
         aContext->SetLineJoin(gfxContext::LINE_JOIN_MITER);
         gfxRGBA color = currentColor;
         color.a *= BOX_BORDER_OPACITY;
-        aContext->SetColor(color);
+        aContext->SetDeviceColor(color);
         aContext->NewPath();
         aContext->Rectangle(borderStrokeRect);
         aContext->Stroke();
     }
 
     gfxPoint center(aRect.X() + aRect.Width()/2,
                     aRect.Y() + aRect.Height()/2);
     gfxFloat halfGap = HEX_CHAR_GAP/2.0;
     gfxFloat top = -(MINIFONT_HEIGHT + halfGap);
     if (aChar < 0x10000) {
         if (aRect.Width() >= 2*MINIFONT_WIDTH + HEX_CHAR_GAP &&
             aRect.Height() >= 2*MINIFONT_HEIGHT + HEX_CHAR_GAP) {
             // Draw 4 digits for BMP
-            aContext->SetColor(currentColor);
+            aContext->SetDeviceColor(currentColor);
             gfxFloat left = -(MINIFONT_WIDTH + halfGap);
             DrawHexChar(aContext,
                         center + gfxPoint(left, top), (aChar >> 12) & 0xF);
             DrawHexChar(aContext,
                         center + gfxPoint(halfGap, top), (aChar >> 8) & 0xF);
             DrawHexChar(aContext,
                         center + gfxPoint(left, halfGap), (aChar >> 4) & 0xF);
             DrawHexChar(aContext,
                         center + gfxPoint(halfGap, halfGap), aChar & 0xF);
         }
     } else {
         if (aRect.Width() >= 3*MINIFONT_WIDTH + 2*HEX_CHAR_GAP &&
             aRect.Height() >= 2*MINIFONT_HEIGHT + HEX_CHAR_GAP) {
             // Draw 6 digits for non-BMP
-            aContext->SetColor(currentColor);
+            aContext->SetDeviceColor(currentColor);
             gfxFloat first = -(MINIFONT_WIDTH * 1.5 + HEX_CHAR_GAP);
             gfxFloat second = -(MINIFONT_WIDTH / 2.0);
             gfxFloat third = (MINIFONT_WIDTH / 2.0 + HEX_CHAR_GAP);
             DrawHexChar(aContext,
                         center + gfxPoint(first, top), (aChar >> 20) & 0xF);
             DrawHexChar(aContext,
                         center + gfxPoint(second, top), (aChar >> 16) & 0xF);
             DrawHexChar(aContext,