Commit af5f98b2 authored by bdakin's avatar bdakin

Reviewed by Darin.

        Fix for <rdar://problem/4567520> Pixel cracks in weather widget at 
        1.83 scaling

        To prevent pixel cracks at non-integral scaling factors, before we 
        call into CG to draw an image, we have to convert the rect to 
        device space, round the origin and size to integers in device 
        space, and convert back to user space. 
        
        No test cases added since this only affects non-1.0 resolution 
        scale factors.

        * bindings/js/JSCanvasRenderingContext2DCustom.cpp:
        (WebCore::JSCanvasRenderingContext2D::drawImage): drawImage() now 
        takes FloatRects.
        * html/CanvasPattern.cpp:
        (WebCore::patternCallback): Call roundToDevicePixels()
        * html/CanvasRenderingContext2D.cpp:
        (WebCore::CanvasRenderingContext2D::drawImage): drawImage() now 
        takes FloatRects and call roundToDevicePixels()
        * html/CanvasRenderingContext2D.h: drawImage() now takes 
        FloatRects.
        * html/HTMLCanvasElement.cpp:
        (WebCore::HTMLCanvasElement::paint): Call roundToDevicePixels()
        * kcanvas/device/quartz/QuartzSupport.mm:
        (WebCore::debugDumpCGImageToFile): Same as above.
        * platform/GraphicsContext.h:
        * platform/cg/GraphicsContextCG.cpp:
        (WebCore::GraphicsContext::roundToDevicePixels): Takes care of 
        converting between coordinate spaces and rounding.
        (WebCore::GraphicsContext::drawLineForText):
        * platform/mac/ImageMac.mm: Call roundToDevicePixels()
        (WebCore::Image::draw): Same as above.
        (WebCore::drawPattern): Same as above.


