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 "GraphicsContextPlatformPrivateCG.h"
30#import <AppKit/AppKit.h>
31#import <wtf/StdLibExtras.h>
32
33#import "WebCoreSystemInterface.h"
34
35@class NSColor;
36
37// FIXME: More of this should use CoreGraphics instead of AppKit.
38// FIXME: More of this should move into GraphicsContextCG.cpp.
39
40namespace WebCore {
41
42// NSColor, NSBezierPath, and NSGraphicsContext
43// calls in this file are all exception-safe, so we don't block
44// exceptions for those.
45
46static void drawFocusRingToContext(CGContextRef context, RetainPtr<CGPathRef> focusRingPath, RetainPtr<CGColorRef> colorRef, int radius)
47{
48#ifdef BUILDING_ON_TIGER
49    CGContextBeginTransparencyLayer(context, 0);
50#endif
51    CGContextBeginPath(context);
52    CGContextAddPath(context, focusRingPath.get());
53    wkDrawFocusRing(context, colorRef.get(), radius);
54#ifdef BUILDING_ON_TIGER
55    CGContextEndTransparencyLayer(context);
56#endif
57}
58
59void GraphicsContext::drawFocusRing(const Vector<Path>& paths, int width, int offset, const Color& color)
60{
61    if (paintingDisabled())
62        return;
63
64    int radius = (width - 1) / 2;
65    offset += radius;
66    RetainPtr<CGColorRef> colorRef;
67    if (color.isValid())
68        colorRef.adoptCF(createCGColor(color));
69
70    RetainPtr<CGMutablePathRef> focusRingPath(AdoptCF, CGPathCreateMutable());
71    unsigned pathCount = paths.size();
72    for (unsigned i = 0; i < pathCount; i++)
73        CGPathAddPath(focusRingPath.get(), 0, paths[i].platformPath());
74
75    drawFocusRingToContext(platformContext(), focusRingPath, colorRef, radius);
76}
77
78void GraphicsContext::drawFocusRing(const Vector<IntRect>& rects, int width, int offset, const Color& color)
79{
80    if (paintingDisabled())
81        return;
82
83    int radius = (width - 1) / 2;
84    offset += radius;
85    RetainPtr<CGColorRef> colorRef;
86    if (color.isValid())
87        colorRef.adoptCF(createCGColor(color));
88
89    RetainPtr<CGMutablePathRef> focusRingPath(AdoptCF, CGPathCreateMutable());
90    unsigned rectCount = rects.size();
91    for (unsigned i = 0; i < rectCount; i++)
92        CGPathAddRect(focusRingPath.get(), 0, CGRectInset(rects[i], -offset, -offset));
93
94    drawFocusRingToContext(platformContext(), focusRingPath, colorRef, radius);
95}
96
97#ifdef BUILDING_ON_TIGER // Post-Tiger's setCompositeOperation() is defined in GraphicsContextCG.cpp.
98void GraphicsContext::setCompositeOperation(CompositeOperator op)
99{
100    if (paintingDisabled())
101        return;
102    NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
103    [[NSGraphicsContext graphicsContextWithGraphicsPort:platformContext() flipped:YES]
104        setCompositingOperation:(NSCompositingOperation)op];
105    [pool drain];
106}
107#endif
108
109static NSColor* createPatternColor(NSString* name, NSColor* defaultColor, bool& usingDot)
110{
111    NSImage *image = [NSImage imageNamed:name];
112    ASSERT(image); // if image is not available, we want to know
113    NSColor *color = (image ? [NSColor colorWithPatternImage:image] : nil);
114    if (color)
115        usingDot = true;
116    else
117        color = defaultColor;
118    return color;
119}
120
121// WebKit on Mac is a standard platform component, so it must use the standard platform artwork for underline.
122void GraphicsContext::drawLineForMisspellingOrBadGrammar(const IntPoint& point, int width, bool grammar)
123{
124    if (paintingDisabled())
125        return;
126
127    // These are the same for misspelling or bad grammar.
128    int patternHeight = cMisspellingLineThickness;
129    int patternWidth = cMisspellingLinePatternWidth;
130
131    bool usingDot;
132    NSColor *patternColor;
133    if (grammar) {
134        // Constants for grammar pattern color.
135        static bool usingDotForGrammar = false;
136        DEFINE_STATIC_LOCAL(RetainPtr<NSColor>, grammarPatternColor, (createPatternColor(@"GrammarDot", [NSColor greenColor], usingDotForGrammar)));
137
138        usingDot = usingDotForGrammar;
139        patternColor = grammarPatternColor.get();
140    } else {
141        // Constants for spelling pattern color.
142        static bool usingDotForSpelling = false;
143        DEFINE_STATIC_LOCAL(RetainPtr<NSColor>, spellingPatternColor, (createPatternColor(@"SpellingDot", [NSColor redColor], usingDotForSpelling)));
144
145        usingDot = usingDotForSpelling;
146        patternColor = spellingPatternColor.get();
147    }
148
149    // Make sure to draw only complete dots.
150    // NOTE: Code here used to shift the underline to the left and increase the width
151    // to make sure everything gets underlined, but that results in drawing out of
152    // bounds (e.g. when at the edge of a view) and could make it appear that the
153    // space between adjacent misspelled words was underlined.
154    if (usingDot) {
155        // allow slightly more considering that the pattern ends with a transparent pixel
156        int widthMod = width % patternWidth;
157        if (patternWidth - widthMod > cMisspellingLinePatternGapWidth)
158            width -= widthMod;
159    }
160
161    // FIXME: This code should not use NSGraphicsContext currentContext
162    // In order to remove this requirement we will need to use CGPattern instead of NSColor
163    // FIXME: This code should not be using wkSetPatternPhaseInUserSpace, as this approach is wrong
164    // for transforms.
165
166    // Draw underline.
167    NSGraphicsContext *currentContext = [NSGraphicsContext currentContext];
168    CGContextRef context = (CGContextRef)[currentContext graphicsPort];
169    CGContextSaveGState(context);
170
171    [patternColor set];
172
173    wkSetPatternPhaseInUserSpace(context, point);
174
175    NSRectFillUsingOperation(NSMakeRect(point.x(), point.y(), width, patternHeight), NSCompositeSourceOver);
176
177    CGContextRestoreGState(context);
178}
179
180}
181