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