tagging audio streams and changing audio sink to pulseaudio
[profile/ivi/webkit-efl.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 float GraphicsContext::strokeThickness() const
188 {
189     return m_state.strokeThickness;
190 }
191
192 StrokeStyle GraphicsContext::strokeStyle() const
193 {
194     return m_state.strokeStyle;
195 }
196
197 Color GraphicsContext::strokeColor() const
198 {
199     return m_state.strokeColor;
200 }
201
202 ColorSpace GraphicsContext::strokeColorSpace() const
203 {
204     return m_state.strokeColorSpace;
205 }
206
207 WindRule GraphicsContext::fillRule() const
208 {
209     return m_state.fillRule;
210 }
211
212 void GraphicsContext::setFillRule(WindRule fillRule)
213 {
214     m_state.fillRule = fillRule;
215 }
216
217 void GraphicsContext::setFillColor(const Color& color, ColorSpace colorSpace)
218 {
219     m_state.fillColor = color;
220     m_state.fillColorSpace = colorSpace;
221     m_state.fillGradient.clear();
222     m_state.fillPattern.clear();
223     setPlatformFillColor(color, colorSpace);
224 }
225
226 Color GraphicsContext::fillColor() const
227 {
228     return m_state.fillColor;
229 }
230
231 ColorSpace GraphicsContext::fillColorSpace() const
232 {
233     return m_state.fillColorSpace;
234 }
235
236 void GraphicsContext::setShouldAntialias(bool b)
237 {
238     m_state.shouldAntialias = b;
239     setPlatformShouldAntialias(b);
240 }
241
242 bool GraphicsContext::shouldAntialias() const
243 {
244     return m_state.shouldAntialias;
245 }
246
247 void GraphicsContext::setShouldSmoothFonts(bool b)
248 {
249     m_state.shouldSmoothFonts = b;
250     setPlatformShouldSmoothFonts(b);
251 }
252
253 bool GraphicsContext::shouldSmoothFonts() const
254 {
255     return m_state.shouldSmoothFonts;
256 }
257
258 const GraphicsContextState& GraphicsContext::state() const
259 {
260     return m_state;
261 }
262
263 void GraphicsContext::setStrokePattern(PassRefPtr<Pattern> pattern)
264 {
265     ASSERT(pattern);
266     if (!pattern) {
267         setStrokeColor(Color::black, ColorSpaceDeviceRGB);
268         return;
269     }
270     m_state.strokeGradient.clear();
271     m_state.strokePattern = pattern;
272 }
273
274 void GraphicsContext::setFillPattern(PassRefPtr<Pattern> pattern)
275 {
276     ASSERT(pattern);
277     if (!pattern) {
278         setFillColor(Color::black, ColorSpaceDeviceRGB);
279         return;
280     }
281     m_state.fillGradient.clear();
282     m_state.fillPattern = pattern;
283 }
284
285 void GraphicsContext::setStrokeGradient(PassRefPtr<Gradient> gradient)
286 {
287     ASSERT(gradient);
288     if (!gradient) {
289         setStrokeColor(Color::black, ColorSpaceDeviceRGB);
290         return;
291     }
292     m_state.strokeGradient = gradient;
293     m_state.strokePattern.clear();
294 }
295
296 void GraphicsContext::setFillGradient(PassRefPtr<Gradient> gradient)
297 {
298     ASSERT(gradient);
299     if (!gradient) {
300         setFillColor(Color::black, ColorSpaceDeviceRGB);
301         return;
302     }
303     m_state.fillGradient = gradient;
304     m_state.fillPattern.clear();
305 }
306
307 Gradient* GraphicsContext::fillGradient() const
308 {
309     return m_state.fillGradient.get();
310 }
311
312 Gradient* GraphicsContext::strokeGradient() const
313 {
314     return m_state.strokeGradient.get();
315 }
316
317 Pattern* GraphicsContext::fillPattern() const
318 {
319     return m_state.fillPattern.get();
320 }
321
322 Pattern* GraphicsContext::strokePattern() const
323 {
324     return m_state.strokePattern.get();
325 }
326
327 void GraphicsContext::setShadowsIgnoreTransforms(bool ignoreTransforms)
328 {
329     m_state.shadowsIgnoreTransforms = ignoreTransforms;
330 }
331
332 bool GraphicsContext::shadowsIgnoreTransforms() const
333 {
334     return m_state.shadowsIgnoreTransforms;
335 }
336
337 void GraphicsContext::beginTransparencyLayer(float opacity)
338 {
339     beginPlatformTransparencyLayer(opacity);
340     ++m_transparencyCount;
341 }
342
343 void GraphicsContext::endTransparencyLayer()
344 {
345     endPlatformTransparencyLayer();
346     ASSERT(m_transparencyCount > 0);
347     --m_transparencyCount;
348 }
349
350 #if !PLATFORM(QT)
351 bool GraphicsContext::isInTransparencyLayer() const
352 {
353     return (m_transparencyCount > 0) && supportsTransparencyLayers();
354 }
355 #endif
356
357 bool GraphicsContext::updatingControlTints() const
358 {
359     return m_updatingControlTints;
360 }
361
362 void GraphicsContext::setUpdatingControlTints(bool b)
363 {
364     setPaintingDisabled(b);
365     m_updatingControlTints = b;
366 }
367
368 void GraphicsContext::setPaintingDisabled(bool f)
369 {
370     m_state.paintingDisabled = f;
371 }
372
373 bool GraphicsContext::paintingDisabled() const
374 {
375     return m_state.paintingDisabled;
376 }
377
378 #if !OS(WINCE) || (PLATFORM(QT) && !HAVE(QRAWFONT))
379 void GraphicsContext::drawText(const Font& font, const TextRun& run, const FloatPoint& point, int from, int to)
380 {
381     if (paintingDisabled())
382         return;
383
384     font.drawText(this, run, point, from, to);
385 }
386 #endif
387
388 void GraphicsContext::drawEmphasisMarks(const Font& font, const TextRun& run, const AtomicString& mark, const FloatPoint& point, int from, int to)
389 {
390     if (paintingDisabled())
391         return;
392
393     font.drawEmphasisMarks(this, run, mark, point, from, to);
394 }
395
396 void GraphicsContext::drawBidiText(const Font& font, const TextRun& run, const FloatPoint& point, Font::CustomFontNotReadyAction customFontNotReadyAction)
397 {
398     if (paintingDisabled())
399         return;
400
401     BidiResolver<TextRunIterator, BidiCharacterRun> bidiResolver;
402     bidiResolver.setStatus(BidiStatus(run.direction(), run.directionalOverride()));
403     bidiResolver.setPositionIgnoringNestedIsolates(TextRunIterator(&run, 0));
404
405     // FIXME: This ownership should be reversed. We should pass BidiRunList
406     // to BidiResolver in createBidiRunsForLine.
407     BidiRunList<BidiCharacterRun>& bidiRuns = bidiResolver.runs();
408     bidiResolver.createBidiRunsForLine(TextRunIterator(&run, run.length()));
409     if (!bidiRuns.runCount())
410         return;
411
412     FloatPoint currPoint = point;
413     BidiCharacterRun* bidiRun = bidiRuns.firstRun();
414     while (bidiRun) {
415         TextRun subrun = run;
416         subrun.setText(run.data(bidiRun->start()), bidiRun->stop() - bidiRun->start());
417         bool isRTL = bidiRun->level() % 2;
418         subrun.setDirection(isRTL ? RTL : LTR);
419         subrun.setDirectionalOverride(bidiRun->dirOverride(false));
420
421         font.drawText(this, subrun, currPoint, 0, -1, customFontNotReadyAction);
422
423         bidiRun = bidiRun->next();
424         // FIXME: Have Font::drawText return the width of what it drew so that we don't have to re-measure here.
425         if (bidiRun)
426             currPoint.move(font.width(subrun), 0);
427     }
428
429     bidiRuns.deleteRuns();
430 }
431
432 void GraphicsContext::drawHighlightForText(const Font& font, const TextRun& run, const FloatPoint& point, int h, const Color& backgroundColor, ColorSpace colorSpace, int from, int to)
433 {
434     if (paintingDisabled())
435         return;
436
437     fillRect(font.selectionRectForText(run, point, h, from, to), backgroundColor, colorSpace);
438 }
439
440 void GraphicsContext::drawImage(Image* image, ColorSpace styleColorSpace, const IntPoint& p, CompositeOperator op, RespectImageOrientationEnum shouldRespectImageOrientation)
441 {
442     drawImage(image, styleColorSpace, p, IntRect(0, 0, -1, -1), op, shouldRespectImageOrientation);
443 }
444
445 void GraphicsContext::drawImage(Image* image, ColorSpace styleColorSpace, const IntRect& r, CompositeOperator op, RespectImageOrientationEnum shouldRespectImageOrientation, bool useLowQualityScale)
446 {
447     drawImage(image, styleColorSpace, r, IntRect(0, 0, -1, -1), op, shouldRespectImageOrientation, useLowQualityScale);
448 }
449
450 void GraphicsContext::drawImage(Image* image, ColorSpace styleColorSpace, const IntPoint& dest, const IntRect& srcRect, CompositeOperator op, RespectImageOrientationEnum shouldRespectImageOrientation)
451 {
452     drawImage(image, styleColorSpace, IntRect(dest, srcRect.size()), srcRect, op, shouldRespectImageOrientation);
453 }
454
455 void GraphicsContext::drawImage(Image* image, ColorSpace styleColorSpace, const IntRect& dest, const IntRect& srcRect, CompositeOperator op, RespectImageOrientationEnum shouldRespectImageOrientation, bool useLowQualityScale)
456 {
457     drawImage(image, styleColorSpace, FloatRect(dest), srcRect, op, shouldRespectImageOrientation, useLowQualityScale);
458 }
459
460 void GraphicsContext::drawImage(Image* image, ColorSpace styleColorSpace, const FloatRect& dest, const FloatRect& src, CompositeOperator op, RespectImageOrientationEnum shouldRespectImageOrientation, bool useLowQualityScale)
461 {
462     if (paintingDisabled() || !image)
463         return;
464
465     float tsw = src.width();
466     float tsh = src.height();
467     float tw = dest.width();
468     float th = dest.height();
469
470     if (tsw == -1)
471         tsw = image->width();
472     if (tsh == -1)
473         tsh = image->height();
474
475     if (tw == -1)
476         tw = image->width();
477     if (th == -1)
478         th = image->height();
479
480     InterpolationQuality previousInterpolationQuality = InterpolationDefault;
481
482     if (useLowQualityScale) {
483         previousInterpolationQuality = imageInterpolationQuality();
484 #if PLATFORM(CHROMIUM)
485         setImageInterpolationQuality(InterpolationLow);
486 #else
487         // FIXME (49002): Should be InterpolationLow
488         setImageInterpolationQuality(InterpolationNone);
489 #endif
490     }
491
492     image->draw(this, FloatRect(dest.location(), FloatSize(tw, th)), FloatRect(src.location(), FloatSize(tsw, tsh)), styleColorSpace, op, shouldRespectImageOrientation);
493
494     if (useLowQualityScale)
495         setImageInterpolationQuality(previousInterpolationQuality);
496 }
497
498 void GraphicsContext::drawTiledImage(Image* image, ColorSpace styleColorSpace, const IntRect& destRect, const IntPoint& srcPoint, const IntSize& tileSize, CompositeOperator op, bool useLowQualityScale)
499 {
500     if (paintingDisabled() || !image)
501         return;
502
503     if (useLowQualityScale) {
504         InterpolationQuality previousInterpolationQuality = imageInterpolationQuality();
505         setImageInterpolationQuality(InterpolationLow);
506         image->drawTiled(this, destRect, srcPoint, tileSize, styleColorSpace, op);
507         setImageInterpolationQuality(previousInterpolationQuality);
508     } else
509         image->drawTiled(this, destRect, srcPoint, tileSize, styleColorSpace, op);
510 }
511
512 void GraphicsContext::drawTiledImage(Image* image, ColorSpace styleColorSpace, const IntRect& dest, const IntRect& srcRect,
513     const FloatSize& tileScaleFactor, Image::TileRule hRule, Image::TileRule vRule, CompositeOperator op, bool useLowQualityScale)
514 {
515     if (paintingDisabled() || !image)
516         return;
517
518     if (hRule == Image::StretchTile && vRule == Image::StretchTile) {
519         // Just do a scale.
520         drawImage(image, styleColorSpace, dest, srcRect, op);
521         return;
522     }
523
524     if (useLowQualityScale) {
525         InterpolationQuality previousInterpolationQuality = imageInterpolationQuality();
526         setImageInterpolationQuality(InterpolationLow);
527         image->drawTiled(this, dest, srcRect, tileScaleFactor, hRule, vRule, styleColorSpace, op);
528         setImageInterpolationQuality(previousInterpolationQuality);
529     } else
530         image->drawTiled(this, dest, srcRect, tileScaleFactor, hRule, vRule, styleColorSpace, op);
531 }
532
533 void GraphicsContext::drawImageBuffer(ImageBuffer* image, ColorSpace styleColorSpace, const IntPoint& p, CompositeOperator op)
534 {
535     drawImageBuffer(image, styleColorSpace, p, IntRect(0, 0, -1, -1), op);
536 }
537
538 void GraphicsContext::drawImageBuffer(ImageBuffer* image, ColorSpace styleColorSpace, const IntRect& r, CompositeOperator op, bool useLowQualityScale)
539 {
540     drawImageBuffer(image, styleColorSpace, r, IntRect(0, 0, -1, -1), op, useLowQualityScale);
541 }
542
543 void GraphicsContext::drawImageBuffer(ImageBuffer* image, ColorSpace styleColorSpace, const IntPoint& dest, const IntRect& srcRect, CompositeOperator op)
544 {
545     drawImageBuffer(image, styleColorSpace, IntRect(dest, srcRect.size()), srcRect, op);
546 }
547
548 void GraphicsContext::drawImageBuffer(ImageBuffer* image, ColorSpace styleColorSpace, const IntRect& dest, const IntRect& srcRect, CompositeOperator op, bool useLowQualityScale)
549 {
550     drawImageBuffer(image, styleColorSpace, FloatRect(dest), srcRect, op, useLowQualityScale);
551 }
552
553 void GraphicsContext::drawImageBuffer(ImageBuffer* image, ColorSpace styleColorSpace, const FloatRect& dest, const FloatRect& src, CompositeOperator op, bool useLowQualityScale)
554 {
555     if (paintingDisabled() || !image)
556         return;
557
558     float tsw = src.width();
559     float tsh = src.height();
560     float tw = dest.width();
561     float th = dest.height();
562
563     if (tsw == -1)
564         tsw = image->logicalSize().width();
565     if (tsh == -1)
566         tsh = image->logicalSize().height();
567
568     if (tw == -1)
569         tw = image->logicalSize().width();
570     if (th == -1)
571         th = image->logicalSize().height();
572
573     if (useLowQualityScale) {
574         InterpolationQuality previousInterpolationQuality = imageInterpolationQuality();
575 #if PLATFORM(CHROMIUM)
576         setImageInterpolationQuality(InterpolationLow);
577 #else
578         // FIXME (49002): Should be InterpolationLow
579         setImageInterpolationQuality(InterpolationNone);
580 #endif
581         image->draw(this, styleColorSpace, FloatRect(dest.location(), FloatSize(tw, th)), FloatRect(src.location(), FloatSize(tsw, tsh)), op, useLowQualityScale);
582         setImageInterpolationQuality(previousInterpolationQuality);
583     } else
584         image->draw(this, styleColorSpace, FloatRect(dest.location(), FloatSize(tw, th)), FloatRect(src.location(), FloatSize(tsw, tsh)), op, useLowQualityScale);
585 }
586
587 #if !PLATFORM(QT)
588 void GraphicsContext::clip(const IntRect& rect)
589 {
590     clip(FloatRect(rect));
591 }
592 #endif
593
594 void GraphicsContext::addRoundedRectClip(const RoundedRect& rect)
595 {
596     if (paintingDisabled())
597         return;
598
599     Path path;
600     path.addRoundedRect(rect);
601     clip(path);
602 }
603
604 void GraphicsContext::clipOutRoundedRect(const RoundedRect& rect)
605 {
606     if (paintingDisabled())
607         return;
608
609     Path path;
610     path.addRoundedRect(rect);
611     clipOut(path);
612 }
613
614 void GraphicsContext::clipToImageBuffer(ImageBuffer* buffer, const FloatRect& rect)
615 {
616     if (paintingDisabled())
617         return;
618     buffer->clip(this, rect);
619 }
620
621 #if !USE(CG) && !PLATFORM(QT) && !USE(CAIRO)
622 IntRect GraphicsContext::clipBounds() const
623 {
624     ASSERT_NOT_REACHED();
625     return IntRect();
626 }
627 #endif
628
629 TextDrawingModeFlags GraphicsContext::textDrawingMode() const
630 {
631     return m_state.textDrawingMode;
632 }
633
634 void GraphicsContext::setTextDrawingMode(TextDrawingModeFlags mode)
635 {
636     m_state.textDrawingMode = mode;
637     if (paintingDisabled())
638         return;
639     setPlatformTextDrawingMode(mode);
640 }
641
642 void GraphicsContext::fillRect(const FloatRect& rect, Generator& generator)
643 {
644     if (paintingDisabled())
645         return;
646     generator.fill(this, rect);
647 }
648
649 void GraphicsContext::fillRect(const FloatRect& rect, const Color& color, ColorSpace styleColorSpace, CompositeOperator op)
650 {
651     if (paintingDisabled())
652         return;
653
654     CompositeOperator previousOperator = compositeOperation();
655     setCompositeOperation(op);
656     fillRect(rect, color, styleColorSpace);
657     setCompositeOperation(previousOperator);
658 }
659
660 void GraphicsContext::fillRoundedRect(const RoundedRect& rect, const Color& color, ColorSpace colorSpace)
661 {
662     fillRoundedRect(rect.rect(), rect.radii().topLeft(), rect.radii().topRight(), rect.radii().bottomLeft(), rect.radii().bottomRight(), color, colorSpace);
663 }
664
665 #if !USE(CG)
666 void GraphicsContext::fillRectWithRoundedHole(const IntRect& rect, const RoundedRect& roundedHoleRect, const Color& color, ColorSpace colorSpace)
667 {
668     if (paintingDisabled())
669         return;
670
671     Path path;
672     path.addRect(rect);
673
674     if (!roundedHoleRect.radii().isZero())
675         path.addRoundedRect(roundedHoleRect);
676     else
677         path.addRect(roundedHoleRect.rect());
678
679     WindRule oldFillRule = fillRule();
680     Color oldFillColor = fillColor();
681     ColorSpace oldFillColorSpace = fillColorSpace();
682     
683     setFillRule(RULE_EVENODD);
684     setFillColor(color, colorSpace);
685
686     fillPath(path);
687     
688     setFillRule(oldFillRule);
689     setFillColor(oldFillColor, oldFillColorSpace);
690 }
691 #endif
692
693 void GraphicsContext::setCompositeOperation(CompositeOperator compositeOperation)
694 {
695     m_state.compositeOperator = compositeOperation;
696     setPlatformCompositeOperation(compositeOperation);
697 }
698
699 CompositeOperator GraphicsContext::compositeOperation() const
700 {
701     return m_state.compositeOperator;
702 }
703
704 #if !USE(CG) && !USE(SKIA)
705 // Implement this if you want to go ahead and push the drawing mode into your native context
706 // immediately.
707 void GraphicsContext::setPlatformTextDrawingMode(TextDrawingModeFlags mode)
708 {
709 }
710 #endif
711
712 #if !PLATFORM(QT) && !USE(CAIRO) && !USE(SKIA) && !PLATFORM(OPENVG)
713 void GraphicsContext::setPlatformStrokeStyle(StrokeStyle)
714 {
715 }
716 #endif
717
718 #if !USE(CG)
719 void GraphicsContext::setPlatformShouldSmoothFonts(bool)
720 {
721 }
722 #endif
723
724 #if !USE(SKIA) && !USE(CG)
725 bool GraphicsContext::isAcceleratedContext() const
726 {
727     return false;
728 }
729 #endif
730
731 void GraphicsContext::adjustLineToPixelBoundaries(FloatPoint& p1, FloatPoint& p2, float strokeWidth, StrokeStyle penStyle)
732 {
733     // For odd widths, we add in 0.5 to the appropriate x/y so that the float arithmetic
734     // works out.  For example, with a border width of 3, WebKit will pass us (y1+y2)/2, e.g.,
735     // (50+53)/2 = 103/2 = 51 when we want 51.5.  It is always true that an even width gave
736     // us a perfect position, but an odd width gave us a position that is off by exactly 0.5.
737     if (penStyle == DottedStroke || penStyle == DashedStroke) {
738         if (p1.x() == p2.x()) {
739             p1.setY(p1.y() + strokeWidth);
740             p2.setY(p2.y() - strokeWidth);
741         } else {
742             p1.setX(p1.x() + strokeWidth);
743             p2.setX(p2.x() - strokeWidth);
744         }
745     }
746
747     if (static_cast<int>(strokeWidth) % 2) { //odd
748         if (p1.x() == p2.x()) {
749             // We're a vertical line.  Adjust our x.
750             p1.setX(p1.x() + 0.5f);
751             p2.setX(p2.x() + 0.5f);
752         } else {
753             // We're a horizontal line. Adjust our y.
754             p1.setY(p1.y() + 0.5f);
755             p2.setY(p2.y() + 0.5f);
756         }
757     }
758 }
759
760 static bool scalesMatch(AffineTransform a, AffineTransform b)
761 {
762     return a.xScale() == b.xScale() && a.yScale() == b.yScale();
763 }
764
765 PassOwnPtr<ImageBuffer> GraphicsContext::createCompatibleBuffer(const IntSize& size) const
766 {
767     // Make the buffer larger if the context's transform is scaling it so we need a higher
768     // resolution than one pixel per unit. Also set up a corresponding scale factor on the
769     // graphics context.
770
771     AffineTransform transform = getCTM(DefinitelyIncludeDeviceScale);
772     IntSize scaledSize(static_cast<int>(ceil(size.width() * transform.xScale())), static_cast<int>(ceil(size.height() * transform.yScale())));
773
774     OwnPtr<ImageBuffer> buffer = ImageBuffer::create(scaledSize, 1, ColorSpaceDeviceRGB, isAcceleratedContext() ? Accelerated : Unaccelerated);
775     if (!buffer)
776         return nullptr;
777
778     buffer->context()->scale(FloatSize(static_cast<float>(scaledSize.width()) / size.width(),
779         static_cast<float>(scaledSize.height()) / size.height()));
780
781     return buffer.release();
782 }
783
784 bool GraphicsContext::isCompatibleWithBuffer(ImageBuffer* buffer) const
785 {
786     GraphicsContext* bufferContext = buffer->context();
787
788     return scalesMatch(getCTM(), bufferContext->getCTM()) && isAcceleratedContext() == bufferContext->isAcceleratedContext();
789 }
790
791 #if !USE(CG)
792 void GraphicsContext::platformApplyDeviceScaleFactor(float)
793 {
794 }
795 #endif
796
797 void GraphicsContext::applyDeviceScaleFactor(float deviceScaleFactor)
798 {
799     scale(FloatSize(deviceScaleFactor, deviceScaleFactor));
800     platformApplyDeviceScaleFactor(deviceScaleFactor);
801 }
802
803 void GraphicsContext::fillEllipse(const FloatRect& ellipse)
804 {
805     platformFillEllipse(ellipse);
806 }
807
808 void GraphicsContext::strokeEllipse(const FloatRect& ellipse)
809 {
810     platformStrokeEllipse(ellipse);
811 }
812
813 void GraphicsContext::fillEllipseAsPath(const FloatRect& ellipse)
814 {
815     Path path;
816     path.addEllipse(ellipse);
817     fillPath(path);
818 }
819
820 void GraphicsContext::strokeEllipseAsPath(const FloatRect& ellipse)
821 {
822     Path path;
823     path.addEllipse(ellipse);
824     strokePath(path);
825 }
826
827 #if !USE(CG) && !USE(SKIA) // append && !USE(MYPLATFORM) here to optimize ellipses on your platform.
828 void GraphicsContext::platformFillEllipse(const FloatRect& ellipse)
829 {
830     if (paintingDisabled())
831         return;
832
833     fillEllipseAsPath(ellipse);
834 }
835
836 void GraphicsContext::platformStrokeEllipse(const FloatRect& ellipse)
837 {
838     if (paintingDisabled())
839         return;
840
841     strokeEllipseAsPath(ellipse);
842 }
843 #endif
844
845 }