2937de7a5b8868a69a337623d6fd5db74e77fd4e
[WebKit-https.git] / WebCore / platform / mac / GraphicsContextMac.mm
1 /*
2  * Copyright (C) 2003, 2004, 2005, 2006 Apple Computer, Inc.  All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
24  */
25
26 #import "config.h"
27 #import "GraphicsContext.h"
28
29 #import "WebCoreSystemInterface.h"
30
31 // FIXME: More of this should use CoreGraphics instead of AppKit.
32 // FIXME: More of this should move into GraphicsContextCG.cpp.
33
34 namespace WebCore {
35
36 // NSColor, NSBezierPath, and NSGraphicsContext
37 // calls in this file are all exception-safe, so we don't block
38 // exceptions for those.
39
40 class GraphicsContextPlatformPrivate {
41 public:
42     GraphicsContextPlatformPrivate(CGContextRef);
43     ~GraphicsContextPlatformPrivate();
44
45     CGContextRef m_cgContext;
46     IntRect m_focusRingClip; // Work around CG bug in focus ring clipping.
47 };
48
49 GraphicsContextPlatformPrivate::GraphicsContextPlatformPrivate(CGContextRef cgContext)
50 {
51     m_cgContext = cgContext;
52     CGContextRetain(m_cgContext);
53 }
54
55 GraphicsContextPlatformPrivate::~GraphicsContextPlatformPrivate()
56 {
57     CGContextRelease(m_cgContext);
58 }
59
60 GraphicsContext::GraphicsContext(CGContextRef cgContext)
61     : m_common(createGraphicsContextPrivate())
62     , m_data(new GraphicsContextPlatformPrivate(cgContext))
63 {
64     setPaintingDisabled(!cgContext);
65 }
66
67 GraphicsContext::~GraphicsContext()
68 {
69     destroyGraphicsContextPrivate(m_common);
70     delete m_data;
71 }
72
73 static int getBlendedColorComponent(int c, int a)
74 {
75     // We use white.
76     float alpha = (float)(a) / 255;
77     int whiteBlend = 255 - a;
78     c -= whiteBlend;
79     return (int)(c/alpha);
80 }
81
82 Color GraphicsContext::selectedTextBackgroundColor() const
83 {
84     NSColor *color = usesInactiveTextBackgroundColor() ? [NSColor secondarySelectedControlColor] : [NSColor selectedTextBackgroundColor];
85     // this needs to always use device colorspace so it can de-calibrate the color for
86     // Color to possibly recalibrate it
87     color = [color colorUsingColorSpaceName:NSDeviceRGBColorSpace];
88     
89     Color col = Color((int)(255 * [color redComponent]), (int)(255 * [color greenComponent]), (int)(255 * [color blueComponent]));
90     
91     // Attempt to make the selection 60% transparent.  We do this by applying a standard blend and then
92     // seeing if the resultant color is still within the 0-255 range.
93     int alpha = 153;
94     int red = getBlendedColorComponent(col.red(), alpha);
95     int green = getBlendedColorComponent(col.green(), alpha);
96     int blue = getBlendedColorComponent(col.blue(), alpha);
97     if (red >= 0 && red <= 255 && green >= 0 && green <= 255 && blue >= 0 && blue <= 255)
98         return Color(red, green, blue, alpha);
99     return col;
100 }
101
102 void GraphicsContext::setFocusRingClip(const IntRect& r)
103 {
104     // This method only exists to work around bugs in Mac focus ring clipping.
105     m_data->m_focusRingClip = r;
106 }
107
108 void GraphicsContext::clearFocusRingClip()
109 {
110     // This method only exists to work around bugs in Mac focus ring clipping.
111     m_data->m_focusRingClip = IntRect();
112 }
113
114 void GraphicsContext::drawFocusRing(const Color& color)
115 {
116     if (paintingDisabled())
117         return;
118
119     int radius = (focusRingWidth() - 1) / 2;
120     int offset = radius + focusRingOffset();
121     CGColorRef colorRef = color.isValid() ? cgColor(color) : 0;
122
123     CGMutablePathRef focusRingPath = CGPathCreateMutable();
124     const Vector<IntRect>& rects = focusRingRects();
125     unsigned rectCount = rects.size();
126     for (unsigned i = 0; i < rectCount; i++)
127         CGPathAddRect(focusRingPath, 0, CGRectInset(rects[i], -offset, -offset));
128
129     CGContextRef context = platformContext();
130
131     // FIXME: This works only inside a NSView's drawRect method. The view must be
132     // focused and this context must be the current NSGraphicsContext.
133     ASSERT(context == [[NSGraphicsContext currentContext] graphicsPort]);
134     NSView* view = [NSView focusView];
135     ASSERT(view);
136
137     const NSRect* drawRects;
138     int count;
139     [view getRectsBeingDrawn:&drawRects count:&count];
140
141     // We have to pass in our own clip rectangles here because a bug in CG
142     // seems to inflate the clip (thus allowing the focus ring to paint
143     // slightly outside the clip).
144     NSRect transformedClipRect = [view convertRect:m_data->m_focusRingClip toView:nil];
145     for (int i = 0; i < count; ++i) {
146         NSRect transformedRect = [view convertRect:drawRects[i] toView:nil];
147         NSRect rectToUse = NSIntersectionRect(transformedRect, transformedClipRect);
148         if (!NSIsEmptyRect(rectToUse)) {
149             CGContextBeginPath(context);
150             CGContextAddPath(context, focusRingPath);
151             wkDrawFocusRing(context, *(CGRect *)&rectToUse, colorRef, radius);
152         }
153     }
154
155     CGColorRelease(colorRef);
156
157     CGPathRelease(focusRingPath);
158 }
159
160 CGContextRef GraphicsContext::platformContext() const
161 {
162     ASSERT(!paintingDisabled());
163     ASSERT(m_data->m_cgContext);
164     return m_data->m_cgContext;
165 }
166
167 void GraphicsContext::setCompositeOperation(CompositeOperator op)
168 {
169     if (paintingDisabled())
170         return;
171     NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
172     [[NSGraphicsContext graphicsContextWithGraphicsPort:platformContext() flipped:YES]
173         setCompositingOperation:(NSCompositingOperation)op];
174     [pool release];
175 }
176
177 }