git-svn-id: http://svn.webkit.org/repository/webkit/trunk@14739 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent 0f15b235
2006-06-05 Beth Dakin <bdakin@apple.com>
Reviewed by Darin.
Fix for <rdar://problem/4567520> Pixel cracks in weather widget at
1.83 scaling
To prevent pixel cracks at non-integral scaling factors, before we
call into CG to draw an image, we have to convert the rect to
device space, round the origin and size to integers in device
space, and convert back to user space.
No test cases added since this only affects non-1.0 resolution
scale factors.
* bindings/js/JSCanvasRenderingContext2DCustom.cpp:
(WebCore::JSCanvasRenderingContext2D::drawImage): drawImage() now
takes FloatRects.
* html/CanvasPattern.cpp:
(WebCore::patternCallback): Call roundToDevicePixels()
* html/CanvasRenderingContext2D.cpp:
(WebCore::CanvasRenderingContext2D::drawImage): drawImage() now
takes FloatRects and call roundToDevicePixels()
* html/CanvasRenderingContext2D.h: drawImage() now takes
FloatRects.
* html/HTMLCanvasElement.cpp:
(WebCore::HTMLCanvasElement::paint): Call roundToDevicePixels()
* kcanvas/device/quartz/QuartzSupport.mm:
(WebCore::debugDumpCGImageToFile): Same as above.
* platform/GraphicsContext.h:
* platform/cg/GraphicsContextCG.cpp:
(WebCore::GraphicsContext::roundToDevicePixels): Takes care of
converting between coordinate spaces and rounding.
(WebCore::GraphicsContext::drawLineForText):
* platform/mac/ImageMac.mm: Call roundToDevicePixels()
(WebCore::Image::draw): Same as above.
(WebCore::drawPattern): Same as above.
2006-06-05 Geoffrey Garen <ggaren@apple.com>
Reviewed by Darin.
......
......@@ -23,6 +23,7 @@
#include "CanvasRenderingContext2D.h"
#include "CanvasStyle.h"
#include "ExceptionCode.h"
#include "FloatRect.h"
#include "HTMLCanvasElement.h"
#include "HTMLImageElement.h"
#include "JSCanvasGradient.h"
......@@ -196,10 +197,10 @@ JSValue* JSCanvasRenderingContext2D::drawImage(ExecState* exec, const List& args
setDOMException(exec, ec);
break;
case 9:
context->drawImage(imgElt, args[1]->toNumber(exec), args[2]->toNumber(exec),
args[3]->toNumber(exec), args[4]->toNumber(exec),
args[5]->toNumber(exec), args[6]->toNumber(exec),
args[7]->toNumber(exec), args[8]->toNumber(exec), ec);
context->drawImage(imgElt, FloatRect(args[1]->toNumber(exec), args[2]->toNumber(exec),
args[3]->toNumber(exec), args[4]->toNumber(exec)),
FloatRect(args[5]->toNumber(exec), args[6]->toNumber(exec),
args[7]->toNumber(exec), args[8]->toNumber(exec)), ec);
setDOMException(exec, ec);
break;
default:
......@@ -217,10 +218,10 @@ JSValue* JSCanvasRenderingContext2D::drawImage(ExecState* exec, const List& args
setDOMException(exec, ec);
break;
case 9:
context->drawImage(canvas, args[1]->toNumber(exec), args[2]->toNumber(exec),
args[3]->toNumber(exec), args[4]->toNumber(exec),
args[5]->toNumber(exec), args[6]->toNumber(exec),
args[7]->toNumber(exec), args[8]->toNumber(exec), ec);
context->drawImage(canvas, FloatRect(args[1]->toNumber(exec), args[2]->toNumber(exec),
args[3]->toNumber(exec), args[4]->toNumber(exec)),
FloatRect(args[5]->toNumber(exec), args[6]->toNumber(exec),
args[7]->toNumber(exec), args[8]->toNumber(exec)), ec);
setDOMException(exec, ec);
break;
default:
......
......@@ -104,7 +104,8 @@ static void patternCallback(void* info, CGContextRef context)
{
CGImageRef platformImage = static_cast<CanvasPattern*>(info)->platformImage();
if (platformImage) {
CGRect rect = CGRectMake(0, 0, CGImageGetWidth(platformImage), CGImageGetHeight(platformImage));
CGRect rect = GraphicsContext(context).roundToDevicePixels(
FloatRect(0, 0, CGImageGetWidth(platformImage), CGImageGetHeight(platformImage)));
CGContextDrawImage(context, rect, platformImage);
return;
}
......@@ -116,7 +117,7 @@ static void patternCallback(void* info, CGContextRef context)
if (!image)
return;
FloatRect rect = image->rect();
FloatRect rect = GraphicsContext(context).roundToDevicePixels(image->rect());
if (image->getCGImageRef()) {
CGContextDrawImage(context, rect, image->getCGImageRef());
......
......@@ -729,34 +729,34 @@ void CanvasRenderingContext2D::drawImage(HTMLImageElement* image,
{
ASSERT(image);
IntSize s = size(image);
drawImage(image, 0, 0, s.width(), s.height(), x, y, width, height, ec);
drawImage(image, FloatRect(0, 0, s.width(), s.height()), FloatRect(x, y, width, height), ec);
}
void CanvasRenderingContext2D::drawImage(HTMLImageElement* image,
float sx, float sy, float sw, float sh,
float dx, float dy, float dw, float dh, ExceptionCode& ec)
void CanvasRenderingContext2D::drawImage(HTMLImageElement* image, const FloatRect& srcRect, const FloatRect& dstRect,
ExceptionCode& ec)
{
ASSERT(image);
GraphicsContext* c = drawingContext();
if (!c)
return;
ec = 0;
FloatRect imageRect = FloatRect(FloatPoint(), size(image));
FloatRect sourceRect = FloatRect(sx, sy, sw, sh);
FloatRect sourceRect = c->roundToDevicePixels(srcRect);
FloatRect destRect = c->roundToDevicePixels(dstRect);
if (!(imageRect.contains(sourceRect) && sw > 0 && sh > 0 && dw > 0 && dh > 0)) {
if (!(imageRect.contains(sourceRect) && sourceRect.width() > 0 && sourceRect.height() > 0
&& destRect.width() > 0 && destRect.height() > 0)) {
ec = INDEX_SIZE_ERR;
return;
}
GraphicsContext* c = drawingContext();
if (!c)
return;
CachedImage* cachedImage = image->cachedImage();
if (!cachedImage)
return;
FloatRect destRect = FloatRect(dx, dy, dw, dh);
willDraw(destRect);
c->drawImage(cachedImage->image(), destRect, sourceRect, state().m_globalComposite);
}
......@@ -772,18 +772,17 @@ void CanvasRenderingContext2D::drawImage(HTMLCanvasElement* canvas,
float x, float y, float width, float height, ExceptionCode& ec)
{
ASSERT(canvas);
drawImage(canvas, 0, 0, canvas->width(), canvas->height(), x, y, width, height, ec);
drawImage(canvas, FloatRect(0, 0, canvas->width(), canvas->height()), FloatRect(x, y, width, height), ec);
}
void CanvasRenderingContext2D::drawImage(HTMLCanvasElement* canvas,
float sx, float sy, float sw, float sh,
float dx, float dy, float dw, float dh, ExceptionCode& ec)
void CanvasRenderingContext2D::drawImage(HTMLCanvasElement* canvas, const FloatRect& srcRect,
const FloatRect& dstRect, ExceptionCode& ec)
{
ASSERT(canvas);
ec = 0;
if (!(sw > 0 && sh > 0 && dw > 0 && dh > 0)) {
if (srcRect.isEmpty() || dstRect.isEmpty()) {
ec = INDEX_SIZE_ERR;
return;
}
......@@ -794,26 +793,29 @@ void CanvasRenderingContext2D::drawImage(HTMLCanvasElement* canvas,
GraphicsContext* c = drawingContext();
if (!c)
return;
FloatRect sourceRect = c->roundToDevicePixels(srcRect);
FloatRect destRect = c->roundToDevicePixels(dstRect);
// FIXME: Do this through platform-independent GraphicsContext API.
#if __APPLE__
CGImageRef platformImage = canvas->createPlatformImage();
if (!platformImage)
return;
FloatRect destRect = FloatRect(dx, dy, dw, dh);
willDraw(destRect);
float iw = CGImageGetWidth(platformImage);
float ih = CGImageGetHeight(platformImage);
if (sx == 0 && sy == 0 && iw == sw && ih == sh) {
if (sourceRect.x() == 0 && sourceRect.y() == 0 && iw == sourceRect.width() && ih == sourceRect.height()) {
// Fast path, yay!
CGContextDrawImage(c->platformContext(), CGRectMake(dx, dy, dw, dh), platformImage);
CGContextDrawImage(c->platformContext(), destRect, platformImage);
} else {
// Slow path, boo!
// Create a new bitmap of the appropriate size and then draw that into our context.
size_t csw = static_cast<size_t>(ceilf(sw));
size_t csh = static_cast<size_t>(ceilf(sh));
size_t csw = static_cast<size_t>(ceilf(sourceRect.width()));
size_t csh = static_cast<size_t>(ceilf(sourceRect.height()));
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
size_t bytesPerRow = csw * 4;
......@@ -822,13 +824,13 @@ void CanvasRenderingContext2D::drawImage(HTMLCanvasElement* canvas,
CGContextRef clippedSourceContext = CGBitmapContextCreate(buffer, csw, csh,
8, bytesPerRow, colorSpace, kCGImageAlphaPremultipliedLast);
CGColorSpaceRelease(colorSpace);
CGContextTranslateCTM(clippedSourceContext, -sx, -sy);
CGContextTranslateCTM(clippedSourceContext, -sourceRect.x(), -sourceRect.y());
CGContextDrawImage(clippedSourceContext, CGRectMake(0, 0, iw, ih), platformImage);
CGImageRef clippedSourceImage = CGBitmapContextCreateImage(clippedSourceContext);
CGContextRelease(clippedSourceContext);
CGContextDrawImage(c->platformContext(), CGRectMake(dx, dy, dw, dh), clippedSourceImage);
CGContextDrawImage(c->platformContext(), destRect, clippedSourceImage);
CGImageRelease(clippedSourceImage);
fastFree(buffer);
......
......@@ -143,12 +143,10 @@ namespace WebCore {
void drawImage(HTMLImageElement*, float x, float y);
void drawImage(HTMLImageElement*, float x, float y, float width, float height, ExceptionCode&);
void drawImage(HTMLImageElement*, float sx, float sy, float sw, float sh,
float dx, float dy, float dw, float dh, ExceptionCode&);
void drawImage(HTMLImageElement*, const FloatRect& srcRect, const FloatRect& dstRect, ExceptionCode&);
void drawImage(HTMLCanvasElement*, float x, float y);
void drawImage(HTMLCanvasElement*, float x, float y, float width, float height, ExceptionCode&);
void drawImage(HTMLCanvasElement*, float sx, float sy, float sw, float sh,
float dx, float dy, float dw, float dh, ExceptionCode&);
void drawImage(HTMLCanvasElement*, const FloatRect& srcRect, const FloatRect& dstRect, ExceptionCode&);
void drawImageFromRect(HTMLImageElement*, float sx, float sy, float sw, float sh,
float dx, float dy, float dw, float dh, const String& compositeOperation);
......
......@@ -138,7 +138,7 @@ void HTMLCanvasElement::paint(GraphicsContext* p, const IntRect& r)
return;
#if __APPLE__
if (CGImageRef image = createPlatformImage()) {
CGContextDrawImage(p->platformContext(), r, image);
CGContextDrawImage(p->platformContext(), p->roundToDevicePixels(r), image);
CGImageRelease(image);
}
#endif
......
......@@ -28,6 +28,7 @@
#if SVG_SUPPORT
#import "QuartzSupport.h"
#import "GraphicsContext.h"
#import "KCanvasMatrix.h"
#import "KCanvasResourcesQuartz.h"
#import "KRenderingFillPainter.h"
......@@ -47,7 +48,8 @@ void debugDumpCGImageToFile(NSString *filename, CGImageRef image, int width, int
NSImage *fileImage = [[NSImage alloc] initWithSize:NSMakeSize(width, height)];
[fileImage lockFocus];
CGContextRef fileImageContext = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];
CGContextDrawImage(fileImageContext, CGRectMake(0, 0, width, height), image);
CGContextDrawImage(fileImageContext, GraphicsContext(fileImageContext).roundToDevicePixels(
FloatRect(0, 0, width, height)), image);
[fileImage unlockFocus];
NSData *tiff = [fileImage TIFFRepresentation];
[tiff writeToFile:filename atomically:YES];
......
......@@ -116,6 +116,8 @@ namespace WebCore {
void drawText(const TextRun&, const IntPoint&, const TextStyle& = TextStyle());
void drawHighlightForText(const TextRun&, const IntPoint&, int h, const TextStyle&, const Color& backgroundColor);
FloatRect roundToDevicePixels(const FloatRect&);
void drawLineForText(const IntPoint&, int yOffset, int width, bool printing);
void drawLineForMisspelling(const IntPoint&, int width);
......
......@@ -636,6 +636,23 @@ void GraphicsContext::translate(const FloatSize& size)
CGContextTranslateCTM(platformContext(), size.width(), size.height());
}
FloatRect GraphicsContext::roundToDevicePixels(const FloatRect& rect)
{
CGRect deviceRect = CGContextConvertRectToDeviceSpace(platformContext(), rect);
deviceRect.origin.x = roundf(deviceRect.origin.x);
deviceRect.origin.y = roundf(deviceRect.origin.y);
deviceRect.size.width = roundf(deviceRect.size.width);
deviceRect.size.height = roundf(deviceRect.size.height);
// Don't let the height or width round to 0 unless either was originally 0
if (deviceRect.size.height == 0 && rect.height() != 0)
deviceRect.size.height = 1;
if (deviceRect.size.width == 0 && rect.width() != 0)
deviceRect.size.width = 1;
return CGContextConvertRectToUserSpace(platformContext(), deviceRect);
}
void GraphicsContext::drawLineForText(const IntPoint& point, int yOffset, int width, bool printing)
{
if (paintingDisabled())
......@@ -663,14 +680,7 @@ void GraphicsContext::drawLineForText(const IntPoint& point, int yOffset, int wi
thickness = 1;
// On screen, round all parameters to integer boundaries in device space.
CGRect lineRect = CGContextConvertRectToDeviceSpace(platformContext(), CGRectMake(x, y, width, thickness));
lineRect.origin.x = roundf(lineRect.origin.x);
lineRect.origin.y = roundf(lineRect.origin.y);
lineRect.size.width = roundf(lineRect.size.width);
lineRect.size.height = roundf(lineRect.size.height);
if (lineRect.size.height == 0) // don't let thickness round down to 0 pixels
lineRect.size.height = 1;
lineRect = CGContextConvertRectToUserSpace(platformContext(), lineRect);
CGRect lineRect = roundToDevicePixels(FloatRect(x, y, width, thickness));
x = lineRect.origin.x;
y = lineRect.origin.y;
width = (int)(lineRect.size.width);
......
......@@ -204,8 +204,8 @@ void Image::draw(GraphicsContext* ctxt, const FloatRect& dstRect, const FloatRec
if (!m_source.initialized())
return;
CGRect fr = srcRect;
CGRect ir = dstRect;
CGRect fr = ctxt->roundToDevicePixels(srcRect);
CGRect ir = ctxt->roundToDevicePixels(dstRect);
CGImageRef image = frameAtIndex(m_currentFrame);
if (!image) // If it's too early we won't have an image yet.
......@@ -279,7 +279,8 @@ static void drawPattern(void* info, CGContextRef context)
CGImageRef image = data->frameAtIndex(data->currentFrame());
float w = CGImageGetWidth(image);
float h = CGImageGetHeight(image);
CGContextDrawImage(context, CGRectMake(0, data->size().height() - h, w, h), image);
CGContextDrawImage(context, GraphicsContext(context).roundToDevicePixels(FloatRect
(0, data->size().height() - h, w, h)), image);
}
static const CGPatternCallbacks patternCallbacks = { 0, drawPattern, NULL };
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment