OLD | NEW |
| (Empty) |
1 /* | |
2 * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 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 #include "config.h" | |
27 #include "GraphicsContextCG.h" | |
28 | |
29 #include "AffineTransform.h" | |
30 #include "Path.h" | |
31 | |
32 #include <CoreGraphics/CGBitmapContext.h> | |
33 #include <WebKitSystemInterface/WebKitSystemInterface.h> | |
34 #include "GraphicsContextPlatformPrivateCG.h" | |
35 | |
36 using namespace std; | |
37 | |
38 namespace WebCore { | |
39 | |
40 static CGContextRef CGContextWithHDC(HDC hdc, bool hasAlpha) | |
41 { | |
42 HBITMAP bitmap = static_cast<HBITMAP>(GetCurrentObject(hdc, OBJ_BITMAP)); | |
43 | |
44 DIBPixelData pixelData(bitmap); | |
45 | |
46 // FIXME: We can get here because we asked for a bitmap that is too big | |
47 // when we have a tiled layer and we're compositing. In that case | |
48 // bmBitsPixel will be 0. This seems to be benign, so for now we will | |
49 // exit gracefully and look at it later: | |
50 // https://bugs.webkit.org/show_bug.cgi?id=52041 | |
51 // ASSERT(bitmapBits.bitsPerPixel() == 32); | |
52 if (pixelData.bitsPerPixel() != 32) | |
53 return 0; | |
54 | |
55 CGBitmapInfo bitmapInfo = kCGBitmapByteOrder32Little | (hasAlpha ? kCGImageA
lphaPremultipliedFirst : kCGImageAlphaNoneSkipFirst); | |
56 CGContextRef context = CGBitmapContextCreate(pixelData.buffer(), pixelData.s
ize().width(), pixelData.size().height(), 8, | |
57 pixelData.bytesPerRow(), device
RGBColorSpaceRef(), bitmapInfo); | |
58 | |
59 // Flip coords | |
60 CGContextTranslateCTM(context, 0, pixelData.size().height()); | |
61 CGContextScaleCTM(context, 1, -1); | |
62 | |
63 // Put the HDC In advanced mode so it will honor affine transforms. | |
64 SetGraphicsMode(hdc, GM_ADVANCED); | |
65 | |
66 return context; | |
67 } | |
68 | |
69 GraphicsContext::GraphicsContext(HDC hdc, bool hasAlpha) | |
70 : m_updatingControlTints(false), | |
71 m_transparencyCount(0) | |
72 { | |
73 platformInit(hdc, hasAlpha); | |
74 } | |
75 | |
76 void GraphicsContext::platformInit(HDC hdc, bool hasAlpha) | |
77 { | |
78 m_data = new GraphicsContextPlatformPrivate(CGContextWithHDC(hdc, hasAlpha))
; | |
79 CGContextRelease(m_data->m_cgContext.get()); | |
80 m_data->m_hdc = hdc; | |
81 setPaintingDisabled(!m_data->m_cgContext); | |
82 if (m_data->m_cgContext) { | |
83 // Make sure the context starts in sync with our state. | |
84 setPlatformFillColor(fillColor(), ColorSpaceDeviceRGB); | |
85 setPlatformStrokeColor(strokeColor(), ColorSpaceDeviceRGB); | |
86 } | |
87 } | |
88 | |
89 // FIXME: Is it possible to merge getWindowsContext and createWindowsBitmap into
a single API | |
90 // suitable for all clients? | |
91 void GraphicsContext::releaseWindowsContext(HDC hdc, const IntRect& dstRect, boo
l supportAlphaBlend, bool mayCreateBitmap) | |
92 { | |
93 bool createdBitmap = mayCreateBitmap && (!m_data->m_hdc || isInTransparencyL
ayer()); | |
94 if (!createdBitmap) { | |
95 m_data->restore(); | |
96 return; | |
97 } | |
98 | |
99 if (dstRect.isEmpty()) | |
100 return; | |
101 | |
102 OwnPtr<HBITMAP> bitmap = adoptPtr(static_cast<HBITMAP>(GetCurrentObject(hdc,
OBJ_BITMAP))); | |
103 | |
104 DIBPixelData pixelData(bitmap.get()); | |
105 | |
106 ASSERT(pixelData.bitsPerPixel() == 32); | |
107 | |
108 CGContextRef bitmapContext = CGBitmapContextCreate(pixelData.buffer(), pixel
Data.size().width(), pixelData.size().height(), 8, | |
109 pixelData.bytesPerRow(),
deviceRGBColorSpaceRef(), kCGBitmapByteOrder32Little | | |
110 (supportAlphaBlend ? kCGI
mageAlphaPremultipliedFirst : kCGImageAlphaNoneSkipFirst)); | |
111 | |
112 CGImageRef image = CGBitmapContextCreateImage(bitmapContext); | |
113 CGContextDrawImage(m_data->m_cgContext.get(), dstRect, image); | |
114 | |
115 // Delete all our junk. | |
116 CGImageRelease(image); | |
117 CGContextRelease(bitmapContext); | |
118 ::DeleteDC(hdc); | |
119 } | |
120 | |
121 void GraphicsContext::drawWindowsBitmap(WindowsBitmap* image, const IntPoint& po
int) | |
122 { | |
123 // FIXME: Creating CFData is non-optimal, but needed to avoid crashing when
printing. Ideally we should | |
124 // make a custom CGDataProvider that controls the WindowsBitmap lifetime. s
ee <rdar://6394455> | |
125 RetainPtr<CFDataRef> imageData(AdoptCF, CFDataCreate(kCFAllocatorDefault, im
age->buffer(), image->bufferLength())); | |
126 RetainPtr<CGDataProviderRef> dataProvider(AdoptCF, CGDataProviderCreateWithC
FData(imageData.get())); | |
127 RetainPtr<CGImageRef> cgImage(AdoptCF, CGImageCreate(image->size().width(),
image->size().height(), 8, 32, image->bytesPerRow(), deviceRGBColorSpaceRef(), | |
128 kCGBitmapByteOrder32Lit
tle | kCGImageAlphaFirst, dataProvider.get(), 0, true, kCGRenderingIntentDefault
)); | |
129 CGContextDrawImage(m_data->m_cgContext.get(), CGRectMake(point.x(), point.y(
), image->size().width(), image->size().height()), cgImage.get()); | |
130 } | |
131 | |
132 void GraphicsContext::drawFocusRing(const Path& path, int width, int offset, con
st Color& color) | |
133 { | |
134 // FIXME: implement | |
135 } | |
136 | |
137 // FIXME: This is nearly identical to the GraphicsContext::drawFocusRing functio
n in GraphicsContextMac.mm. | |
138 // The code could move to GraphicsContextCG.cpp and be shared. | |
139 void GraphicsContext::drawFocusRing(const Vector<IntRect>& rects, int width, int
offset, const Color& color) | |
140 { | |
141 if (paintingDisabled()) | |
142 return; | |
143 | |
144 float radius = (width - 1) / 2.0f; | |
145 offset += radius; | |
146 CGColorRef colorRef = color.isValid() ? cachedCGColor(color, ColorSpaceDevic
eRGB) : 0; | |
147 | |
148 CGMutablePathRef focusRingPath = CGPathCreateMutable(); | |
149 unsigned rectCount = rects.size(); | |
150 for (unsigned i = 0; i < rectCount; i++) | |
151 CGPathAddRect(focusRingPath, 0, CGRectInset(rects[i], -offset, -offset))
; | |
152 | |
153 CGContextRef context = platformContext(); | |
154 CGContextSaveGState(context); | |
155 | |
156 CGContextBeginPath(context); | |
157 CGContextAddPath(context, focusRingPath); | |
158 | |
159 wkDrawFocusRing(context, colorRef, radius); | |
160 | |
161 CGPathRelease(focusRingPath); | |
162 | |
163 CGContextRestoreGState(context); | |
164 } | |
165 | |
166 // Pulled from GraphicsContextCG | |
167 static void setCGStrokeColor(CGContextRef context, const Color& color) | |
168 { | |
169 CGFloat red, green, blue, alpha; | |
170 color.getRGBA(red, green, blue, alpha); | |
171 CGContextSetRGBStrokeColor(context, red, green, blue, alpha); | |
172 } | |
173 | |
174 static const Color& spellingPatternColor() { | |
175 static const Color spellingColor(255, 0, 0); | |
176 return spellingColor; | |
177 } | |
178 | |
179 static const Color& grammarPatternColor() { | |
180 static const Color grammarColor(0, 128, 0); | |
181 return grammarColor; | |
182 } | |
183 | |
184 void GraphicsContext::drawLineForDocumentMarker(const FloatPoint& point, float w
idth, DocumentMarkerLineStyle style) | |
185 { | |
186 if (paintingDisabled()) | |
187 return; | |
188 | |
189 if (style != DocumentMarkerSpellingLineStyle && style != DocumentMarkerGramm
arLineStyle) | |
190 return; | |
191 | |
192 // These are the same for misspelling or bad grammar | |
193 const int patternHeight = 3; // 3 rows | |
194 ASSERT(cMisspellingLineThickness == patternHeight); | |
195 const int patternWidth = 4; // 4 pixels | |
196 ASSERT(patternWidth == cMisspellingLinePatternWidth); | |
197 | |
198 // Make sure to draw only complete dots. | |
199 // NOTE: Code here used to shift the underline to the left and increase the
width | |
200 // to make sure everything gets underlined, but that results in drawing out
of | |
201 // bounds (e.g. when at the edge of a view) and could make it appear that th
e | |
202 // space between adjacent misspelled words was underlined. | |
203 // allow slightly more considering that the pattern ends with a transparent
pixel | |
204 float widthMod = fmodf(width, patternWidth); | |
205 if (patternWidth - widthMod > cMisspellingLinePatternGapWidth) | |
206 width -= widthMod; | |
207 | |
208 // Draw the underline | |
209 CGContextRef context = platformContext(); | |
210 CGContextSaveGState(context); | |
211 | |
212 const Color& patternColor = style == DocumentMarkerGrammarLineStyle ? gramma
rPatternColor() : spellingPatternColor(); | |
213 setCGStrokeColor(context, patternColor); | |
214 | |
215 wkSetPatternPhaseInUserSpace(context, point); | |
216 CGContextSetBlendMode(context, kCGBlendModeNormal); | |
217 | |
218 // 3 rows, each offset by half a pixel for blending purposes | |
219 const CGPoint upperPoints [] = {{point.x(), point.y() + patternHeight - 2.5
}, {point.x() + width, point.y() + patternHeight - 2.5}}; | |
220 const CGPoint middlePoints [] = {{point.x(), point.y() + patternHeight - 1.5
}, {point.x() + width, point.y() + patternHeight - 1.5}}; | |
221 const CGPoint lowerPoints [] = {{point.x(), point.y() + patternHeight - 0.5
}, {point.x() + width, point.y() + patternHeight - 0.5 }}; | |
222 | |
223 // Dash lengths for the top and bottom of the error underline are the same. | |
224 // These are magic. | |
225 static const float edge_dash_lengths[] = {2.0f, 2.0f}; | |
226 static const float middle_dash_lengths[] = {2.76f, 1.24f}; | |
227 static const float edge_offset = -(edge_dash_lengths[1] - 1.0f) / 2.0f; | |
228 static const float middle_offset = -(middle_dash_lengths[1] - 1.0f) / 2.0f; | |
229 | |
230 // Line opacities. Once again, these are magic. | |
231 const float upperOpacity = 0.33f; | |
232 const float middleOpacity = 0.75f; | |
233 const float lowerOpacity = 0.88f; | |
234 | |
235 //Top line | |
236 CGContextSetLineDash(context, edge_offset, edge_dash_lengths, WTF_ARRAY_LENG
TH(edge_dash_lengths)); | |
237 CGContextSetAlpha(context, upperOpacity); | |
238 CGContextStrokeLineSegments(context, upperPoints, 2); | |
239 | |
240 // Middle line | |
241 CGContextSetLineDash(context, middle_offset, middle_dash_lengths, WTF_ARRAY_
LENGTH(middle_dash_lengths)); | |
242 CGContextSetAlpha(context, middleOpacity); | |
243 CGContextStrokeLineSegments(context, middlePoints, 2); | |
244 | |
245 // Bottom line | |
246 CGContextSetLineDash(context, edge_offset, edge_dash_lengths, WTF_ARRAY_LENG
TH(edge_dash_lengths)); | |
247 CGContextSetAlpha(context, lowerOpacity); | |
248 CGContextStrokeLineSegments(context, lowerPoints, 2); | |
249 | |
250 CGContextRestoreGState(context); | |
251 } | |
252 | |
253 void GraphicsContextPlatformPrivate::flush() | |
254 { | |
255 CGContextFlush(m_cgContext.get()); | |
256 } | |
257 | |
258 } | |
OLD | NEW |