blob: 1ffa998824f318331969d72f4427165d26449794 [file] [log] [blame]
/*
* Copyright (C) 2004, 2006 Apple Computer, Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
//#define DEBUG_LAYOUT
#include "config.h"
#include "render_canvasimage.h"
#if __APPLE__
#include "DocumentImpl.h"
#include "html_canvasimpl.h"
#include "htmlnames.h"
namespace WebCore {
using namespace HTMLNames;
RenderCanvasImage::RenderCanvasImage(NodeImpl *_node)
: RenderImage(_node), _drawingContext(0), _drawingContextData(0), _drawnImage(0), _needsImageUpdate(0)
{
}
RenderCanvasImage::~RenderCanvasImage()
{
if (_drawingContext) {
CFRelease (_drawingContext);
_drawingContext = 0;
}
fastFree(_drawingContextData);
_drawingContextData = 0;
if (_drawnImage) {
CFRelease (_drawnImage);
_drawnImage = 0;
}
}
#define BITS_PER_COMPONENT 8
#define BYTES_PER_ROW(width,bitsPerComponent,numComponents) ((width * bitsPerComponent * numComponents + 7)/8)
void RenderCanvasImage::createDrawingContext()
{
if (_drawingContext) {
CFRelease (_drawingContext);
_drawingContext = 0;
}
fastFree(_drawingContextData);
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
int cWidth = contentWidth();
int cHeight = contentHeight();
size_t numComponents = CGColorSpaceGetNumberOfComponents(colorSpace);
size_t bytesPerRow = BYTES_PER_ROW(cWidth,BITS_PER_COMPONENT,(numComponents+1)); // + 1 for alpha
_drawingContextData = fastCalloc(height(), bytesPerRow);
_drawingContext = CGBitmapContextCreate(_drawingContextData, cWidth, cHeight, BITS_PER_COMPONENT, bytesPerRow, colorSpace, kCGImageAlphaPremultipliedLast);
#ifdef DEBUG_CANVAS_BACKGROUND
CGContextSetRGBFillColor(_drawingContext, 1.0, 0., 0., 1.);
CGContextFillRect (_drawingContext, CGRectMake (0, 0, width(), height()));
CGContextFlush (_drawingContext);
#endif
updateDrawnImage();
CFRelease (colorSpace);
}
CGContextRef RenderCanvasImage::drawingContext()
{
if (!_drawingContext) {
document()->updateLayout();
createDrawingContext();
}
return _drawingContext;
}
void RenderCanvasImage::setNeedsImageUpdate()
{
_needsImageUpdate = true;
repaint();
}
void RenderCanvasImage::updateDrawnImage()
{
if (_drawnImage)
CFRelease (_drawnImage);
CGContextFlush (_drawingContext);
_drawnImage = CGBitmapContextCreateImage (_drawingContext);
}
CGImageRef RenderCanvasImage::drawnImage()
{
return _drawnImage;
}
void RenderCanvasImage::paint(PaintInfo& i, int _tx, int _ty)
{
if (!shouldPaint(i, _tx, _ty))
return;
int x = _tx + m_x;
int y = _ty + m_y;
if (shouldPaintBackgroundOrBorder() && i.phase != PaintActionOutline)
paintBoxDecorations(i, x, y);
QPainter* p = i.p;
if (p->paintingDisabled())
return;
if (i.phase == PaintActionOutline && style()->outlineWidth() && style()->visibility() == VISIBLE)
paintOutline(p, x, y, width(), height(), style());
if (i.phase != PaintActionForeground && i.phase != PaintActionSelection)
return;
if (!shouldPaintWithinRoot(i))
return;
bool isPrinting = i.p->printing();
bool drawSelectionTint = (selectionState() != SelectionNone) && !isPrinting;
if (i.phase == PaintActionSelection) {
if (selectionState() == SelectionNone) {
return;
}
drawSelectionTint = false;
}
int cWidth = contentWidth();
int cHeight = contentHeight();
int leftBorder = borderLeft();
int topBorder = borderTop();
int leftPad = paddingLeft();
int topPad = paddingTop();
x += leftBorder + leftPad;
y += topBorder + topPad;
if (_needsImageUpdate) {
updateDrawnImage();
_needsImageUpdate = false;
}
if (drawnImage()) {
HTMLCanvasElementImpl* i = (element() && element()->hasTagName(canvasTag)) ? static_cast<HTMLCanvasElementImpl*>(element()) : 0;
int oldOperation = 0;
if (i) {
oldOperation = QPainter::getCompositeOperation(p->currentContext());
QPainter::setCompositeOperation(p->currentContext(), i->compositeOperator());
}
CGContextDrawImage(p->currentContext(), CGRectMake(x, y, cWidth, cHeight), drawnImage());
if (i)
QPainter::setCompositeOperation (p->currentContext(), oldOperation);
}
if (drawSelectionTint)
p->fillRect(selectionRect(), selectionColor(p));
}
void RenderCanvasImage::layout()
{
KHTMLAssert(needsLayout());
KHTMLAssert(minMaxKnown());
IntRect oldBounds;
bool checkForRepaint = checkForRepaintDuringLayout();
if (checkForRepaint)
oldBounds = getAbsoluteRepaintRect();
int oldwidth = m_width;
int oldheight = m_height;
calcWidth();
calcHeight();
if ( m_width != oldwidth || m_height != oldheight ) {
createDrawingContext();
}
if (checkForRepaint)
repaintAfterLayoutIfNeeded(oldBounds, oldBounds);
setNeedsLayout(false);
}
}
#endif