27bc3a936440f9fd623fba3f5050a48e7461e6f4
[WebKit-https.git] / Source / WebCore / platform / graphics / GraphicsContext.cpp
1 /*
2  * Copyright (C) 2003, 2004, 2005, 2006, 2009 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 INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "GraphicsContext.h"
28
29 #include "BidiResolver.h"
30 #include "BitmapImage.h"
31 #include "Generator.h"
32 #include "ImageBuffer.h"
33 #include "IntRect.h"
34 #include "RoundedRect.h"
35 #include "TextRun.h"
36
37 #include "stdio.h"
38
39 using namespace std;
40
41 namespace WebCore {
42
43 class TextRunIterator {
44 public:
45     TextRunIterator()
46         : m_textRun(0)
47         , m_offset(0)
48     {
49     }
50
51     TextRunIterator(const TextRun* textRun, unsigned offset)
52         : m_textRun(textRun)
53         , m_offset(offset)
54     {
55     }
56
57     TextRunIterator(const TextRunIterator& other)
58         : m_textRun(other.m_textRun)
59         , m_offset(other.m_offset)
60     {
61     }
62
63     unsigned offset() const { return m_offset; }
64     void increment() { m_offset++; }
65     bool atEnd() const { return !m_textRun || m_offset >= m_textRun->length(); }
66     UChar current() const { return (*m_textRun)[m_offset]; }
67     WTF::Unicode::Direction direction() const { return atEnd() ? WTF::Unicode::OtherNeutral : WTF::Unicode::direction(current()); }
68
69     bool operator==(const TextRunIterator& other)
70     {
71         return m_offset == other.m_offset && m_textRun == other.m_textRun;
72     }
73
74     bool operator!=(const TextRunIterator& other) { return !operator==(other); }
75
76 private:
77     const TextRun* m_textRun;
78     int m_offset;
79 };
80
81 GraphicsContext::GraphicsContext(PlatformGraphicsContext* platformGraphicsContext)
82     : m_updatingControlTints(false)
83     , m_transparencyCount(0)
84 {
85     platformInit(platformGraphicsContext);
86 }
87
88 GraphicsContext::~GraphicsContext()
89 {
90     ASSERT(m_stack.isEmpty());
91     ASSERT(!m_transparencyCount);
92     platformDestroy();
93 }
94
95 void GraphicsContext::save()
96 {
97     if (paintingDisabled())
98         return;
99
100     m_stack.append(m_state);
101
102     savePlatformState();
103 }
104
105 void GraphicsContext::restore()
106 {
107     if (paintingDisabled())
108         return;
109
110     if (m_stack.isEmpty()) {
111         LOG_ERROR("ERROR void GraphicsContext::restore() stack is empty");
112         return;
113     }
114     m_state = m_stack.last();
115     m_stack.removeLast();
116
117     restorePlatformState();
118 }
119
120 void GraphicsContext::setStrokeThickness(float thickness)
121 {
122     m_state.strokeThickness = thickness;
123     setPlatformStrokeThickness(thickness);
124 }
125
126 void GraphicsContext::setStrokeStyle(StrokeStyle style)
127 {
128     m_state.strokeStyle = style;
129     setPlatformStrokeStyle(style);
130 }
131
132 void GraphicsContext::setStrokeColor(const Color& color, ColorSpace colorSpace)
133 {
134     m_state.strokeColor = color;
135     m_state.strokeColorSpace = colorSpace;
136     m_state.strokeGradient.clear();
137     m_state.strokePattern.clear();
138     setPlatformStrokeColor(color, colorSpace);
139 }
140
141 void GraphicsContext::setShadow(const FloatSize& offset, float blur, const Color& color, ColorSpace colorSpace)
142 {
143     m_state.shadowOffset = offset;
144     m_state.shadowBlur = blur;
145     m_state.shadowColor = color;
146     m_state.shadowColorSpace = colorSpace;
147     setPlatformShadow(offset, blur, color, colorSpace);
148 }
149
150 void GraphicsContext::setLegacyShadow(const FloatSize& offset, float blur, const Color& color, ColorSpace colorSpace)
151 {
152     m_state.shadowOffset = offset;
153     m_state.shadowBlur = blur;
154     m_state.shadowColor = color;
155     m_state.shadowColorSpace = colorSpace;
156 #if USE(CG)
157     m_state.shadowsUseLegacyRadius = true;
158 #endif
159     setPlatformShadow(offset, blur, color, colorSpace);
160 }
161
162 void GraphicsContext::clearShadow()
163 {
164     m_state.shadowOffset = FloatSize();
165     m_state.shadowBlur = 0;
166     m_state.shadowColor = Color();
167     m_state.shadowColorSpace = ColorSpaceDeviceRGB;
168     clearPlatformShadow();
169 }
170
171 bool GraphicsContext::hasShadow() const
172 {
173     return m_state.shadowColor.isValid() && m_state.shadowColor.alpha()
174            && (m_state.shadowBlur || m_state.shadowOffset.width() || m_state.shadowOffset.height());
175 }
176
177 bool GraphicsContext::getShadow(FloatSize& offset, float& blur, Color& color, ColorSpace& colorSpace) const
178 {
179     offset = m_state.shadowOffset;
180     blur = m_state.shadowBlur;
181     color = m_state.shadowColor;
182     colorSpace = m_state.shadowColorSpace;
183
184     return hasShadow();
185 }
186
187 bool GraphicsContext::hasBlurredShadow() const
188 {
189     return m_state.shadowColor.isValid() && m_state.shadowColor.alpha() && m_state.shadowBlur;
190 }
191
192 #if PLATFORM(QT) || USE(CAIRO)
193 bool GraphicsContext::mustUseShadowBlur() const
194 {
195     // We can't avoid ShadowBlur if the shadow has blur.
196     if (hasBlurredShadow())
197         return true;
198     // We can avoid ShadowBlur and optimize, since we're not drawing on a
199     // canvas and box shadows are affected by the transformation matrix.
200     if (!m_state.shadowsIgnoreTransforms)
201         return false;
202     // We can avoid ShadowBlur, since there are no transformations to apply to the canvas.
203     if (getCTM().isIdentity())
204         return false;
205     // Otherwise, no chance avoiding ShadowBlur.
206     return true;
207 }
208 #endif
209
210 float GraphicsContext::strokeThickness() const
211 {
212     return m_state.strokeThickness;
213 }
214
215 StrokeStyle GraphicsContext::strokeStyle() const
216 {
217     return m_state.strokeStyle;
218 }
219
220 Color GraphicsContext::strokeColor() const
221 {
222     return m_state.strokeColor;
223 }
224
225 ColorSpace GraphicsContext::strokeColorSpace() const
226 {
227     return m_state.strokeColorSpace;
228 }
229
230 WindRule GraphicsContext::fillRule() const
231 {
232     return m_state.fillRule;
233 }
234
235 void GraphicsContext::setFillRule(WindRule fillRule)
236 {
237     m_state.fillRule = fillRule;
238 }
239
240 void GraphicsContext::setFillColor(const Color& color, ColorSpace colorSpace)
241 {
242     m_state.fillColor = color;
243     m_state.fillColorSpace = colorSpace;
244     m_state.fillGradient.clear();
245     m_state.fillPattern.clear();
246     setPlatformFillColor(color, colorSpace);
247 }
248
249 Color GraphicsContext::fillColor() const
250 {
251     return m_state.fillColor;
252 }
253
254 ColorSpace GraphicsContext::fillColorSpace() const
255 {
256     return m_state.fillColorSpace;
257 }
258
259 void GraphicsContext::setShouldAntialias(bool b)
260 {
261     m_state.shouldAntialias = b;
262     setPlatformShouldAntialias(b);
263 }
264
265 bool GraphicsContext::shouldAntialias() const
266 {
267     return m_state.shouldAntialias;
268 }
269
270 void GraphicsContext::setShouldSmoothFonts(bool b)
271 {
272     m_state.shouldSmoothFonts = b;
273     setPlatformShouldSmoothFonts(b);
274 }
275
276 bool GraphicsContext::shouldSmoothFonts() const
277 {
278     return m_state.shouldSmoothFonts;
279 }
280
281 void GraphicsContext::setShouldSubpixelQuantizeFonts(bool b)
282 {
283     m_state.shouldSubpixelQuantizeFonts = b;
284 }
285
286 bool GraphicsContext::shouldSubpixelQuantizeFonts() const
287 {
288     return m_state.shouldSubpixelQuantizeFonts;
289 }
290
291 const GraphicsContextState& GraphicsContext::state() const
292 {
293     return m_state;
294 }
295
296 void GraphicsContext::setStrokePattern(PassRefPtr<Pattern> pattern)
297 {
298     ASSERT(pattern);
299     if (!pattern) {
300         setStrokeColor(Color::black, ColorSpaceDeviceRGB);
301         return;
302     }
303     m_state.strokeGradient.clear();
304     m_state.strokePattern = pattern;
305 }
306
307 void GraphicsContext::setFillPattern(PassRefPtr<Pattern> pattern)
308 {
309     ASSERT(pattern);
310     if (!pattern) {
311         setFillColor(Color::black, ColorSpaceDeviceRGB);
312         return;
313     }
314     m_state.fillGradient.clear();
315     m_state.fillPattern = pattern;
316 }
317
318 void GraphicsContext::setStrokeGradient(PassRefPtr<Gradient> gradient)
319 {
320     ASSERT(gradient);
321     if (!gradient) {
322         setStrokeColor(Color::black, ColorSpaceDeviceRGB);
323         return;
324     }
325     m_state.strokeGradient = gradient;
326     m_state.strokePattern.clear();
327 }
328
329 void GraphicsContext::setFillGradient(PassRefPtr<Gradient> gradient)
330 {
331     ASSERT(gradient);
332     if (!gradient) {
333         setFillColor(Color::black, ColorSpaceDeviceRGB);
334         return;
335     }
336     m_state.fillGradient = gradient;
337     m_state.fillPattern.clear();
338 }
339
340 Gradient* GraphicsContext::fillGradient() const
341 {
342     return m_state.fillGradient.get();
343 }
344
345 Gradient* GraphicsContext::strokeGradient() const
346 {
347     return m_state.strokeGradient.get();
348 }
349
350 Pattern* GraphicsContext::fillPattern() const
351 {
352     return m_state.fillPattern.get();
353 }
354
355 Pattern* GraphicsContext::strokePattern() const
356 {
357     return m_state.strokePattern.get();
358 }
359
360 void GraphicsContext::setShadowsIgnoreTransforms(bool ignoreTransforms)
361 {
362     m_state.shadowsIgnoreTransforms = ignoreTransforms;
363 }
364
365 bool GraphicsContext::shadowsIgnoreTransforms() const
366 {
367     return m_state.shadowsIgnoreTransforms;
368 }
369
370 void GraphicsContext::beginTransparencyLayer(float opacity)
371 {
372     beginPlatformTransparencyLayer(opacity);
373     ++m_transparencyCount;
374 }
375
376 void GraphicsContext::endTransparencyLayer()
377 {
378     endPlatformTransparencyLayer();
379     ASSERT(m_transparencyCount > 0);
380     --m_transparencyCount;
381 }
382
383 #if !PLATFORM(QT)
384 bool GraphicsContext::isInTransparencyLayer() const
385 {
386     return (m_transparencyCount > 0) && supportsTransparencyLayers();
387 }
388 #endif
389
390 bool GraphicsContext::updatingControlTints() const
391 {
392     return m_updatingControlTints;
393 }
394
395 void GraphicsContext::setUpdatingControlTints(bool b)
396 {
397     setPaintingDisabled(b);
398     m_updatingControlTints = b;
399 }
400
401 void GraphicsContext::setPaintingDisabled(bool f)
402 {
403     m_state.paintingDisabled = f;
404 }
405
406 bool GraphicsContext::paintingDisabled() const
407 {
408     return m_state.paintingDisabled;
409 }
410
411 #if !OS(WINCE) || PLATFORM(QT)
412 void GraphicsContext::drawText(const Font& font, const TextRun& run, const FloatPoint& point, int from, int to)
413 {
414     if (paintingDisabled())
415         return;
416
417     font.drawText(this, run, point, from, to);
418 }
419 #endif
420
421 void GraphicsContext::drawEmphasisMarks(const Font& font, const TextRun& run, const AtomicString& mark, const FloatPoint& point, int from, int to)
422 {
423     if (paintingDisabled())
424         return;
425
426     font.drawEmphasisMarks(this, run, mark, point, from, to);
427 }
428
429 void GraphicsContext::drawBidiText(const Font& font, const TextRun& run, const FloatPoint& point, Font::CustomFontNotReadyAction customFontNotReadyAction)
430 {
431     if (paintingDisabled())
432         return;
433
434     BidiResolver<TextRunIterator, BidiCharacterRun> bidiResolver;
435     bidiResolver.setStatus(BidiStatus(run.direction(), run.directionalOverride()));
436     bidiResolver.setPositionIgnoringNestedIsolates(TextRunIterator(&run, 0));
437
438     // FIXME: This ownership should be reversed. We should pass BidiRunList
439     // to BidiResolver in createBidiRunsForLine.
440     BidiRunList<BidiCharacterRun>& bidiRuns = bidiResolver.runs();
441     bidiResolver.createBidiRunsForLine(TextRunIterator(&run, run.length()));
442     if (!bidiRuns.runCount())
443         return;
444
445     FloatPoint currPoint = point;
446     BidiCharacterRun* bidiRun = bidiRuns.firstRun();
447     while (bidiRun) {
448         TextRun subrun = run.subRun(bidiRun->start(), bidiRun->stop() - bidiRun->start());
449         bool isRTL = bidiRun->level() % 2;
450         subrun.setDirection(isRTL ? RTL : LTR);
451         subrun.setDirectionalOverride(bidiRun->dirOverride(false));
452
453         font.drawText(this, subrun, currPoint, 0, -1, customFontNotReadyAction);
454
455         bidiRun = bidiRun->next();
456         // FIXME: Have Font::drawText return the width of what it drew so that we don't have to re-measure here.
457         if (bidiRun)
458             currPoint.move(font.width(subrun), 0);
459     }
460
461     bidiRuns.deleteRuns();
462 }
463
464 void GraphicsContext::drawHighlightForText(const Font& font, const TextRun& run, const FloatPoint& point, int h, const Color& backgroundColor, ColorSpace colorSpace, int from, int to)
465 {
466     if (paintingDisabled())
467         return;
468
469     fillRect(font.selectionRectForText(run, point, h, from, to), backgroundColor, colorSpace);
470 }
471
472 void GraphicsContext::drawImage(Image* image, ColorSpace styleColorSpace, const IntPoint& p, CompositeOperator op, RespectImageOrientationEnum shouldRespectImageOrientation)
473 {
474     if (!image)
475         return;
476     drawImage(image, styleColorSpace, FloatRect(IntRect(p, image->size())), FloatRect(FloatPoint(), FloatSize(image->size())), op, shouldRespectImageOrientation);
477 }
478
479 void GraphicsContext::drawImage(Image* image, ColorSpace styleColorSpace, const IntRect& r, CompositeOperator op, RespectImageOrientationEnum shouldRespectImageOrientation, bool useLowQualityScale)
480 {
481     if (!image)
482         return;
483     drawImage(image, styleColorSpace, FloatRect(r), FloatRect(FloatPoint(), FloatSize(image->size())), op, shouldRespectImageOrientation, useLowQualityScale);
484 }
485
486 void GraphicsContext::drawImage(Image* image, ColorSpace styleColorSpace, const IntPoint& dest, const IntRect& srcRect, CompositeOperator op, RespectImageOrientationEnum shouldRespectImageOrientation)
487 {
488     drawImage(image, styleColorSpace, FloatRect(IntRect(dest, srcRect.size())), FloatRect(srcRect), op, shouldRespectImageOrientation);
489 }
490
491 void GraphicsContext::drawImage(Image* image, ColorSpace styleColorSpace, const FloatRect& dest, const FloatRect& src, CompositeOperator op, RespectImageOrientationEnum shouldRespectImageOrientation, bool useLowQualityScale)
492 {
493     drawImage(image, styleColorSpace, dest, src, op, BlendModeNormal, shouldRespectImageOrientation, useLowQualityScale);
494 }
495
496 void GraphicsContext::drawImage(Image* image, ColorSpace styleColorSpace, const FloatRect& dest)
497 {
498     if (!image)
499         return;
500     drawImage(image, styleColorSpace, dest, FloatRect(IntRect(IntPoint(), image->size())));
501 }
502
503 void GraphicsContext::drawImage(Image* image, ColorSpace styleColorSpace, const FloatRect& dest, const FloatRect& src, CompositeOperator op, BlendMode blendMode, RespectImageOrientationEnum shouldRespectImageOrientation, bool useLowQualityScale)
504 {    if (paintingDisabled() || !image)
505         return;
506
507     InterpolationQuality previousInterpolationQuality = InterpolationDefault;
508
509     if (useLowQualityScale) {
510         previousInterpolationQuality = imageInterpolationQuality();
511 #if PLATFORM(CHROMIUM)
512         setImageInterpolationQuality(InterpolationLow);
513 #else
514         // FIXME (49002): Should be InterpolationLow
515         setImageInterpolationQuality(InterpolationNone);
516 #endif
517     }
518
519     image->draw(this, dest, src, styleColorSpace, op, blendMode, shouldRespectImageOrientation);
520
521     if (useLowQualityScale)
522         setImageInterpolationQuality(previousInterpolationQuality);
523 }
524
525 void GraphicsContext::drawTiledImage(Image* image, ColorSpace styleColorSpace, const IntRect& destRect, const IntPoint& srcPoint, const IntSize& tileSize, CompositeOperator op, bool useLowQualityScale, BlendMode blendMode)
526 {
527     if (paintingDisabled() || !image)
528         return;
529
530     if (useLowQualityScale) {
531         InterpolationQuality previousInterpolationQuality = imageInterpolationQuality();
532         setImageInterpolationQuality(InterpolationLow);
533         image->drawTiled(this, destRect, srcPoint, tileSize, styleColorSpace, op, blendMode);
534         setImageInterpolationQuality(previousInterpolationQuality);
535     } else
536         image->drawTiled(this, destRect, srcPoint, tileSize, styleColorSpace, op, blendMode);
537 }
538
539 void GraphicsContext::drawTiledImage(Image* image, ColorSpace styleColorSpace, const IntRect& dest, const IntRect& srcRect,
540     const FloatSize& tileScaleFactor, Image::TileRule hRule, Image::TileRule vRule, CompositeOperator op, bool useLowQualityScale)
541 {
542     if (paintingDisabled() || !image)
543         return;
544
545     if (hRule == Image::StretchTile && vRule == Image::StretchTile) {
546         // Just do a scale.
547         drawImage(image, styleColorSpace, dest, srcRect, op);
548         return;
549     }
550
551     if (useLowQualityScale) {
552         InterpolationQuality previousInterpolationQuality = imageInterpolationQuality();
553         setImageInterpolationQuality(InterpolationLow);
554         image->drawTiled(this, dest, srcRect, tileScaleFactor, hRule, vRule, styleColorSpace, op);
555         setImageInterpolationQuality(previousInterpolationQuality);
556     } else
557         image->drawTiled(this, dest, srcRect, tileScaleFactor, hRule, vRule, styleColorSpace, op);
558 }
559
560 void GraphicsContext::drawImageBuffer(ImageBuffer* image, ColorSpace styleColorSpace, const IntPoint& p, CompositeOperator op, BlendMode blendMode)
561 {
562     if (!image)
563         return;
564     drawImageBuffer(image, styleColorSpace, FloatRect(IntRect(p, image->logicalSize())), FloatRect(FloatPoint(), FloatSize(image->logicalSize())), op, blendMode);
565 }
566
567 void GraphicsContext::drawImageBuffer(ImageBuffer* image, ColorSpace styleColorSpace, const IntRect& r, CompositeOperator op, BlendMode blendMode, bool useLowQualityScale)
568 {
569     if (!image)
570         return;
571     drawImageBuffer(image, styleColorSpace, FloatRect(r), FloatRect(FloatPoint(), FloatSize(image->logicalSize())), op, blendMode, useLowQualityScale);
572 }
573
574 void GraphicsContext::drawImageBuffer(ImageBuffer* image, ColorSpace styleColorSpace, const IntPoint& dest, const IntRect& srcRect, CompositeOperator op, BlendMode blendMode)
575 {
576     drawImageBuffer(image, styleColorSpace, FloatRect(IntRect(dest, srcRect.size())), FloatRect(srcRect), op, blendMode);
577 }
578
579 void GraphicsContext::drawImageBuffer(ImageBuffer* image, ColorSpace styleColorSpace, const IntRect& dest, const IntRect& srcRect, CompositeOperator op, BlendMode blendMode, bool useLowQualityScale)
580 {
581     drawImageBuffer(image, styleColorSpace, FloatRect(dest), FloatRect(srcRect), op, blendMode, useLowQualityScale);
582 }
583
584 void GraphicsContext::drawImageBuffer(ImageBuffer* image, ColorSpace styleColorSpace, const FloatRect& dest)
585 {
586     if (!image)
587         return;
588     drawImageBuffer(image, styleColorSpace, dest, FloatRect(IntRect(IntPoint(), image->logicalSize())));
589 }
590
591 void GraphicsContext::drawImageBuffer(ImageBuffer* image, ColorSpace styleColorSpace, const FloatRect& dest, const FloatRect& src, CompositeOperator op, BlendMode blendMode, bool useLowQualityScale)
592 {
593     if (paintingDisabled() || !image)
594         return;
595
596     if (useLowQualityScale) {
597         InterpolationQuality previousInterpolationQuality = imageInterpolationQuality();
598 #if PLATFORM(CHROMIUM)
599         setImageInterpolationQuality(InterpolationLow);
600 #else
601         // FIXME (49002): Should be InterpolationLow
602         setImageInterpolationQuality(InterpolationNone);
603 #endif
604         image->draw(this, styleColorSpace, dest, src, op, blendMode, useLowQualityScale);
605         setImageInterpolationQuality(previousInterpolationQuality);
606     } else
607         image->draw(this, styleColorSpace, dest, src, op, blendMode, useLowQualityScale);
608 }
609
610 #if !PLATFORM(QT)
611 void GraphicsContext::clip(const IntRect& rect)
612 {
613     clip(FloatRect(rect));
614 }
615 #endif
616
617 #if !USE(SKIA)
618 void GraphicsContext::clipRoundedRect(const RoundedRect& rect)
619 {
620     if (paintingDisabled())
621         return;
622
623     if (!rect.isRounded()) {
624         clip(rect.rect());
625         return;
626     }
627
628     Path path;
629     path.addRoundedRect(rect);
630     clip(path);
631 }
632 #endif
633
634 void GraphicsContext::clipOutRoundedRect(const RoundedRect& rect)
635 {
636     if (paintingDisabled())
637         return;
638
639     if (!rect.isRounded()) {
640         clipOut(rect.rect());
641         return;
642     }
643
644     Path path;
645     path.addRoundedRect(rect);
646     clipOut(path);
647 }
648
649 void GraphicsContext::clipToImageBuffer(ImageBuffer* buffer, const FloatRect& rect)
650 {
651     if (paintingDisabled())
652         return;
653     buffer->clip(this, rect);
654 }
655
656 #if !USE(CG) && !PLATFORM(QT) && !USE(CAIRO)
657 IntRect GraphicsContext::clipBounds() const
658 {
659     ASSERT_NOT_REACHED();
660     return IntRect();
661 }
662 #endif
663
664 TextDrawingModeFlags GraphicsContext::textDrawingMode() const
665 {
666     return m_state.textDrawingMode;
667 }
668
669 void GraphicsContext::setTextDrawingMode(TextDrawingModeFlags mode)
670 {
671     m_state.textDrawingMode = mode;
672     if (paintingDisabled())
673         return;
674     setPlatformTextDrawingMode(mode);
675 }
676
677 void GraphicsContext::fillRect(const FloatRect& rect, Generator& generator)
678 {
679     if (paintingDisabled())
680         return;
681     generator.fill(this, rect);
682 }
683
684 void GraphicsContext::fillRect(const FloatRect& rect, const Color& color, ColorSpace styleColorSpace, CompositeOperator op)
685 {
686     if (paintingDisabled())
687         return;
688
689     CompositeOperator previousOperator = compositeOperation();
690     setCompositeOperation(op);
691     fillRect(rect, color, styleColorSpace);
692     setCompositeOperation(previousOperator);
693 }
694
695 void GraphicsContext::fillRoundedRect(const RoundedRect& rect, const Color& color, ColorSpace colorSpace)
696 {
697     if (rect.isRounded())
698         fillRoundedRect(rect.rect(), rect.radii().topLeft(), rect.radii().topRight(), rect.radii().bottomLeft(), rect.radii().bottomRight(), color, colorSpace);
699     else
700         fillRect(rect.rect(), color, colorSpace);
701 }
702
703 #if !USE(CG) && !PLATFORM(QT)
704 void GraphicsContext::fillRectWithRoundedHole(const IntRect& rect, const RoundedRect& roundedHoleRect, const Color& color, ColorSpace colorSpace)
705 {
706     if (paintingDisabled())
707         return;
708
709     Path path;
710     path.addRect(rect);
711
712     if (!roundedHoleRect.radii().isZero())
713         path.addRoundedRect(roundedHoleRect);
714     else
715         path.addRect(roundedHoleRect.rect());
716
717     WindRule oldFillRule = fillRule();
718     Color oldFillColor = fillColor();
719     ColorSpace oldFillColorSpace = fillColorSpace();
720     
721     setFillRule(RULE_EVENODD);
722     setFillColor(color, colorSpace);
723
724     fillPath(path);
725     
726     setFillRule(oldFillRule);
727     setFillColor(oldFillColor, oldFillColorSpace);
728 }
729 #endif
730
731 void GraphicsContext::setCompositeOperation(CompositeOperator compositeOperation, BlendMode blendMode)
732 {
733     m_state.compositeOperator = compositeOperation;
734     m_state.blendMode = blendMode;
735     setPlatformCompositeOperation(compositeOperation, blendMode);
736 }
737
738 CompositeOperator GraphicsContext::compositeOperation() const
739 {
740     return m_state.compositeOperator;
741 }
742
743 BlendMode GraphicsContext::blendModeOperation() const
744 {
745     return m_state.blendMode;
746 }
747
748 #if !USE(CG) && !USE(SKIA)
749 // Implement this if you want to go ahead and push the drawing mode into your native context
750 // immediately.
751 void GraphicsContext::setPlatformTextDrawingMode(TextDrawingModeFlags)
752 {
753 }
754 #endif
755
756 #if !PLATFORM(QT) && !USE(CAIRO) && !USE(SKIA) && !PLATFORM(OPENVG)
757 void GraphicsContext::setPlatformStrokeStyle(StrokeStyle)
758 {
759 }
760 #endif
761
762 #if !USE(CG)
763 void GraphicsContext::setPlatformShouldSmoothFonts(bool)
764 {
765 }
766 #endif
767
768 #if !USE(SKIA) && !USE(CG)
769 bool GraphicsContext::isAcceleratedContext() const
770 {
771     return false;
772 }
773 #endif
774
775 void GraphicsContext::adjustLineToPixelBoundaries(FloatPoint& p1, FloatPoint& p2, float strokeWidth, StrokeStyle penStyle)
776 {
777     // For odd widths, we add in 0.5 to the appropriate x/y so that the float arithmetic
778     // works out.  For example, with a border width of 3, WebKit will pass us (y1+y2)/2, e.g.,
779     // (50+53)/2 = 103/2 = 51 when we want 51.5.  It is always true that an even width gave
780     // us a perfect position, but an odd width gave us a position that is off by exactly 0.5.
781     if (penStyle == DottedStroke || penStyle == DashedStroke) {
782         if (p1.x() == p2.x()) {
783             p1.setY(p1.y() + strokeWidth);
784             p2.setY(p2.y() - strokeWidth);
785         } else {
786             p1.setX(p1.x() + strokeWidth);
787             p2.setX(p2.x() - strokeWidth);
788         }
789     }
790
791     if (static_cast<int>(strokeWidth) % 2) { //odd
792         if (p1.x() == p2.x()) {
793             // We're a vertical line.  Adjust our x.
794             p1.setX(p1.x() + 0.5f);
795             p2.setX(p2.x() + 0.5f);
796         } else {
797             // We're a horizontal line. Adjust our y.
798             p1.setY(p1.y() + 0.5f);
799             p2.setY(p2.y() + 0.5f);
800         }
801     }
802 }
803
804 static bool scalesMatch(AffineTransform a, AffineTransform b)
805 {
806     return a.xScale() == b.xScale() && a.yScale() == b.yScale();
807 }
808
809 PassOwnPtr<ImageBuffer> GraphicsContext::createCompatibleBuffer(const IntSize& size, bool hasAlpha) const
810 {
811     // Make the buffer larger if the context's transform is scaling it so we need a higher
812     // resolution than one pixel per unit. Also set up a corresponding scale factor on the
813     // graphics context.
814
815     AffineTransform transform = getCTM(DefinitelyIncludeDeviceScale);
816     IntSize scaledSize(static_cast<int>(ceil(size.width() * transform.xScale())), static_cast<int>(ceil(size.height() * transform.yScale())));
817
818     OwnPtr<ImageBuffer> buffer = ImageBuffer::createCompatibleBuffer(scaledSize, 1, ColorSpaceDeviceRGB, this, hasAlpha);
819     if (!buffer)
820         return nullptr;
821
822     buffer->context()->scale(FloatSize(static_cast<float>(scaledSize.width()) / size.width(),
823         static_cast<float>(scaledSize.height()) / size.height()));
824
825     return buffer.release();
826 }
827
828 bool GraphicsContext::isCompatibleWithBuffer(ImageBuffer* buffer) const
829 {
830     GraphicsContext* bufferContext = buffer->context();
831
832     return scalesMatch(getCTM(), bufferContext->getCTM()) && isAcceleratedContext() == bufferContext->isAcceleratedContext();
833 }
834
835 #if !USE(CG)
836 void GraphicsContext::platformApplyDeviceScaleFactor(float)
837 {
838 }
839 #endif
840
841 void GraphicsContext::applyDeviceScaleFactor(float deviceScaleFactor)
842 {
843     scale(FloatSize(deviceScaleFactor, deviceScaleFactor));
844     platformApplyDeviceScaleFactor(deviceScaleFactor);
845 }
846
847 void GraphicsContext::fillEllipse(const FloatRect& ellipse)
848 {
849     platformFillEllipse(ellipse);
850 }
851
852 void GraphicsContext::strokeEllipse(const FloatRect& ellipse)
853 {
854     platformStrokeEllipse(ellipse);
855 }
856
857 void GraphicsContext::fillEllipseAsPath(const FloatRect& ellipse)
858 {
859     Path path;
860     path.addEllipse(ellipse);
861     fillPath(path);
862 }
863
864 void GraphicsContext::strokeEllipseAsPath(const FloatRect& ellipse)
865 {
866     Path path;
867     path.addEllipse(ellipse);
868     strokePath(path);
869 }
870
871 #if !USE(CG) && !USE(SKIA) // append && !USE(MYPLATFORM) here to optimize ellipses on your platform.
872 void GraphicsContext::platformFillEllipse(const FloatRect& ellipse)
873 {
874     if (paintingDisabled())
875         return;
876
877     fillEllipseAsPath(ellipse);
878 }
879
880 void GraphicsContext::platformStrokeEllipse(const FloatRect& ellipse)
881 {
882     if (paintingDisabled())
883         return;
884
885     strokeEllipseAsPath(ellipse);
886 }
887 #endif
888
889 }