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