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 "GraphicsContextCG.h" 30#import "GraphicsContextPlatformPrivateCG.h" 31#import <AppKit/AppKit.h> 32#import <wtf/StdLibExtras.h> 33 34#import "LocalCurrentGraphicsContext.h" 35#import "WebCoreSystemInterface.h" 36 37@class NSColor; 38 39// FIXME: More of this should use CoreGraphics instead of AppKit. 40// FIXME: More of this should move into GraphicsContextCG.cpp. 41 42namespace WebCore { 43 44// NSColor, NSBezierPath, and NSGraphicsContext 45// calls in this file are all exception-safe, so we don't block 46// exceptions for those. 47 48static void drawFocusRingToContext(CGContextRef context, CGPathRef focusRingPath, CGColorRef color, int radius) 49{ 50 CGContextBeginPath(context); 51 CGContextAddPath(context, focusRingPath); 52 wkDrawFocusRing(context, color, radius); 53} 54 55void GraphicsContext::drawFocusRing(const Path& path, int width, int /*offset*/, const Color& color) 56{ 57 // FIXME: Use 'offset' for something? http://webkit.org/b/49909 58 59 if (paintingDisabled() || path.isNull()) 60 return; 61 62 int radius = (width - 1) / 2; 63 CGColorRef colorRef = color.isValid() ? cachedCGColor(color, ColorSpaceDeviceRGB) : 0; 64 65 drawFocusRingToContext(platformContext(), path.platformPath(), colorRef, radius); 66} 67 68void GraphicsContext::drawFocusRing(const Vector<IntRect>& rects, int width, int offset, const Color& color) 69{ 70 if (paintingDisabled()) 71 return; 72 73 int radius = (width - 1) / 2; 74 offset += radius; 75 CGColorRef colorRef = color.isValid() ? cachedCGColor(color, ColorSpaceDeviceRGB) : 0; 76 77 RetainPtr<CGMutablePathRef> focusRingPath = adoptCF(CGPathCreateMutable()); 78 unsigned rectCount = rects.size(); 79 for (unsigned i = 0; i < rectCount; i++) 80 CGPathAddRect(focusRingPath.get(), 0, CGRectInset(rects[i], -offset, -offset)); 81 82 drawFocusRingToContext(platformContext(), focusRingPath.get(), colorRef, radius); 83} 84 85 86static NSColor* createPatternColor(NSString* firstChoiceName, NSString* secondChoiceName, NSColor* defaultColor, bool& usingDot) 87{ 88 // Eventually we should be able to get rid of the secondChoiceName. For the time being we need both to keep 89 // this working on all platforms. 90 NSImage *image = [NSImage imageNamed:firstChoiceName]; 91 if (!image) 92 image = [NSImage imageNamed:secondChoiceName]; 93 ASSERT(image); // if image is not available, we want to know 94 NSColor *color = (image ? [NSColor colorWithPatternImage:image] : nil); 95 if (color) 96 usingDot = true; 97 else 98 color = defaultColor; 99 return color; 100} 101 102// WebKit on Mac is a standard platform component, so it must use the standard platform artwork for underline. 103void GraphicsContext::drawLineForDocumentMarker(const FloatPoint& point, float width, DocumentMarkerLineStyle style) 104{ 105 if (paintingDisabled()) 106 return; 107 108 // These are the same for misspelling or bad grammar. 109 int patternHeight = cMisspellingLineThickness; 110 float patternWidth = cMisspellingLinePatternWidth; 111 112 bool usingDot; 113 NSColor *patternColor; 114 switch (style) { 115 case DocumentMarkerSpellingLineStyle: 116 { 117 // Constants for spelling pattern color. 118 static bool usingDotForSpelling = false; 119 DEFINE_STATIC_LOCAL(RetainPtr<NSColor>, spellingPatternColor, (createPatternColor(@"NSSpellingDot", @"SpellingDot", [NSColor redColor], usingDotForSpelling))); 120 usingDot = usingDotForSpelling; 121 patternColor = spellingPatternColor.get(); 122 break; 123 } 124 case DocumentMarkerGrammarLineStyle: 125 { 126 // Constants for grammar pattern color. 127 static bool usingDotForGrammar = false; 128 DEFINE_STATIC_LOCAL(RetainPtr<NSColor>, grammarPatternColor, (createPatternColor(@"NSGrammarDot", @"GrammarDot", [NSColor greenColor], usingDotForGrammar))); 129 usingDot = usingDotForGrammar; 130 patternColor = grammarPatternColor.get(); 131 break; 132 } 133#if PLATFORM(MAC) && (PLATFORM(IOS) || __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070) 134 // To support correction panel. 135 case DocumentMarkerAutocorrectionReplacementLineStyle: 136 case DocumentMarkerDictationAlternativesLineStyle: 137 { 138 // Constants for spelling pattern color. 139 static bool usingDotForSpelling = false; 140 DEFINE_STATIC_LOCAL(RetainPtr<NSColor>, spellingPatternColor, (createPatternColor(@"NSCorrectionDot", @"CorrectionDot", [NSColor blueColor], usingDotForSpelling))); 141 usingDot = usingDotForSpelling; 142 patternColor = spellingPatternColor.get(); 143 break; 144 } 145#endif 146 default: 147 return; 148 } 149 150 FloatPoint offsetPoint = point; 151 152 // Make sure to draw only complete dots. 153 // NOTE: Code here used to shift the underline to the left and increase the width 154 // to make sure everything gets underlined, but that results in drawing out of 155 // bounds (e.g. when at the edge of a view) and could make it appear that the 156 // space between adjacent misspelled words was underlined. 157 if (usingDot) { 158 // allow slightly more considering that the pattern ends with a transparent pixel 159 float widthMod = fmodf(width, patternWidth); 160 if (patternWidth - widthMod > cMisspellingLinePatternGapWidth) { 161 offsetPoint.move(widthMod / 2, 0); 162 width -= widthMod; 163 } 164 } 165 166 // FIXME: This code should not use NSGraphicsContext currentContext 167 // In order to remove this requirement we will need to use CGPattern instead of NSColor 168 // FIXME: This code should not be using wkSetPatternPhaseInUserSpace, as this approach is wrong 169 // for transforms. 170 171 // Draw underline. 172 LocalCurrentGraphicsContext localContext(this); 173 NSGraphicsContext *currentContext = [NSGraphicsContext currentContext]; 174 CGContextRef context = (CGContextRef)[currentContext graphicsPort]; 175 CGContextSaveGState(context); 176 177 [patternColor set]; 178 179 wkSetPatternPhaseInUserSpace(context, offsetPoint); 180 181 NSRectFillUsingOperation(NSMakeRect(offsetPoint.x(), offsetPoint.y(), width, patternHeight), NSCompositeSourceOver); 182 183 CGContextRestoreGState(context); 184} 185 186CGColorSpaceRef linearRGBColorSpaceRef() 187{ 188 static CGColorSpaceRef linearSRGBSpace = 0; 189 190 if (linearSRGBSpace) 191 return linearSRGBSpace; 192 193 RetainPtr<NSString> iccProfilePath = [[NSBundle bundleWithIdentifier:@"com.apple.WebCore"] pathForResource:@"linearSRGB" ofType:@"icc"]; 194 RetainPtr<NSData> iccProfileData = adoptNS([[NSData alloc] initWithContentsOfFile:iccProfilePath.get()]); 195 196 if (iccProfileData) 197 linearSRGBSpace = CGColorSpaceCreateWithICCProfile((CFDataRef)iccProfileData.get()); 198 199 // If we fail to load the linearized sRGB ICC profile, fall back to DeviceRGB. 200 if (!linearSRGBSpace) 201 return deviceRGBColorSpaceRef(); 202 203 return linearSRGBSpace; 204} 205 206} 207