/* * Copyright (C) 2003 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. */ #import "KWQPainter.h" #import "KWQAssertions.h" #import "KWQExceptions.h" #import "KWQFontMetrics.h" #import "KWQKHTMLPart.h" #import "KWQPaintDevice.h" #import "KWQPixmap.h" #import "KWQPointArray.h" #import "KWQPrinter.h" #import "KWQPtrStack.h" #import "KWQWidget.h" #import "KWQFoundationExtras.h" #import "WebCoreGraphicsBridge.h" #import "WebCoreImageRenderer.h" #import "WebCoreImageRendererFactory.h" #import "WebCoreTextRenderer.h" #import "WebCoreTextRendererFactory.h" // NSColor, NSBezierPath, NSGraphicsContext and WebCoreTextRenderer // calls in this file are all exception-safe, so we don't block // exceptions for those. struct QPState { QPState() : paintingDisabled(false) { } QFont font; QPen pen; QBrush brush; QRegion clip; bool paintingDisabled; }; struct QPainterPrivate { QPainterPrivate() : textRenderer(0), focusRingPath(0), focusRingWidth(0), focusRingOffset(0), hasFocusRingColor(false) { } ~QPainterPrivate() { KWQRelease(textRenderer); KWQRelease(focusRingPath); } QPState state; QPtrStack<QPState> stack; id <WebCoreTextRenderer> textRenderer; QFont textRendererFont; NSBezierPath *focusRingPath; int focusRingWidth; int focusRingOffset; bool hasFocusRingColor; QColor focusRingColor; }; static inline void _fillRectXX(float x, float y, float w, float h, const QColor& col); static CGColorRef CGColorFromNSColor(NSColor *color) { // this needs to always use device colorspace so it can de-calibrate the color for // CGColor to possibly recalibrate it NSColor* deviceColor = [color colorUsingColorSpaceName:NSDeviceRGBColorSpace]; float red = [deviceColor redComponent]; float green = [deviceColor greenComponent]; float blue = [deviceColor blueComponent]; float alpha = [deviceColor alphaComponent]; const float components[] = { red, green, blue, alpha }; CGColorSpaceRef colorSpace = QPainter::rgbColorSpace(); CGColorRef cgColor = CGColorCreate(colorSpace, components); CGColorSpaceRelease(colorSpace); return cgColor; } QPainter::QPainter() : data(new QPainterPrivate), _isForPrinting(false), _usesInactiveTextBackgroundColor(false), _drawsFocusRing(true) { } QPainter::QPainter(bool forPrinting) : data(new QPainterPrivate), _isForPrinting(forPrinting), _usesInactiveTextBackgroundColor(false), _drawsFocusRing(true) { } QPainter::~QPainter() { delete data; } QPaintDevice *QPainter::device() const { static QPrinter printer; static QPaintDevice screen; return _isForPrinting ? &printer : &screen; } const QFont &QPainter::font() const { return data->state.font; } void QPainter::setFont(const QFont &aFont) { data->state.font = aFont; } QFontMetrics QPainter::fontMetrics() const { return data->state.font; } const QPen &QPainter::pen() const { return data->state.pen; } void QPainter::setPen(const QPen &pen) { data->state.pen = pen; } void QPainter::setPen(PenStyle style) { data->state.pen.setStyle(style); data->state.pen.setColor(Qt::black); data->state.pen.setWidth(0); } void QPainter::setPen(QRgb rgb) { data->state.pen.setStyle(SolidLine); data->state.pen.setColor(rgb); data->state.pen.setWidth(0); } void QPainter::setBrush(const QBrush &brush) { data->state.brush = brush; } void QPainter::setBrush(BrushStyle style) { data->state.brush.setStyle(style); data->state.brush.setColor(Qt::black); } void QPainter::setBrush(QRgb rgb) { data->state.brush.setStyle(SolidPattern); data->state.brush.setColor(rgb); } const QBrush &QPainter::brush() const { return data->state.brush; } QRect QPainter::xForm(const QRect &aRect) const { // No difference between device and model coords, so the identity transform is ok. return aRect; } void QPainter::save() { data->stack.push(new QPState(data->state)); [NSGraphicsContext saveGraphicsState]; } void QPainter::restore() { if (data->stack.isEmpty()) { ERROR("ERROR void QPainter::restore() stack is empty"); return; } QPState *ps = data->stack.pop(); data->state = *ps; delete ps; [NSGraphicsContext restoreGraphicsState]; } // Draws a filled rectangle with a stroked border. void QPainter::drawRect(int x, int y, int w, int h) { if (data->state.paintingDisabled) return; if (data->state.brush.style() != NoBrush) _fillRectXX(x, y, w, h, data->state.brush.color()); if (data->state.pen.style() != NoPen) { _setColorFromPen(); NSFrameRect(NSMakeRect(x, y, w, h)); } } void QPainter::_setColorFromBrush() { [data->state.brush.color().getNSColor() set]; } void QPainter::_setColorFromPen() { [data->state.pen.color().getNSColor() set]; } // This is only used to draw borders. void QPainter::drawLine(int x1, int y1, int x2, int y2) { if (data->state.paintingDisabled) return; PenStyle penStyle = data->state.pen.style(); if (penStyle == NoPen) return; float width = data->state.pen.width(); if (width < 1) width = 1; NSPoint p1 = NSMakePoint(x1, y1); NSPoint p2 = NSMakePoint(x2, y2); // For odd widths, we add in 0.5 to the appropriate x/y so that the float arithmetic // works out. For example, with a border width of 3, KHTML will pass us (y1+y2)/2, e.g., // (50+53)/2 = 103/2 = 51 when we want 51.5. It is always true that an even width gave // us a perfect position, but an odd width gave us a position that is off by exactly 0.5. if (penStyle == DotLine || penStyle == DashLine) { if (x1 == x2) { p1.y += width; p2.y -= width; } else { p1.x += width; p2.x -= width; } } if (((int)width)%2) { if (x1 == x2) { // We're a vertical line. Adjust our x. p1.x += 0.5; p2.x += 0.5; } else { // We're a horizontal line. Adjust our y. p1.y += 0.5; p2.y += 0.5; } } NSBezierPath *path = [[NSBezierPath alloc] init]; [path setLineWidth:width]; int patWidth = 0; switch (penStyle) { case NoPen: case SolidLine: break; case DotLine: patWidth = (int)width; break; case DashLine: patWidth = 3*(int)width; break; } _setColorFromPen(); NSGraphicsContext *graphicsContext = [NSGraphicsContext currentContext]; BOOL flag = [graphicsContext shouldAntialias]; [graphicsContext setShouldAntialias: NO]; if (patWidth) { // Do a rect fill of our endpoints. This ensures we always have the // appearance of being a border. We then draw the actual dotted/dashed line. if (x1 == x2) { _fillRectXX(p1.x-width/2, p1.y-width, width, width, data->state.pen.color()); _fillRectXX(p2.x-width/2, p2.y, width, width, data->state.pen.color()); } else { _fillRectXX(p1.x-width, p1.y-width/2, width, width, data->state.pen.color()); _fillRectXX(p2.x, p2.y-width/2, width, width, data->state.pen.color()); } // Example: 80 pixels with a width of 30 pixels. // Remainder is 20. The maximum pixels of line we could paint // will be 50 pixels. int distance = ((x1 == x2) ? (y2 - y1) : (x2 - x1)) - 2*(int)width; int remainder = distance%patWidth; int coverage = distance-remainder; int numSegments = coverage/patWidth; float patternOffset = 0; // Special case 1px dotted borders for speed. if (patWidth == 1) patternOffset = 1.0; else { bool evenNumberOfSegments = numSegments%2 == 0; if (remainder) evenNumberOfSegments = !evenNumberOfSegments; if (evenNumberOfSegments) { if (remainder) { patternOffset += patWidth - remainder; patternOffset += remainder/2; } else patternOffset = patWidth/2; } else if (!evenNumberOfSegments) { if (remainder) patternOffset = (patWidth - remainder)/2; } } const float dottedLine[2] = { patWidth, patWidth }; [path setLineDash:dottedLine count:2 phase:patternOffset]; } [path moveToPoint:p1]; [path lineToPoint:p2]; [path stroke]; [path release]; [graphicsContext setShouldAntialias: flag]; } // This method is only used to draw the little circles used in lists. void QPainter::drawEllipse(int x, int y, int w, int h) { // This code can only handle circles, not ellipses. But khtml only // uses it for circles. ASSERT(w == h); if (data->state.paintingDisabled) return; CGContextRef context = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort]; CGContextBeginPath(context); float r = (float)w / 2; CGContextAddArc(context, x + r, y + r, r, 0, 2*M_PI, true); CGContextClosePath(context); if (data->state.brush.style() != NoBrush) { _setColorFromBrush(); if (data->state.pen.style() != NoPen) { // stroke and fill _setColorFromPen(); uint penWidth = data->state.pen.width(); if (penWidth == 0) penWidth++; CGContextSetLineWidth(context, penWidth); CGContextDrawPath(context, kCGPathFillStroke); } else { CGContextFillPath(context); } } if (data->state.pen.style() != NoPen) { _setColorFromPen(); uint penWidth = data->state.pen.width(); if (penWidth == 0) penWidth++; CGContextSetLineWidth(context, penWidth); CGContextStrokePath(context); } } void QPainter::drawArc (int x, int y, int w, int h, int a, int alen) { // Only supports arc on circles. That's all khtml needs. ASSERT(w == h); if (data->state.paintingDisabled) return; if (data->state.pen.style() != NoPen) { CGContextRef context = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort]; CGContextBeginPath(context); float r = (float)w / 2; float fa = (float)a / 16; float falen = fa + (float)alen / 16; CGContextAddArc(context, x + r, y + r, r, -fa * M_PI/180, -falen * M_PI/180, true); _setColorFromPen(); CGContextSetLineWidth(context, data->state.pen.width()); CGContextStrokePath(context); } } void QPainter::drawLineSegments(const QPointArray &points, int index, int nlines) { if (data->state.paintingDisabled) return; _drawPoints (points, 0, index, nlines, false); } void QPainter::drawPolyline(const QPointArray &points, int index, int npoints) { _drawPoints (points, 0, index, npoints, false); } void QPainter::drawPolygon(const QPointArray &points, bool winding, int index, int npoints) { _drawPoints (points, winding, index, npoints, true); } void QPainter::drawConvexPolygon(const QPointArray &points) { _drawPoints (points, false, 0, -1, true); } void QPainter::_drawPoints (const QPointArray &_points, bool winding, int index, int _npoints, bool fill) { if (data->state.paintingDisabled) return; NSGraphicsContext *graphicsContext = [NSGraphicsContext currentContext]; BOOL flag = [graphicsContext shouldAntialias]; [graphicsContext setShouldAntialias: NO]; int npoints = _npoints != -1 ? _npoints : _points.size()-index; NSPoint points[npoints]; for (int i = 0; i < npoints; i++) { points[i].x = _points[index+i].x(); points[i].y = _points[index+i].y(); } NSBezierPath *path = [[NSBezierPath alloc] init]; [path appendBezierPathWithPoints:&points[0] count:npoints]; [path closePath]; // Qt always closes the path. Determined empirically. if (fill && data->state.brush.style() != NoBrush) { [path setWindingRule:winding ? NSNonZeroWindingRule : NSEvenOddWindingRule]; _setColorFromBrush(); [path fill]; } if (data->state.pen.style() != NoPen) { _setColorFromPen(); [path setLineWidth:data->state.pen.width()]; [path stroke]; } [path release]; [graphicsContext setShouldAntialias: flag]; } void QPainter::drawPixmap(const QPoint &p, const QPixmap &pix) { drawPixmap(p.x(), p.y(), pix); } void QPainter::drawPixmap(const QPoint &p, const QPixmap &pix, const QRect &r) { drawPixmap(p.x(), p.y(), pix, r.x(), r.y(), r.width(), r.height()); } struct CompositeOperator { const char *name; NSCompositingOperation value; }; #define NUM_COMPOSITE_OPERATORS 14 struct CompositeOperator compositeOperators[NUM_COMPOSITE_OPERATORS] = { { "clear", NSCompositeClear }, { "copy", NSCompositeCopy }, { "source-over", NSCompositeSourceOver }, { "source-in", NSCompositeSourceIn }, { "source-out", NSCompositeSourceOut }, { "source-atop", NSCompositeSourceAtop }, { "destination-over", NSCompositeDestinationOver }, { "destination-in", NSCompositeDestinationIn }, { "destination-out", NSCompositeDestinationOut }, { "destination-atop", NSCompositeDestinationAtop }, { "xor", NSCompositeXOR }, { "darker", NSCompositePlusDarker }, { "highlight", NSCompositeHighlight }, { "lighter", NSCompositePlusLighter } }; int QPainter::getCompositeOperation(CGContextRef context) { return (int)[[WebCoreImageRendererFactory sharedFactory] CGCompositeOperationInContext:context]; } void QPainter::setCompositeOperation (CGContextRef context, QString op) { [[WebCoreImageRendererFactory sharedFactory] setCGCompositeOperationFromString:op.getNSString() inContext:context]; } void QPainter::setCompositeOperation (CGContextRef context, int op) { [[WebCoreImageRendererFactory sharedFactory] setCGCompositeOperation:op inContext:context]; } int QPainter::compositeOperatorFromString (QString aString) { NSCompositingOperation op = NSCompositeSourceOver; if (aString.length()) { const char *operatorString = aString.ascii(); int i; for (i = 0; i < NUM_COMPOSITE_OPERATORS; i++) { if (strcasecmp (operatorString, compositeOperators[i].name) == 0) { return compositeOperators[i].value; } } } return (int)op; } void QPainter::drawPixmap(const QPoint &p, const QPixmap &pix, const QRect &r, const QString &compositeOperator) { drawPixmap(p.x(), p.y(), pix, r.x(), r.y(), r.width(), r.height(), compositeOperatorFromString(compositeOperator)); } void QPainter::drawPixmap( int x, int y, const QPixmap &pixmap, int sx, int sy, int sw, int sh, int compositeOperator, CGContextRef context) { drawPixmap (x, y, sw, sh, pixmap, sx, sy, sw, sh, compositeOperator, context); } void QPainter::drawPixmap( int x, int y, int w, int h, const QPixmap &pixmap, int sx, int sy, int sw, int sh, int compositeOperator, CGContextRef context) { drawFloatPixmap ((float)x, (float)y, (float)w, (float)h, pixmap, (float)sx, (float)sy, (float)sw, (float)sh, compositeOperator, context); } void QPainter::drawFloatPixmap( float x, float y, float w, float h, const QPixmap &pixmap, float sx, float sy, float sw, float sh, int compositeOperator, CGContextRef context) { if (data->state.paintingDisabled) return; // As a workaround for a GCC bug, we moved KWQ_BLOCK_EXCEPTIONS from just above [pixmap.imageRender ...] to here // and we created 4 temporary variables to hold the function arguments KWQ_BLOCK_EXCEPTIONS; float tsw = sw; float tsh = sh; float tw = w; float th = h; if (tsw == -1) tsw = pixmap.width(); if (tsh == -1) tsh = pixmap.height(); if (tw == -1) tw = pixmap.width(); if (th == -1) th = pixmap.height(); NSRect inRect = NSMakeRect(x, y, tw, th); NSRect fromRect = NSMakeRect(sx, sy, tsw, tsh); [pixmap.imageRenderer drawImageInRect:inRect fromRect:fromRect compositeOperator:(NSCompositingOperation)compositeOperator context:context]; KWQ_UNBLOCK_EXCEPTIONS; } void QPainter::drawTiledPixmap( int x, int y, int w, int h, const QPixmap &pixmap, int sx, int sy, CGContextRef context) { if (data->state.paintingDisabled) return; KWQ_BLOCK_EXCEPTIONS; NSRect tempRect = { {x, y}, {w, h} }; // workaround for 4213314 NSPoint tempPoint = { sx, sy }; [pixmap.imageRenderer tileInRect:tempRect fromPoint:tempPoint context:context]; KWQ_UNBLOCK_EXCEPTIONS; } void QPainter::_updateRenderer() { if (data->textRenderer == 0 || data->state.font != data->textRendererFont) { data->textRendererFont = data->state.font; id <WebCoreTextRenderer> oldRenderer = data->textRenderer; KWQ_BLOCK_EXCEPTIONS; data->textRenderer = KWQRetain([[WebCoreTextRendererFactory sharedFactory] rendererWithFont:data->textRendererFont.getNSFont() usingPrinterFont:data->textRendererFont.isPrinterFont()]); KWQRelease(oldRenderer); KWQ_UNBLOCK_EXCEPTIONS; } } void QPainter::drawText(int x, int y, int tabWidth, int xpos, int, int, int alignmentFlags, const QString &qstring) { if (data->state.paintingDisabled) return; // Avoid allocations, use stack array to pass font families. Normally these // css fallback lists are small <= 3. CREATE_FAMILY_ARRAY(data->state.font, families); _updateRenderer(); const UniChar* str = (const UniChar*)qstring.unicode(); WebCoreTextRun run; WebCoreInitializeTextRun(&run, str, qstring.length(), 0, qstring.length()); WebCoreTextStyle style; WebCoreInitializeEmptyTextStyle(&style); style.textColor = data->state.pen.color().getNSColor(); style.families = families; style.tabWidth = tabWidth; style.xpos = xpos; if (alignmentFlags & Qt::AlignRight) x -= ROUND_TO_INT([data->textRenderer floatWidthForRun:&run style:&style widths:0]); WebCoreTextGeometry geometry; WebCoreInitializeEmptyTextGeometry(&geometry); geometry.point = NSMakePoint(x, y); [data->textRenderer drawRun:&run style:&style geometry:&geometry]; } void QPainter::drawText(int x, int y, int tabWidth, int xpos, const QChar *str, int len, int from, int to, int toAdd, const QColor &backgroundColor, QPainter::TextDirection d, bool visuallyOrdered, int letterSpacing, int wordSpacing, bool smallCaps) { if (data->state.paintingDisabled || len <= 0) return; // Avoid allocations, use stack array to pass font families. Normally these // css fallback lists are small <= 3. CREATE_FAMILY_ARRAY(data->state.font, families); _updateRenderer(); if (from < 0) from = 0; if (to < 0) to = len; WebCoreTextRun run; WebCoreInitializeTextRun(&run, (const UniChar *)str, len, from, to); WebCoreTextStyle style; WebCoreInitializeEmptyTextStyle(&style); style.textColor = data->state.pen.color().getNSColor(); style.backgroundColor = backgroundColor.isValid() ? backgroundColor.getNSColor() : nil; style.rtl = d == RTL ? true : false; style.visuallyOrdered = visuallyOrdered; style.letterSpacing = letterSpacing; style.wordSpacing = wordSpacing; style.smallCaps = smallCaps; style.families = families; style.padding = toAdd; style.tabWidth = tabWidth; style.xpos = xpos; WebCoreTextGeometry geometry; WebCoreInitializeEmptyTextGeometry(&geometry); geometry.point = NSMakePoint(x, y); [data->textRenderer drawRun:&run style:&style geometry:&geometry]; } void QPainter::drawHighlightForText(int x, int y, int h, int tabWidth, int xpos, const QChar *str, int len, int from, int to, int toAdd, const QColor &backgroundColor, QPainter::TextDirection d, bool visuallyOrdered, int letterSpacing, int wordSpacing, bool smallCaps) { if (data->state.paintingDisabled || len <= 0) return; // Avoid allocations, use stack array to pass font families. Normally these // css fallback lists are small <= 3. CREATE_FAMILY_ARRAY(data->state.font, families); _updateRenderer(); if (from < 0) from = 0; if (to < 0) to = len; WebCoreTextRun run; WebCoreInitializeTextRun(&run, (const UniChar *)str, len, from, to); WebCoreTextStyle style; WebCoreInitializeEmptyTextStyle(&style); style.textColor = data->state.pen.color().getNSColor(); style.backgroundColor = backgroundColor.isValid() ? backgroundColor.getNSColor() : nil; style.rtl = d == RTL ? true : false; style.visuallyOrdered = visuallyOrdered; style.letterSpacing = letterSpacing; style.wordSpacing = wordSpacing; style.smallCaps = smallCaps; style.families = families; style.padding = toAdd; style.tabWidth = tabWidth; style.xpos = xpos; WebCoreTextGeometry geometry; WebCoreInitializeEmptyTextGeometry(&geometry); geometry.point = NSMakePoint(x, y); geometry.selectionY = y; geometry.selectionHeight = h; geometry.useFontMetricsForSelectionYAndHeight = false; [data->textRenderer drawHighlightForRun:&run style:&style geometry:&geometry]; } void QPainter::drawLineForText(int x, int y, int yOffset, int width) { if (data->state.paintingDisabled) return; _updateRenderer(); [data->textRenderer drawLineForCharacters: NSMakePoint(x, y) yOffset:(float)yOffset width: width color:data->state.pen.color().getNSColor() thickness:data->state.pen.width()]; } void QPainter::drawLineForMisspelling(int x, int y, int width) { if (data->state.paintingDisabled) return; _updateRenderer(); [data->textRenderer drawLineForMisspelling:NSMakePoint(x, y) withWidth:width]; } int QPainter::misspellingLineThickness() const { return [data->textRenderer misspellingLineThickness]; } static int getBlendedColorComponent(int c, int a) { // We use white. float alpha = (float)(a) / 255; int whiteBlend = 255 - a; c -= whiteBlend; return (int)(c/alpha); } QColor QPainter::selectedTextBackgroundColor() const { NSColor *color = _usesInactiveTextBackgroundColor ? [NSColor secondarySelectedControlColor] : [NSColor selectedTextBackgroundColor]; // this needs to always use device colorspace so it can de-calibrate the color for // QColor to possibly recalibrate it color = [color colorUsingColorSpaceName:NSDeviceRGBColorSpace]; QColor col = QColor((int)(255 * [color redComponent]), (int)(255 * [color greenComponent]), (int)(255 * [color blueComponent])); // Attempt to make the selection 60% transparent. We do this by applying a standard blend and then // seeing if the resultant color is still within the 0-255 range. int alpha = 153; int red = getBlendedColorComponent(col.red(), alpha); int green = getBlendedColorComponent(col.green(), alpha); int blue = getBlendedColorComponent(col.blue(), alpha); if (red >= 0 && red <= 255 && green >= 0 && green <= 255 && blue >= 0 && blue <= 255) return QColor(qRgba(red, green, blue, alpha)); return col; } // A fillRect designed to work around buggy behavior in NSRectFill. static inline void _fillRectXX(float x, float y, float w, float h, const QColor& col) { [col.getNSColor() set]; NSRectFillUsingOperation(NSMakeRect(x,y,w,h), NSCompositeSourceOver); } void QPainter::fillRect(int x, int y, int w, int h, const QBrush &brush) { if (data->state.paintingDisabled) return; if (brush.style() == SolidPattern) _fillRectXX(x, y, w, h, brush.color()); } void QPainter::fillRect(const QRect &rect, const QBrush &brush) { fillRect(rect.left(), rect.top(), rect.width(), rect.height(), brush); } void QPainter::addClip(const QRect &rect) { [NSBezierPath clipRect:rect]; } Qt::RasterOp QPainter::rasterOp() const { return CopyROP; } void QPainter::setRasterOp(RasterOp) { } void QPainter::setPaintingDisabled(bool f) { data->state.paintingDisabled = f; } bool QPainter::paintingDisabled() const { return data->state.paintingDisabled; } CGContextRef QPainter::currentContext() { return (CGContextRef)([[NSGraphicsContext currentContext] graphicsPort]); } void QPainter::beginTransparencyLayer(float opacity) { [NSGraphicsContext saveGraphicsState]; CGContextRef context = (CGContextRef)([[NSGraphicsContext currentContext] graphicsPort]); CGContextSetAlpha(context, opacity); CGContextBeginTransparencyLayer(context, 0); } void QPainter::endTransparencyLayer() { CGContextRef context = (CGContextRef)([[NSGraphicsContext currentContext] graphicsPort]); CGContextEndTransparencyLayer(context); [NSGraphicsContext restoreGraphicsState]; } void QPainter::setShadow(int x, int y, int blur, const QColor& color) { // Check for an invalid color, as this means that the color was not set for the shadow // and we should therefore just use the default shadow color. CGContextRef context = (CGContextRef)([[NSGraphicsContext currentContext] graphicsPort]); if (!color.isValid()) { CGContextSetShadow(context, CGSizeMake(x,-y), blur); // y is flipped. } else { CGColorRef cgColor = CGColorFromNSColor(color.getNSColor()); CGContextSetShadowWithColor(context, CGSizeMake(x,-y), // y is flipped. blur, cgColor); CGColorRelease(cgColor); } } void QPainter::clearShadow() { CGContextRef context = (CGContextRef)([[NSGraphicsContext currentContext] graphicsPort]); CGContextSetShadowWithColor(context, CGSizeZero, 0, NULL); } void QPainter::initFocusRing(int width, int offset) { if (!_drawsFocusRing) return; clearFocusRing(); data->focusRingWidth = width; data->hasFocusRingColor = false; data->focusRingOffset = offset; data->focusRingPath = KWQRetainNSRelease([[NSBezierPath alloc] init]); [data->focusRingPath setWindingRule:NSNonZeroWindingRule]; } void QPainter::initFocusRing(int width, int offset, const QColor &color) { if (!_drawsFocusRing) return; initFocusRing(width, offset); data->hasFocusRingColor = true; data->focusRingColor = color; } void QPainter::addFocusRingRect(int x, int y, int width, int height) { if (!_drawsFocusRing) return; ASSERT(data->focusRingPath); NSRect rect = NSMakeRect(x, y, width, height); int offset = (data->focusRingWidth-1)/2 + data->focusRingOffset; rect = NSInsetRect(rect, -offset, -offset); [data->focusRingPath appendBezierPathWithRect:rect]; } void QPainter::drawFocusRing() { if (!_drawsFocusRing) return; ASSERT(data->focusRingPath); if (data->state.paintingDisabled) return; if ([data->focusRingPath elementCount] == 0) { ERROR("Request to draw focus ring with no control points"); return; } NSRect bounds = [data->focusRingPath bounds]; if (!NSIsEmptyRect(bounds)) { int radius = (data->focusRingWidth-1)/2; NSColor *color = data->hasFocusRingColor ? data->focusRingColor.getNSColor() : nil; [NSGraphicsContext saveGraphicsState]; [[WebCoreGraphicsBridge sharedBridge] setFocusRingStyle:NSFocusRingOnly radius:radius color:color]; [data->focusRingPath fill]; [NSGraphicsContext restoreGraphicsState]; } } void QPainter::clearFocusRing() { if (data->focusRingPath) { KWQRelease(data->focusRingPath); data->focusRingPath = nil; } } CGColorSpaceRef QPainter::rgbColorSpace() { return [[WebCoreGraphicsBridge sharedBridge] createRGBColorSpace]; } CGColorSpaceRef QPainter::grayColorSpace() { return [[WebCoreGraphicsBridge sharedBridge] createGrayColorSpace]; } CGColorSpaceRef QPainter::cmykColorSpace() { return [[WebCoreGraphicsBridge sharedBridge] createCMYKColorSpace]; }