Home | History | Annotate | Download | only in graphics
      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 "Font.h"
     31 #include "Generator.h"
     32 #include "ImageBuffer.h"
     33 #include "IntRect.h"
     34 #include "RoundedIntRect.h"
     35 #include "TextRun.h"
     36 
     37 using namespace std;
     38 
     39 namespace WebCore {
     40 
     41 class TextRunIterator {
     42 public:
     43     TextRunIterator()
     44         : m_textRun(0)
     45         , m_offset(0)
     46     {
     47     }
     48 
     49     TextRunIterator(const TextRun* textRun, unsigned offset)
     50         : m_textRun(textRun)
     51         , m_offset(offset)
     52     {
     53     }
     54 
     55     TextRunIterator(const TextRunIterator& other)
     56         : m_textRun(other.m_textRun)
     57         , m_offset(other.m_offset)
     58     {
     59     }
     60 
     61     unsigned offset() const { return m_offset; }
     62     void increment() { m_offset++; }
     63     bool atEnd() const { return !m_textRun || m_offset >= m_textRun->length(); }
     64     UChar current() const { return (*m_textRun)[m_offset]; }
     65     WTF::Unicode::Direction direction() const { return atEnd() ? WTF::Unicode::OtherNeutral : WTF::Unicode::direction(current()); }
     66 
     67     bool operator==(const TextRunIterator& other)
     68     {
     69         return m_offset == other.m_offset && m_textRun == other.m_textRun;
     70     }
     71 
     72     bool operator!=(const TextRunIterator& other) { return !operator==(other); }
     73 
     74 private:
     75     const TextRun* m_textRun;
     76     int m_offset;
     77 };
     78 
     79 GraphicsContext::GraphicsContext(PlatformGraphicsContext* platformGraphicsContext)
     80     : m_updatingControlTints(false)
     81 {
     82     platformInit(platformGraphicsContext);
     83 }
     84 
     85 GraphicsContext::~GraphicsContext()
     86 {
     87     platformDestroy();
     88 }
     89 
     90 void GraphicsContext::save()
     91 {
     92     if (paintingDisabled())
     93         return;
     94 
     95     m_stack.append(m_state);
     96 
     97     savePlatformState();
     98 }
     99 
    100 void GraphicsContext::restore()
    101 {
    102     if (paintingDisabled())
    103         return;
    104 
    105     if (m_stack.isEmpty()) {
    106         LOG_ERROR("ERROR void GraphicsContext::restore() stack is empty");
    107         return;
    108     }
    109     m_state = m_stack.last();
    110     m_stack.removeLast();
    111 
    112     restorePlatformState();
    113 }
    114 
    115 void GraphicsContext::setStrokeThickness(float thickness)
    116 {
    117     m_state.strokeThickness = thickness;
    118     setPlatformStrokeThickness(thickness);
    119 }
    120 
    121 void GraphicsContext::setStrokeStyle(StrokeStyle style)
    122 {
    123     m_state.strokeStyle = style;
    124     setPlatformStrokeStyle(style);
    125 }
    126 
    127 void GraphicsContext::setStrokeColor(const Color& color, ColorSpace colorSpace)
    128 {
    129     m_state.strokeColor = color;
    130     m_state.strokeColorSpace = colorSpace;
    131     m_state.strokeGradient.clear();
    132     m_state.strokePattern.clear();
    133     setPlatformStrokeColor(color, colorSpace);
    134 }
    135 
    136 void GraphicsContext::setShadow(const FloatSize& offset, float blur, const Color& color, ColorSpace colorSpace)
    137 {
    138     m_state.shadowOffset = offset;
    139     m_state.shadowBlur = blur;
    140     m_state.shadowColor = color;
    141     m_state.shadowColorSpace = colorSpace;
    142     setPlatformShadow(offset, blur, color, colorSpace);
    143 }
    144 
    145 void GraphicsContext::setLegacyShadow(const FloatSize& offset, float blur, const Color& color, ColorSpace colorSpace)
    146 {
    147     m_state.shadowOffset = offset;
    148     m_state.shadowBlur = blur;
    149     m_state.shadowColor = color;
    150     m_state.shadowColorSpace = colorSpace;
    151 #if USE(CG)
    152     m_state.shadowsUseLegacyRadius = true;
    153 #endif
    154     setPlatformShadow(offset, blur, color, colorSpace);
    155 }
    156 
    157 void GraphicsContext::clearShadow()
    158 {
    159     m_state.shadowOffset = FloatSize();
    160     m_state.shadowBlur = 0;
    161     m_state.shadowColor = Color();
    162     m_state.shadowColorSpace = ColorSpaceDeviceRGB;
    163     clearPlatformShadow();
    164 }
    165 
    166 bool GraphicsContext::hasShadow() const
    167 {
    168     return m_state.shadowColor.isValid() && m_state.shadowColor.alpha()
    169            && (m_state.shadowBlur || m_state.shadowOffset.width() || m_state.shadowOffset.height());
    170 }
    171 
    172 bool GraphicsContext::getShadow(FloatSize& offset, float& blur, Color& color, ColorSpace& colorSpace) const
    173 {
    174     offset = m_state.shadowOffset;
    175     blur = m_state.shadowBlur;
    176     color = m_state.shadowColor;
    177     colorSpace = m_state.shadowColorSpace;
    178 
    179     return hasShadow();
    180 }
    181 
    182 float GraphicsContext::strokeThickness() const
    183 {
    184     return m_state.strokeThickness;
    185 }
    186 
    187 StrokeStyle GraphicsContext::strokeStyle() const
    188 {
    189     return m_state.strokeStyle;
    190 }
    191 
    192 Color GraphicsContext::strokeColor() const
    193 {
    194     return m_state.strokeColor;
    195 }
    196 
    197 ColorSpace GraphicsContext::strokeColorSpace() const
    198 {
    199     return m_state.strokeColorSpace;
    200 }
    201 
    202 WindRule GraphicsContext::fillRule() const
    203 {
    204     return m_state.fillRule;
    205 }
    206 
    207 void GraphicsContext::setFillRule(WindRule fillRule)
    208 {
    209     m_state.fillRule = fillRule;
    210 }
    211 
    212 void GraphicsContext::setFillColor(const Color& color, ColorSpace colorSpace)
    213 {
    214     m_state.fillColor = color;
    215     m_state.fillColorSpace = colorSpace;
    216     m_state.fillGradient.clear();
    217     m_state.fillPattern.clear();
    218     setPlatformFillColor(color, colorSpace);
    219 }
    220 
    221 Color GraphicsContext::fillColor() const
    222 {
    223     return m_state.fillColor;
    224 }
    225 
    226 ColorSpace GraphicsContext::fillColorSpace() const
    227 {
    228     return m_state.fillColorSpace;
    229 }
    230 
    231 void GraphicsContext::setShouldAntialias(bool b)
    232 {
    233     m_state.shouldAntialias = b;
    234     setPlatformShouldAntialias(b);
    235 }
    236 
    237 bool GraphicsContext::shouldAntialias() const
    238 {
    239     return m_state.shouldAntialias;
    240 }
    241 
    242 void GraphicsContext::setShouldSmoothFonts(bool b)
    243 {
    244     m_state.shouldSmoothFonts = b;
    245     setPlatformShouldSmoothFonts(b);
    246 }
    247 
    248 bool GraphicsContext::shouldSmoothFonts() const
    249 {
    250     return m_state.shouldSmoothFonts;
    251 }
    252 
    253 const GraphicsContextState& GraphicsContext::state() const
    254 {
    255     return m_state;
    256 }
    257 
    258 void GraphicsContext::setStrokePattern(PassRefPtr<Pattern> pattern)
    259 {
    260     ASSERT(pattern);
    261     if (!pattern) {
    262         setStrokeColor(Color::black, ColorSpaceDeviceRGB);
    263         return;
    264     }
    265     m_state.strokeGradient.clear();
    266     m_state.strokePattern = pattern;
    267     setPlatformStrokePattern(m_state.strokePattern.get());
    268 }
    269 
    270 void GraphicsContext::setFillPattern(PassRefPtr<Pattern> pattern)
    271 {
    272     ASSERT(pattern);
    273     if (!pattern) {
    274         setFillColor(Color::black, ColorSpaceDeviceRGB);
    275         return;
    276     }
    277     m_state.fillGradient.clear();
    278     m_state.fillPattern = pattern;
    279     setPlatformFillPattern(m_state.fillPattern.get());
    280 }
    281 
    282 void GraphicsContext::setStrokeGradient(PassRefPtr<Gradient> gradient)
    283 {
    284     ASSERT(gradient);
    285     if (!gradient) {
    286         setStrokeColor(Color::black, ColorSpaceDeviceRGB);
    287         return;
    288     }
    289     m_state.strokeGradient = gradient;
    290     m_state.strokePattern.clear();
    291     setPlatformStrokeGradient(m_state.strokeGradient.get());
    292 }
    293 
    294 void GraphicsContext::setFillGradient(PassRefPtr<Gradient> gradient)
    295 {
    296     ASSERT(gradient);
    297     if (!gradient) {
    298         setFillColor(Color::black, ColorSpaceDeviceRGB);
    299         return;
    300     }
    301     m_state.fillGradient = gradient;
    302     m_state.fillPattern.clear();
    303     setPlatformFillGradient(m_state.fillGradient.get());
    304 }
    305 
    306 Gradient* GraphicsContext::fillGradient() const
    307 {
    308     return m_state.fillGradient.get();
    309 }
    310 
    311 Gradient* GraphicsContext::strokeGradient() const
    312 {
    313     return m_state.strokeGradient.get();
    314 }
    315 
    316 Pattern* GraphicsContext::fillPattern() const
    317 {
    318     return m_state.fillPattern.get();
    319 }
    320 
    321 Pattern* GraphicsContext::strokePattern() const
    322 {
    323     return m_state.strokePattern.get();
    324 }
    325 
    326 void GraphicsContext::setShadowsIgnoreTransforms(bool ignoreTransforms)
    327 {
    328     m_state.shadowsIgnoreTransforms = ignoreTransforms;
    329 }
    330 
    331 bool GraphicsContext::shadowsIgnoreTransforms() const
    332 {
    333     return m_state.shadowsIgnoreTransforms;
    334 }
    335 
    336 bool GraphicsContext::updatingControlTints() const
    337 {
    338     return m_updatingControlTints;
    339 }
    340 
    341 void GraphicsContext::setUpdatingControlTints(bool b)
    342 {
    343     setPaintingDisabled(b);
    344     m_updatingControlTints = b;
    345 }
    346 
    347 void GraphicsContext::setPaintingDisabled(bool f)
    348 {
    349     m_state.paintingDisabled = f;
    350 }
    351 
    352 bool GraphicsContext::paintingDisabled() const
    353 {
    354     return m_state.paintingDisabled;
    355 }
    356 
    357 void GraphicsContext::drawImage(Image* image, ColorSpace styleColorSpace, const IntPoint& p, CompositeOperator op)
    358 {
    359     drawImage(image, styleColorSpace, p, IntRect(0, 0, -1, -1), op);
    360 }
    361 
    362 void GraphicsContext::drawImage(Image* image, ColorSpace styleColorSpace, const IntRect& r, CompositeOperator op, bool useLowQualityScale)
    363 {
    364     drawImage(image, styleColorSpace, r, IntRect(0, 0, -1, -1), op, useLowQualityScale);
    365 }
    366 
    367 void GraphicsContext::drawImage(Image* image, ColorSpace styleColorSpace, const IntPoint& dest, const IntRect& srcRect, CompositeOperator op)
    368 {
    369     drawImage(image, styleColorSpace, IntRect(dest, srcRect.size()), srcRect, op);
    370 }
    371 
    372 void GraphicsContext::drawImage(Image* image, ColorSpace styleColorSpace, const IntRect& dest, const IntRect& srcRect, CompositeOperator op, bool useLowQualityScale)
    373 {
    374     drawImage(image, styleColorSpace, FloatRect(dest), srcRect, op, useLowQualityScale);
    375 }
    376 
    377 #if !OS(WINCE) || PLATFORM(QT)
    378 void GraphicsContext::drawText(const Font& font, const TextRun& run, const FloatPoint& point, int from, int to)
    379 {
    380     if (paintingDisabled())
    381         return;
    382 
    383     font.drawText(this, run, point, from, to);
    384 }
    385 #endif
    386 
    387 void GraphicsContext::drawEmphasisMarks(const Font& font, const TextRun& run, const AtomicString& mark, const FloatPoint& point, int from, int to)
    388 {
    389     if (paintingDisabled())
    390         return;
    391 
    392     font.drawEmphasisMarks(this, run, mark, point, from, to);
    393 }
    394 
    395 void GraphicsContext::drawBidiText(const Font& font, const TextRun& run, const FloatPoint& point)
    396 {
    397     if (paintingDisabled())
    398         return;
    399 
    400     // FIXME: This ownership should be reversed. We should pass BidiRunList
    401     // to BidiResolver in createBidiRunsForLine.
    402     BidiResolver<TextRunIterator, BidiCharacterRun> bidiResolver;
    403     BidiRunList<BidiCharacterRun>& bidiRuns = bidiResolver.runs();
    404 
    405     WTF::Unicode::Direction paragraphDirection = run.ltr() ? WTF::Unicode::LeftToRight : WTF::Unicode::RightToLeft;
    406 
    407     bidiResolver.setStatus(BidiStatus(paragraphDirection, paragraphDirection, paragraphDirection, BidiContext::create(run.ltr() ? 0 : 1, paragraphDirection, run.directionalOverride())));
    408 
    409     bidiResolver.setPosition(TextRunIterator(&run, 0));
    410     bidiResolver.createBidiRunsForLine(TextRunIterator(&run, run.length()));
    411 
    412     if (!bidiRuns.runCount())
    413         return;
    414 
    415     FloatPoint currPoint = point;
    416     BidiCharacterRun* bidiRun = bidiRuns.firstRun();
    417     while (bidiRun) {
    418 
    419         TextRun subrun = run;
    420         subrun.setText(run.data(bidiRun->start()), bidiRun->stop() - bidiRun->start());
    421         subrun.setRTL(bidiRun->level() % 2);
    422         subrun.setDirectionalOverride(bidiRun->dirOverride(false));
    423 
    424         font.drawText(this, subrun, currPoint);
    425 
    426         bidiRun = bidiRun->next();
    427         // FIXME: Have Font::drawText return the width of what it drew so that we don't have to re-measure here.
    428         if (bidiRun)
    429             currPoint.move(font.width(subrun), 0);
    430     }
    431 
    432     bidiRuns.deleteRuns();
    433 }
    434 
    435 #if !PLATFORM(ANDROID)
    436 void GraphicsContext::drawHighlightForText(const Font& font, const TextRun& run, const FloatPoint& point, int h, const Color& backgroundColor, ColorSpace colorSpace, int from, int to)
    437 {
    438     if (paintingDisabled())
    439         return;
    440 
    441     fillRect(font.selectionRectForText(run, point, h, from, to), backgroundColor, colorSpace);
    442 }
    443 #endif
    444 
    445 void GraphicsContext::drawImage(Image* image, ColorSpace styleColorSpace, const FloatRect& dest, const FloatRect& src, CompositeOperator op, bool useLowQualityScale)
    446 {
    447     if (paintingDisabled() || !image)
    448         return;
    449 
    450     float tsw = src.width();
    451     float tsh = src.height();
    452     float tw = dest.width();
    453     float th = dest.height();
    454 
    455     if (tsw == -1)
    456         tsw = image->width();
    457     if (tsh == -1)
    458         tsh = image->height();
    459 
    460     if (tw == -1)
    461         tw = image->width();
    462     if (th == -1)
    463         th = image->height();
    464 
    465     if (useLowQualityScale) {
    466         InterpolationQuality previousInterpolationQuality = imageInterpolationQuality();
    467         // FIXME: Should be InterpolationLow
    468         setImageInterpolationQuality(InterpolationNone);
    469         image->draw(this, FloatRect(dest.location(), FloatSize(tw, th)), FloatRect(src.location(), FloatSize(tsw, tsh)), styleColorSpace, op);
    470         setImageInterpolationQuality(previousInterpolationQuality);
    471     } else
    472         image->draw(this, FloatRect(dest.location(), FloatSize(tw, th)), FloatRect(src.location(), FloatSize(tsw, tsh)), styleColorSpace, op);
    473 }
    474 
    475 void GraphicsContext::drawTiledImage(Image* image, ColorSpace styleColorSpace, const IntRect& rect, const IntPoint& srcPoint, const IntSize& tileSize, CompositeOperator op, bool useLowQualityScale)
    476 {
    477     if (paintingDisabled() || !image)
    478         return;
    479 
    480     if (useLowQualityScale) {
    481         InterpolationQuality previousInterpolationQuality = imageInterpolationQuality();
    482         setImageInterpolationQuality(InterpolationLow);
    483         image->drawTiled(this, rect, srcPoint, tileSize, styleColorSpace, op);
    484         setImageInterpolationQuality(previousInterpolationQuality);
    485     } else
    486         image->drawTiled(this, rect, srcPoint, tileSize, styleColorSpace, op);
    487 }
    488 
    489 void GraphicsContext::drawTiledImage(Image* image, ColorSpace styleColorSpace, const IntRect& dest, const IntRect& srcRect, Image::TileRule hRule, Image::TileRule vRule, CompositeOperator op, bool useLowQualityScale)
    490 {
    491     if (paintingDisabled() || !image)
    492         return;
    493 
    494     if (hRule == Image::StretchTile && vRule == Image::StretchTile) {
    495         // Just do a scale.
    496         drawImage(image, styleColorSpace, dest, srcRect, op);
    497         return;
    498     }
    499 
    500     if (useLowQualityScale) {
    501         InterpolationQuality previousInterpolationQuality = imageInterpolationQuality();
    502         setImageInterpolationQuality(InterpolationLow);
    503         image->drawTiled(this, dest, srcRect, hRule, vRule, styleColorSpace, op);
    504         setImageInterpolationQuality(previousInterpolationQuality);
    505     } else
    506         image->drawTiled(this, dest, srcRect, hRule, vRule, styleColorSpace, op);
    507 }
    508 
    509 void GraphicsContext::drawImageBuffer(ImageBuffer* image, ColorSpace styleColorSpace, const IntPoint& p, CompositeOperator op)
    510 {
    511     drawImageBuffer(image, styleColorSpace, p, IntRect(0, 0, -1, -1), op);
    512 }
    513 
    514 void GraphicsContext::drawImageBuffer(ImageBuffer* image, ColorSpace styleColorSpace, const IntRect& r, CompositeOperator op, bool useLowQualityScale)
    515 {
    516     drawImageBuffer(image, styleColorSpace, r, IntRect(0, 0, -1, -1), op, useLowQualityScale);
    517 }
    518 
    519 void GraphicsContext::drawImageBuffer(ImageBuffer* image, ColorSpace styleColorSpace, const IntPoint& dest, const IntRect& srcRect, CompositeOperator op)
    520 {
    521     drawImageBuffer(image, styleColorSpace, IntRect(dest, srcRect.size()), srcRect, op);
    522 }
    523 
    524 void GraphicsContext::drawImageBuffer(ImageBuffer* image, ColorSpace styleColorSpace, const IntRect& dest, const IntRect& srcRect, CompositeOperator op, bool useLowQualityScale)
    525 {
    526     drawImageBuffer(image, styleColorSpace, FloatRect(dest), srcRect, op, useLowQualityScale);
    527 }
    528 
    529 void GraphicsContext::drawImageBuffer(ImageBuffer* image, ColorSpace styleColorSpace, const FloatRect& dest, const FloatRect& src, CompositeOperator op, bool useLowQualityScale)
    530 {
    531     if (paintingDisabled() || !image)
    532         return;
    533 
    534     float tsw = src.width();
    535     float tsh = src.height();
    536     float tw = dest.width();
    537     float th = dest.height();
    538 
    539     if (tsw == -1)
    540         tsw = image->width();
    541     if (tsh == -1)
    542         tsh = image->height();
    543 
    544     if (tw == -1)
    545         tw = image->width();
    546     if (th == -1)
    547         th = image->height();
    548 
    549     if (useLowQualityScale) {
    550         InterpolationQuality previousInterpolationQuality = imageInterpolationQuality();
    551         // FIXME: Should be InterpolationLow
    552         setImageInterpolationQuality(InterpolationNone);
    553         image->draw(this, styleColorSpace, FloatRect(dest.location(), FloatSize(tw, th)), FloatRect(src.location(), FloatSize(tsw, tsh)), op, useLowQualityScale);
    554         setImageInterpolationQuality(previousInterpolationQuality);
    555     } else
    556         image->draw(this, styleColorSpace, FloatRect(dest.location(), FloatSize(tw, th)), FloatRect(src.location(), FloatSize(tsw, tsh)), op, useLowQualityScale);
    557 }
    558 
    559 #if !PLATFORM(QT)
    560 void GraphicsContext::clip(const IntRect& rect)
    561 {
    562     clip(FloatRect(rect));
    563 }
    564 #endif
    565 
    566 void GraphicsContext::addRoundedRectClip(const RoundedIntRect& rect)
    567 {
    568     if (paintingDisabled())
    569         return;
    570 
    571     Path path;
    572     path.addRoundedRect(rect);
    573     clip(path);
    574 }
    575 
    576 void GraphicsContext::clipOutRoundedRect(const RoundedIntRect& rect)
    577 {
    578     if (paintingDisabled())
    579         return;
    580 
    581     Path path;
    582     path.addRoundedRect(rect);
    583     clipOut(path);
    584 }
    585 
    586 void GraphicsContext::clipToImageBuffer(ImageBuffer* buffer, const FloatRect& rect)
    587 {
    588     if (paintingDisabled())
    589         return;
    590     buffer->clip(this, rect);
    591 }
    592 
    593 #if !USE(CG)
    594 IntRect GraphicsContext::clipBounds() const
    595 {
    596     ASSERT_NOT_REACHED();
    597     return IntRect();
    598 }
    599 #endif
    600 
    601 TextDrawingModeFlags GraphicsContext::textDrawingMode() const
    602 {
    603     return m_state.textDrawingMode;
    604 }
    605 
    606 void GraphicsContext::setTextDrawingMode(TextDrawingModeFlags mode)
    607 {
    608     m_state.textDrawingMode = mode;
    609     if (paintingDisabled())
    610         return;
    611     setPlatformTextDrawingMode(mode);
    612 }
    613 
    614 void GraphicsContext::fillRect(const FloatRect& rect, Generator& generator)
    615 {
    616     if (paintingDisabled())
    617         return;
    618     generator.fill(this, rect);
    619 }
    620 
    621 void GraphicsContext::fillRoundedRect(const RoundedIntRect& rect, const Color& color, ColorSpace colorSpace)
    622 {
    623     fillRoundedRect(rect.rect(), rect.radii().topLeft(), rect.radii().topRight(), rect.radii().bottomLeft(), rect.radii().bottomRight(), color, colorSpace);
    624 }
    625 
    626 #if !USE(CG)
    627 void GraphicsContext::fillRectWithRoundedHole(const IntRect& rect, const RoundedIntRect& roundedHoleRect, const Color& color, ColorSpace colorSpace)
    628 {
    629     if (paintingDisabled())
    630         return;
    631 
    632     Path path;
    633     path.addRect(rect);
    634 
    635     if (!roundedHoleRect.radii().isZero())
    636         path.addRoundedRect(roundedHoleRect);
    637     else
    638         path.addRect(roundedHoleRect.rect());
    639 
    640     WindRule oldFillRule = fillRule();
    641     Color oldFillColor = fillColor();
    642     ColorSpace oldFillColorSpace = fillColorSpace();
    643 
    644     setFillRule(RULE_EVENODD);
    645     setFillColor(color, colorSpace);
    646 
    647     fillPath(path);
    648 
    649     setFillRule(oldFillRule);
    650     setFillColor(oldFillColor, oldFillColorSpace);
    651 }
    652 #endif
    653 
    654 void GraphicsContext::setCompositeOperation(CompositeOperator compositeOperation)
    655 {
    656     m_state.compositeOperator = compositeOperation;
    657     setPlatformCompositeOperation(compositeOperation);
    658 }
    659 
    660 CompositeOperator GraphicsContext::compositeOperation() const
    661 {
    662     return m_state.compositeOperator;
    663 }
    664 
    665 #if !USE(SKIA)
    666 void GraphicsContext::setPlatformFillGradient(Gradient*)
    667 {
    668 }
    669 
    670 void GraphicsContext::setPlatformFillPattern(Pattern*)
    671 {
    672 }
    673 
    674 void GraphicsContext::setPlatformStrokeGradient(Gradient*)
    675 {
    676 }
    677 
    678 void GraphicsContext::setPlatformStrokePattern(Pattern*)
    679 {
    680 }
    681 #endif
    682 
    683 #if !USE(CG) && !(USE(SKIA) && !PLATFORM(ANDROID))
    684 // Implement this if you want to go ahead and push the drawing mode into your native context
    685 // immediately.
    686 void GraphicsContext::setPlatformTextDrawingMode(TextDrawingModeFlags mode)
    687 {
    688 }
    689 #endif
    690 
    691 #if !PLATFORM(QT) && !USE(CAIRO) && !USE(SKIA) && !PLATFORM(OPENVG)
    692 void GraphicsContext::setPlatformStrokeStyle(StrokeStyle)
    693 {
    694 }
    695 #endif
    696 
    697 #if !USE(CG)
    698 void GraphicsContext::setPlatformShouldSmoothFonts(bool)
    699 {
    700 }
    701 #endif
    702 
    703 #if !USE(SKIA)
    704 void GraphicsContext::setSharedGraphicsContext3D(SharedGraphicsContext3D*, DrawingBuffer*, const IntSize&)
    705 {
    706 }
    707 
    708 void GraphicsContext::syncSoftwareCanvas()
    709 {
    710 }
    711 
    712 void GraphicsContext::markDirtyRect(const IntRect&)
    713 {
    714 }
    715 #endif
    716 
    717 
    718 void GraphicsContext::adjustLineToPixelBoundaries(FloatPoint& p1, FloatPoint& p2, float strokeWidth, StrokeStyle penStyle)
    719 {
    720     // For odd widths, we add in 0.5 to the appropriate x/y so that the float arithmetic
    721     // works out.  For example, with a border width of 3, WebKit will pass us (y1+y2)/2, e.g.,
    722     // (50+53)/2 = 103/2 = 51 when we want 51.5.  It is always true that an even width gave
    723     // us a perfect position, but an odd width gave us a position that is off by exactly 0.5.
    724     if (penStyle == DottedStroke || penStyle == DashedStroke) {
    725         if (p1.x() == p2.x()) {
    726             p1.setY(p1.y() + strokeWidth);
    727             p2.setY(p2.y() - strokeWidth);
    728         } else {
    729             p1.setX(p1.x() + strokeWidth);
    730             p2.setX(p2.x() - strokeWidth);
    731         }
    732     }
    733 
    734     if (static_cast<int>(strokeWidth) % 2) { //odd
    735         if (p1.x() == p2.x()) {
    736             // We're a vertical line.  Adjust our x.
    737             p1.setX(p1.x() + 0.5f);
    738             p2.setX(p2.x() + 0.5f);
    739         } else {
    740             // We're a horizontal line. Adjust our y.
    741             p1.setY(p1.y() + 0.5f);
    742             p2.setY(p2.y() + 0.5f);
    743         }
    744     }
    745 }
    746 
    747 }
    748