void CanvasRenderingContext2D::fill() { GraphicsContext* c = drawingContext(); if (!c) return; // FIXME: Do this through platform-independent GraphicsContext API. #if PLATFORM(CG) CGContextBeginPath(c->platformContext()); CGContextAddPath(c->platformContext(), state().m_path.platformPath()); if (!state().m_path.isEmpty()) willDraw(CGContextGetPathBoundingBox(c->platformContext())); if (state().m_fillStyle->gradient()) { // Shading works on the entire clip region, so convert the current path to a clip. c->save(); CGContextClip(c->platformContext()); CGContextDrawShading(c->platformContext(), state().m_fillStyle->gradient()->platformShading()); c->restore(); } else { if (state().m_fillStyle->pattern()) applyFillPattern(); CGContextFillPath(c->platformContext()); } #elif PLATFORM(QT) QPainterPath* path = state().m_path.platformPath(); QPainter* p = static_cast<QPainter*>(c->platformContext()); willDraw(path->controlPointRect()); if (state().m_fillStyle->gradient()) { p->fillPath(*path, QBrush(*(state().m_fillStyle->gradient()->platformShading()))); } else { if (state().m_fillStyle->pattern()) applyFillPattern(); p->fillPath(*path, p->brush()); } #endif clearPathForDashboardBackwardCompatibilityMode(); }
void CanvasRenderingContext2D::applyStrokePattern() { GraphicsContext* c = drawingContext(); if (!c) return; #if PLATFORM(CG) // Check for case where the pattern is already set. CGAffineTransform m = CGContextGetCTM(c->platformContext()); if (state().m_appliedStrokePattern && CGAffineTransformEqualToTransform(m, state().m_strokeStylePatternTransform)) return; CanvasPattern* pattern = state().m_strokeStyle->pattern(); if (!pattern) return; CGPatternRef platformPattern = pattern->createPattern(m); if (!platformPattern) return; CGColorSpaceRef patternSpace = CGColorSpaceCreatePattern(0); CGContextSetStrokeColorSpace(c->platformContext(), patternSpace); CGColorSpaceRelease(patternSpace); const CGFloat patternAlpha = 1; CGContextSetStrokePattern(c->platformContext(), platformPattern, &patternAlpha); CGPatternRelease(platformPattern); state().m_strokeStylePatternTransform = m; #elif PLATFORM(QT) fprintf(stderr, "FIXME: CanvasRenderingContext2D::applyStrokePattern\n"); #elif PLATFORM(CAIRO) notImplemented(); #endif state().m_appliedStrokePattern = true; }
// FIXME: Why isn't this just another overload of drawImage? Why have a different name? void CanvasRenderingContext2D::drawImageFromRect(HTMLImageElement* image, float sx, float sy, float sw, float sh, float dx, float dy, float dw, float dh, const String& compositeOperation) { if (!image) return; CachedImage* cachedImage = image->cachedImage(); if (!cachedImage) return; GraphicsContext* c = drawingContext(); if (!c) return; CompositeOperator op; if (!parseCompositeOperator(compositeOperation, op)) op = CompositeSourceOver; FloatRect destRect = FloatRect(dx, dy, dw, dh); willDraw(destRect); c->drawImage(cachedImage->image(), destRect, FloatRect(sx, sy, sw, sh), op); }
void CanvasRenderingContext2D::applyShadow() { GraphicsContext* c = drawingContext(); if (!c) return; // FIXME: Do this through platform-independent GraphicsContext API. #if PLATFORM(CG) RGBA32 rgba = 0; // default is transparent black if (!state().m_shadowColor.isEmpty()) CSSParser::parseColor(rgba, state().m_shadowColor); const CGFloat components[4] = { ((rgba >> 16) & 0xFF) / 255.0f, ((rgba >> 8) & 0xFF) / 255.0f, (rgba & 0xFF) / 255.0f, ((rgba >> 24) & 0xFF) / 255.0f }; CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); CGColorRef color = CGColorCreate(colorSpace, components); CGColorSpaceRelease(colorSpace); CGContextSetShadowWithColor(c->platformContext(), adjustedShadowSize(state().m_shadowOffset.width(), -state().m_shadowOffset.height()), state().m_shadowBlur, color); CGColorRelease(color); #endif }
void CanvasRenderingContext2D::strokeRect(float x, float y, float width, float height, float lineWidth) { if (!validateRectForCanvas(x, y, width, height)) return; if (!(lineWidth >= 0)) return; GraphicsContext* c = drawingContext(); if (!c) return; FloatRect rect(x, y, width, height); FloatRect boundingRect = rect; boundingRect.inflate(lineWidth / 2); willDraw(boundingRect); // FIXME: No support for gradients! if (state().m_strokeStyle->pattern()) applyStrokePattern(); c->strokeRect(rect, lineWidth); }
void CanvasRenderingContext2D::setFillStyle(PassRefPtr<CanvasStyle> style) { if (!style) return; if (m_canvas->originClean()) { if (CanvasPattern* pattern = style->pattern()) { if (!pattern->originClean()) m_canvas->setOriginTainted(); } } state().m_fillStyle = style; GraphicsContext* c = drawingContext(); if (!c) return; #if PLATFORM(CAIRO) // FIXME: hack to reduce code duplication in CanvasStyle.cpp state().m_fillStyle->applyStrokeColor(c); #else state().m_fillStyle->applyFillColor(c); #endif state().m_appliedFillPattern = false; }
void CanvasRenderingContext2D::drawImage(HTMLCanvasElement* canvas, const FloatRect& srcRect, const FloatRect& dstRect, ExceptionCode& ec) { ASSERT(canvas); ec = 0; FloatRect srcCanvasRect = FloatRect(FloatPoint(), canvas->size()); if (!(srcCanvasRect.contains(srcRect) && srcRect.width() >= 0 && srcRect.height() >= 0 && dstRect.width() >= 0 && dstRect.height() >= 0)) { ec = INDEX_SIZE_ERR; return; } if (srcRect.isEmpty() || dstRect.isEmpty()) return; GraphicsContext* c = drawingContext(); if (!c) return; FloatRect sourceRect = c->roundToDevicePixels(srcRect); FloatRect destRect = c->roundToDevicePixels(dstRect); // FIXME: Do this through platform-independent GraphicsContext API. ImageBuffer* buffer = canvas->buffer(); if (!buffer) return; if (!canvas->originClean()) m_canvas->setOriginTainted(); c->drawImage(buffer->image(), destRect, sourceRect); willDraw(destRect); // This call comes after drawImage, since the buffer we draw into may be our own, and we need to make sure it is dirty. // FIXME: Arguably willDraw should become didDraw and occur after drawing calls and not before them to avoid problems like this. }
void CanvasRenderingContext2D::drawImage(HTMLCanvasElement* canvas, const FloatRect& srcRect, const FloatRect& dstRect, ExceptionCode& ec) { ASSERT(canvas); ec = 0; FloatRect srcCanvasRect = FloatRect(FloatPoint(), canvas->size()); if (!(srcCanvasRect.contains(srcRect) && srcRect.width() >= 0 && srcRect.height() >= 0 && dstRect.width() >= 0 && dstRect.height() >= 0)) { ec = INDEX_SIZE_ERR; return; } if (srcRect.isEmpty() || dstRect.isEmpty()) return; 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 PLATFORM(CG) CGImageRef platformImage = canvas->createPlatformImage(); if (!platformImage) return; willDraw(destRect); float iw = CGImageGetWidth(platformImage); float ih = CGImageGetHeight(platformImage); if (sourceRect.x() == 0 && sourceRect.y() == 0 && iw == sourceRect.width() && ih == sourceRect.height()) { // Fast path, yay! 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(sourceRect.width())); size_t csh = static_cast<size_t>(ceilf(sourceRect.height())); CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); size_t bytesPerRow = csw * 4; void* buffer = fastMalloc(csh * bytesPerRow); CGContextRef clippedSourceContext = CGBitmapContextCreate(buffer, csw, csh, 8, bytesPerRow, colorSpace, kCGImageAlphaPremultipliedLast); CGColorSpaceRelease(colorSpace); CGContextTranslateCTM(clippedSourceContext, -sourceRect.x(), -sourceRect.y()); CGContextDrawImage(clippedSourceContext, CGRectMake(0, 0, iw, ih), platformImage); CGImageRef clippedSourceImage = CGBitmapContextCreateImage(clippedSourceContext); CGContextRelease(clippedSourceContext); CGContextDrawImage(c->platformContext(), destRect, clippedSourceImage); CGImageRelease(clippedSourceImage); fastFree(buffer); } CGImageRelease(platformImage); #elif PLATFORM(QT) QPixmap px = canvas->createPlatformImage(); if (px.isNull()) return; willDraw(dstRect); QPainter* painter = static_cast<QPainter*>(c->platformContext()); painter->drawPixmap(dstRect, px, srcRect); #endif }
void CanvasRenderingContext2D::stroke() { GraphicsContext* c = drawingContext(); if (!c) return; // FIXME: Do this through platform-independent GraphicsContext API. #if PLATFORM(CG) CGContextBeginPath(c->platformContext()); CGContextAddPath(c->platformContext(), state().m_path.platformPath()); if (!state().m_path.isEmpty()) { float lineWidth = state().m_lineWidth; float inset = -lineWidth / 2; CGRect boundingRect = CGRectInset(CGContextGetPathBoundingBox(c->platformContext()), inset, inset); willDraw(boundingRect); } if (state().m_strokeStyle->gradient()) { // Shading works on the entire clip region, so convert the current path to a clip. c->save(); CGContextReplacePathWithStrokedPath(c->platformContext()); CGContextClip(c->platformContext()); CGContextDrawShading(c->platformContext(), state().m_strokeStyle->gradient()->platformShading()); c->restore(); } else { if (state().m_strokeStyle->pattern()) applyStrokePattern(); CGContextStrokePath(c->platformContext()); } #elif PLATFORM(QT) QPainterPath* path = state().m_path.platformPath(); QPainter* p = static_cast<QPainter*>(c->platformContext()); willDraw(path->controlPointRect()); if (state().m_strokeStyle->gradient()) { p->save(); p->setBrush(*(state().m_strokeStyle->gradient()->platformShading())); p->strokePath(*path, p->pen()); p->restore(); } else { if (state().m_strokeStyle->pattern()) applyStrokePattern(); p->strokePath(*path, p->pen()); } #elif PLATFORM(CAIRO) cairo_t* pathCr = state().m_path.platformPath()->m_cr; cairo_t* cr = c->platformContext(); cairo_save(cr); // FIXME: consider inset, as in CG willDraw(state().m_path.boundingRect()); if (state().m_strokeStyle->gradient()) { cairo_set_source(cr, state().m_strokeStyle->gradient()->platformShading()); c->addPath(state().m_path); cairo_stroke(cr); } else { if (state().m_strokeStyle->pattern()) applyStrokePattern(); c->addPath(state().m_path); cairo_stroke(cr); } cairo_restore(cr); #endif clearPathForDashboardBackwardCompatibilityMode(); }
void CanvasRenderingContext2D::stroke() { GraphicsContext* c = drawingContext(); if (!c) return; c->beginPath(); c->addPath(m_path); if (!m_path.isEmpty()) { // FIXME: This is insufficient, need to use CGContextReplacePathWithStrokedPath to expand to required bounds float lineWidth = state().m_lineWidth; float inset = lineWidth / 2; FloatRect boundingRect = m_path.boundingRect(); boundingRect.inflate(inset); willDraw(boundingRect); } // FIXME: Do this through platform-independent GraphicsContext API. #if PLATFORM(CG) if (state().m_strokeStyle->canvasGradient()) { // Shading works on the entire clip region, so convert the current path to a clip. c->save(); CGContextReplacePathWithStrokedPath(c->platformContext()); CGContextClip(c->platformContext()); CGContextDrawShading(c->platformContext(), state().m_strokeStyle->canvasGradient()->gradient().platformGradient()); c->restore(); } else { if (state().m_strokeStyle->pattern()) applyStrokePattern(); CGContextStrokePath(c->platformContext()); } #elif PLATFORM(QT) QPainterPath* path = m_path.platformPath(); QPainter* p = static_cast<QPainter*>(c->platformContext()); if (state().m_strokeStyle->canvasGradient()) { p->save(); p->setBrush(*(state().m_strokeStyle->canvasGradient()->gradient().platformGradient())); p->strokePath(*path, p->pen()); p->restore(); } else { if (state().m_strokeStyle->pattern()) applyStrokePattern(); p->strokePath(*path, p->pen()); } #elif PLATFORM(CAIRO) && !PLATFORM(BAL) cairo_t* cr = c->platformContext(); cairo_save(cr); if (state().m_strokeStyle->canvasGradient()) { cairo_set_source(cr, state().m_strokeStyle->canvasGradient()->gradient().platformGradient()); c->addPath(m_path); cairo_stroke(cr); } else { if (state().m_strokeStyle->pattern()) applyStrokePattern(); c->addPath(m_path); cairo_stroke(cr); } cairo_restore(cr); #elif PLATFORM(BAL) //FIXME notImplemented(); #endif #if ENABLE(DASHBOARD_SUPPORT) clearPathForDashboardBackwardCompatibilityMode(); #endif }