| 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 |