60bbaf2d2d674f735081a05236b55c37bab5a906
[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     if (paintingDisabled() || !image)
472         return;
473
474     float tsw = src.width();
475     float tsh = src.height();
476     float tw = dest.width();
477     float th = dest.height();
478
479     if (tsw == -1)
480         tsw = image->width();
481     if (tsh == -1)
482         tsh = image->height();
483
484     if (tw == -1)
485         tw = image->width();
486     if (th == -1)
487         th = image->height();
488
489     InterpolationQuality previousInterpolationQuality = InterpolationDefault;
490
491     if (useLowQualityScale) {
492         previousInterpolationQuality = imageInterpolationQuality();
493 #if PLATFORM(CHROMIUM)
494         setImageInterpolationQuality(InterpolationLow);
495 #else
496         // FIXME (49002): Should be InterpolationLow
497         setImageInterpolationQuality(InterpolationNone);
498 #endif
499     }
500
501     image->draw(this, FloatRect(dest.location(), FloatSize(tw, th)), FloatRect(src.location(), FloatSize(tsw, tsh)), styleColorSpace, op, shouldRespectImageOrientation);
502
503     if (useLowQualityScale)
504         setImageInterpolationQuality(previousInterpolationQuality);
505 }
506
507 void GraphicsContext::drawTiledImage(Image* image, ColorSpace styleColorSpace, const IntRect& destRect, const IntPoint& srcPoint, const IntSize& tileSize, CompositeOperator op, bool useLowQualityScale)
508 {
509     if (paintingDisabled() || !image)
510         return;
511
512     if (useLowQualityScale) {
513         InterpolationQuality previousInterpolationQuality = imageInterpolationQuality();
514         setImageInterpolationQuality(InterpolationLow);
515         image->drawTiled(this, destRect, srcPoint, tileSize, styleColorSpace, op);
516         setImageInterpolationQuality(previousInterpolationQuality);
517     } else
518         image->drawTiled(this, destRect, srcPoint, tileSize, styleColorSpace, op);
519 }
520
521 void GraphicsContext::drawTiledImage(Image* image, ColorSpace styleColorSpace, const IntRect& dest, const IntRect& srcRect,
522     const FloatSize& tileScaleFactor, Image::TileRule hRule, Image::TileRule vRule, CompositeOperator op, bool useLowQualityScale)
523 {
524     if (paintingDisabled() || !image)
525         return;
526
527     if (hRule == Image::StretchTile && vRule == Image::StretchTile) {
528         // Just do a scale.
529         drawImage(image, styleColorSpace, dest, srcRect, op);
530         return;
531     }
532
533     if (useLowQualityScale) {
534         InterpolationQuality previousInterpolationQuality = imageInterpolationQuality();
535         setImageInterpolationQuality(InterpolationLow);
536         image->drawTiled(this, dest, srcRect, tileScaleFactor, hRule, vRule, styleColorSpace, op);
537         setImageInterpolationQuality(previousInterpolationQuality);
538     } else
539         image->drawTiled(this, dest, srcRect, tileScaleFactor, hRule, vRule, styleColorSpace, op);
540 }
541
542 void GraphicsContext::drawImageBuffer(ImageBuffer* image, ColorSpace styleColorSpace, const IntPoint& p, CompositeOperator op)
543 {
544     drawImageBuffer(image, styleColorSpace, p, IntRect(0, 0, -1, -1), op);
545 }
546
547 void GraphicsContext::drawImageBuffer(ImageBuffer* image, ColorSpace styleColorSpace, const IntRect& r, CompositeOperator op, bool useLowQualityScale)
548 {
549     drawImageBuffer(image, styleColorSpace, r, IntRect(0, 0, -1, -1), op, useLowQualityScale);
550 }
551
552 void GraphicsContext::drawImageBuffer(ImageBuffer* image, ColorSpace styleColorSpace, const IntPoint& dest, const IntRect& srcRect, CompositeOperator op)
553 {
554     drawImageBuffer(image, styleColorSpace, IntRect(dest, srcRect.size()), srcRect, op);
555 }
556
557 void GraphicsContext::drawImageBuffer(ImageBuffer* image, ColorSpace styleColorSpace, const IntRect& dest, const IntRect& srcRect, CompositeOperator op, bool useLowQualityScale)
558 {
559     drawImageBuffer(image, styleColorSpace, FloatRect(dest), srcRect, op, useLowQualityScale);
560 }
561
562 void GraphicsContext::drawImageBuffer(ImageBuffer* image, ColorSpace styleColorSpace, const FloatRect& dest, const FloatRect& src, CompositeOperator op, bool useLowQualityScale)
563 {
564     if (paintingDisabled() || !image)
565         return;
566
567     float tsw = src.width();
568     float tsh = src.height();
569     float tw = dest.width();
570     float th = dest.height();
571
572     if (tsw == -1)
573         tsw = image->logicalSize().width();
574     if (tsh == -1)
575         tsh = image->logicalSize().height();
576
577     if (tw == -1)
578         tw = image->logicalSize().width();
579     if (th == -1)
580         th = image->logicalSize().height();
581
582     if (useLowQualityScale) {
583         InterpolationQuality previousInterpolationQuality = imageInterpolationQuality();
584 #if PLATFORM(CHROMIUM)
585         setImageInterpolationQuality(InterpolationLow);
586 #else
587         // FIXME (49002): Should be InterpolationLow
588         setImageInterpolationQuality(InterpolationNone);
589 #endif
590         image->draw(this, styleColorSpace, FloatRect(dest.location(), FloatSize(tw, th)), FloatRect(src.location(), FloatSize(tsw, tsh)), op, useLowQualityScale);
591         setImageInterpolationQuality(previousInterpolationQuality);
592     } else
593         image->draw(this, styleColorSpace, FloatRect(dest.location(), FloatSize(tw, th)), FloatRect(src.location(), FloatSize(tsw, tsh)), op, useLowQualityScale);
594 }
595
596 #if !PLATFORM(QT)
597 void GraphicsContext::clip(const IntRect& rect)
598 {
599     clip(FloatRect(rect));
600 }
601 #endif
602
603 void GraphicsContext::addRoundedRectClip(const RoundedRect& rect)
604 {
605     if (paintingDisabled())
606         return;
607
608     Path path;
609     path.addRoundedRect(rect);
610     clip(path);
611 }
612
613 void GraphicsContext::clipOutRoundedRect(const RoundedRect& rect)
614 {
615     if (paintingDisabled())
616         return;
617
618     Path path;
619     path.addRoundedRect(rect);
620     clipOut(path);
621 }
622
623 void GraphicsContext::clipToImageBuffer(ImageBuffer* buffer, const FloatRect& rect)
624 {
625     if (paintingDisabled())
626         return;
627     buffer->clip(this, rect);
628 }
629
630 #if !USE(CG) && !PLATFORM(QT) && !USE(CAIRO)
631 IntRect GraphicsContext::clipBounds() const
632 {
633     ASSERT_NOT_REACHED();
634     return IntRect();
635 }
636 #endif
637
638 TextDrawingModeFlags GraphicsContext::textDrawingMode() const
639 {
640     return m_state.textDrawingMode;
641 }
642
643 void GraphicsContext::setTextDrawingMode(TextDrawingModeFlags mode)
644 {
645     m_state.textDrawingMode = mode;
646     if (paintingDisabled())
647         return;
648     setPlatformTextDrawingMode(mode);
649 }
650
651 void GraphicsContext::fillRect(const FloatRect& rect, Generator& generator)
652 {
653     if (paintingDisabled())
654         return;
655     generator.fill(this, rect);
656 }
657
658 void GraphicsContext::fillRect(const FloatRect& rect, const Color& color, ColorSpace styleColorSpace, CompositeOperator op)
659 {
660     if (paintingDisabled())
661         return;
662
663     CompositeOperator previousOperator = compositeOperation();
664     setCompositeOperation(op);
665     fillRect(rect, color, styleColorSpace);
666     setCompositeOperation(previousOperator);
667 }
668
669 void GraphicsContext::fillRoundedRect(const RoundedRect& rect, const Color& color, ColorSpace colorSpace)
670 {
671     fillRoundedRect(rect.rect(), rect.radii().topLeft(), rect.radii().topRight(), rect.radii().bottomLeft(), rect.radii().bottomRight(), color, colorSpace);
672 }
673
674 #if !USE(CG)
675 void GraphicsContext::fillRectWithRoundedHole(const IntRect& rect, const RoundedRect& roundedHoleRect, const Color& color, ColorSpace colorSpace)
676 {
677     if (paintingDisabled())
678         return;
679
680     Path path;
681     path.addRect(rect);
682
683     if (!roundedHoleRect.radii().isZero())
684         path.addRoundedRect(roundedHoleRect);
685     else
686         path.addRect(roundedHoleRect.rect());
687
688     WindRule oldFillRule = fillRule();
689     Color oldFillColor = fillColor();
690     ColorSpace oldFillColorSpace = fillColorSpace();
691     
692     setFillRule(RULE_EVENODD);
693     setFillColor(color, colorSpace);
694
695     fillPath(path);
696     
697     setFillRule(oldFillRule);
698     setFillColor(oldFillColor, oldFillColorSpace);
699 }
700 #endif
701
702 void GraphicsContext::setCompositeOperation(CompositeOperator compositeOperation)
703 {
704     m_state.compositeOperator = compositeOperation;
705     setPlatformCompositeOperation(compositeOperation);
706 }
707
708 CompositeOperator GraphicsContext::compositeOperation() const
709 {
710     return m_state.compositeOperator;
711 }
712
713 #if !USE(CG) && !USE(SKIA)
714 // Implement this if you want to go ahead and push the drawing mode into your native context
715 // immediately.
716 void GraphicsContext::setPlatformTextDrawingMode(TextDrawingModeFlags)
717 {
718 }
719 #endif
720
721 #if !PLATFORM(QT) && !USE(CAIRO) && !USE(SKIA) && !PLATFORM(OPENVG)
722 void GraphicsContext::setPlatformStrokeStyle(StrokeStyle)
723 {
724 }
725 #endif
726
727 #if !USE(CG)
728 void GraphicsContext::setPlatformShouldSmoothFonts(bool)
729 {
730 }
731 #endif
732
733 #if !USE(SKIA) && !USE(CG)
734 bool GraphicsContext::isAcceleratedContext() const
735 {
736     return false;
737 }
738 #endif
739
740 void GraphicsContext::adjustLineToPixelBoundaries(FloatPoint& p1, FloatPoint& p2, float strokeWidth, StrokeStyle penStyle)
741 {
742     // For odd widths, we add in 0.5 to the appropriate x/y so that the float arithmetic
743     // works out.  For example, with a border width of 3, WebKit will pass us (y1+y2)/2, e.g.,
744     // (50+53)/2 = 103/2 = 51 when we want 51.5.  It is always true that an even width gave
745     // us a perfect position, but an odd width gave us a position that is off by exactly 0.5.
746     if (penStyle == DottedStroke || penStyle == DashedStroke) {
747         if (p1.x() == p2.x()) {
748             p1.setY(p1.y() + strokeWidth);
749             p2.setY(p2.y() - strokeWidth);
750         } else {
751             p1.setX(p1.x() + strokeWidth);
752             p2.setX(p2.x() - strokeWidth);
753         }
754     }
755
756     if (static_cast<int>(strokeWidth) % 2) { //odd
757         if (p1.x() == p2.x()) {
758             // We're a vertical line.  Adjust our x.
759             p1.setX(p1.x() + 0.5f);
760             p2.setX(p2.x() + 0.5f);
761         } else {
762             // We're a horizontal line. Adjust our y.
763             p1.setY(p1.y() + 0.5f);
764             p2.setY(p2.y() + 0.5f);
765         }
766     }
767 }
768
769 static bool scalesMatch(AffineTransform a, AffineTransform b)
770 {
771     return a.xScale() == b.xScale() && a.yScale() == b.yScale();
772 }
773
774 PassOwnPtr<ImageBuffer> GraphicsContext::createCompatibleBuffer(const IntSize& size, bool hasAlpha) const
775 {
776     // Make the buffer larger if the context's transform is scaling it so we need a higher
777     // resolution than one pixel per unit. Also set up a corresponding scale factor on the
778     // graphics context.
779
780     AffineTransform transform = getCTM(DefinitelyIncludeDeviceScale);
781     IntSize scaledSize(static_cast<int>(ceil(size.width() * transform.xScale())), static_cast<int>(ceil(size.height() * transform.yScale())));
782
783     OwnPtr<ImageBuffer> buffer = ImageBuffer::createCompatibleBuffer(scaledSize, 1, ColorSpaceDeviceRGB, this, hasAlpha);
784     if (!buffer)
785         return nullptr;
786
787     buffer->context()->scale(FloatSize(static_cast<float>(scaledSize.width()) / size.width(),
788         static_cast<float>(scaledSize.height()) / size.height()));
789
790     return buffer.release();
791 }
792
793 bool GraphicsContext::isCompatibleWithBuffer(ImageBuffer* buffer) const
794 {
795     GraphicsContext* bufferContext = buffer->context();
796
797     return scalesMatch(getCTM(), bufferContext->getCTM()) && isAcceleratedContext() == bufferContext->isAcceleratedContext();
798 }
799
800 #if !USE(CG)
801 void GraphicsContext::platformApplyDeviceScaleFactor(float)
802 {
803 }
804 #endif
805
806 void GraphicsContext::applyDeviceScaleFactor(float deviceScaleFactor)
807 {
808     scale(FloatSize(deviceScaleFactor, deviceScaleFactor));
809     platformApplyDeviceScaleFactor(deviceScaleFactor);
810 }
811
812 void GraphicsContext::fillEllipse(const FloatRect& ellipse)
813 {
814     platformFillEllipse(ellipse);
815 }
816
817 void GraphicsContext::strokeEllipse(const FloatRect& ellipse)
818 {
819     platformStrokeEllipse(ellipse);
820 }
821
822 void GraphicsContext::fillEllipseAsPath(const FloatRect& ellipse)
823 {
824     Path path;
825     path.addEllipse(ellipse);
826     fillPath(path);
827 }
828
829 void GraphicsContext::strokeEllipseAsPath(const FloatRect& ellipse)
830 {
831     Path path;
832     path.addEllipse(ellipse);
833     strokePath(path);
834 }
835
836 #if !USE(CG) && !USE(SKIA) // append && !USE(MYPLATFORM) here to optimize ellipses on your platform.
837 void GraphicsContext::platformFillEllipse(const FloatRect& ellipse)
838 {
839     if (paintingDisabled())
840         return;
841
842     fillEllipseAsPath(ellipse);
843 }
844
845 void GraphicsContext::platformStrokeEllipse(const FloatRect& ellipse)
846 {
847     if (paintingDisabled())
848         return;
849
850     strokeEllipseAsPath(ellipse);
851 }
852 #endif
853
854 }