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 void GraphicsContext::drawHighlightForText(const Font& font, const TextRun& run, const FloatPoint& point, int h, const Color& backgroundColor, ColorSpace colorSpace, int from, int to)
    436 {
    437     if (paintingDisabled())
    438         return;
    439 
    440     fillRect(font.selectionRectForText(run, point, h, from, to), backgroundColor, colorSpace);
    441 }
    442 
    443 void GraphicsContext::drawImage(Image* image, ColorSpace styleColorSpace, const FloatRect& dest, const FloatRect& src, CompositeOperator op, bool useLowQualityScale)
    444 {
    445     if (paintingDisabled() || !image)
    446         return;
    447 
    448     float tsw = src.width();
    449     float tsh = src.height();
    450     float tw = dest.width();
    451     float th = dest.height();
    452 
    453     if (tsw == -1)
    454         tsw = image->width();
    455     if (tsh == -1)
    456         tsh = image->height();
    457 
    458     if (tw == -1)
    459         tw = image->width();
    460     if (th == -1)
    461         th = image->height();
    462 
    463     if (useLowQualityScale) {
    464         InterpolationQuality previousInterpolationQuality = imageInterpolationQuality();
    465         // FIXME: Should be InterpolationLow
    466         setImageInterpolationQuality(InterpolationNone);
    467         image->draw(this, FloatRect(dest.location(), FloatSize(tw, th)), FloatRect(src.location(), FloatSize(tsw, tsh)), styleColorSpace, op);
    468         setImageInterpolationQuality(previousInterpolationQuality);
    469     } else
    470         image->draw(this, FloatRect(dest.location(), FloatSize(tw, th)), FloatRect(src.location(), FloatSize(tsw, tsh)), styleColorSpace, op);
    471 }
    472 
    473 void GraphicsContext::drawTiledImage(Image* image, ColorSpace styleColorSpace, const IntRect& rect, const IntPoint& srcPoint, const IntSize& tileSize, CompositeOperator op, bool useLowQualityScale)
    474 {
    475     if (paintingDisabled() || !image)
    476         return;
    477 
    478     if (useLowQualityScale) {
    479         InterpolationQuality previousInterpolationQuality = imageInterpolationQuality();
    480         setImageInterpolationQuality(InterpolationLow);
    481         image->drawTiled(this, rect, srcPoint, tileSize, styleColorSpace, op);
    482         setImageInterpolationQuality(previousInterpolationQuality);
    483     } else
    484         image->drawTiled(this, rect, srcPoint, tileSize, styleColorSpace, op);
    485 }
    486 
    487 void GraphicsContext::drawTiledImage(Image* image, ColorSpace styleColorSpace, const IntRect& dest, const IntRect& srcRect, Image::TileRule hRule, Image::TileRule vRule, CompositeOperator op, bool useLowQualityScale)
    488 {
    489     if (paintingDisabled() || !image)
    490         return;
    491 
    492     if (hRule == Image::StretchTile && vRule == Image::StretchTile) {
    493         // Just do a scale.
    494         drawImage(image, styleColorSpace, dest, srcRect, op);
    495         return;
    496     }
    497 
    498     if (useLowQualityScale) {
    499         InterpolationQuality previousInterpolationQuality = imageInterpolationQuality();
    500         setImageInterpolationQuality(InterpolationLow);
    501         image->drawTiled(this, dest, srcRect, hRule, vRule, styleColorSpace, op);
    502         setImageInterpolationQuality(previousInterpolationQuality);
    503     } else
    504         image->drawTiled(this, dest, srcRect, hRule, vRule, styleColorSpace, op);
    505 }
    506 
    507 void GraphicsContext::drawImageBuffer(ImageBuffer* image, ColorSpace styleColorSpace, const IntPoint& p, CompositeOperator op)
    508 {
    509     drawImageBuffer(image, styleColorSpace, p, IntRect(0, 0, -1, -1), op);
    510 }
    511 
    512 void GraphicsContext::drawImageBuffer(ImageBuffer* image, ColorSpace styleColorSpace, const IntRect& r, CompositeOperator op, bool useLowQualityScale)
    513 {
    514     drawImageBuffer(image, styleColorSpace, r, IntRect(0, 0, -1, -1), op, useLowQualityScale);
    515 }
    516 
    517 void GraphicsContext::drawImageBuffer(ImageBuffer* image, ColorSpace styleColorSpace, const IntPoint& dest, const IntRect& srcRect, CompositeOperator op)
    518 {
    519     drawImageBuffer(image, styleColorSpace, IntRect(dest, srcRect.size()), srcRect, op);
    520 }
    521 
    522 void GraphicsContext::drawImageBuffer(ImageBuffer* image, ColorSpace styleColorSpace, const IntRect& dest, const IntRect& srcRect, CompositeOperator op, bool useLowQualityScale)
    523 {
    524     drawImageBuffer(image, styleColorSpace, FloatRect(dest), srcRect, op, useLowQualityScale);
    525 }
    526 
    527 void GraphicsContext::drawImageBuffer(ImageBuffer* image, ColorSpace styleColorSpace, const FloatRect& dest, const FloatRect& src, CompositeOperator op, bool useLowQualityScale)
    528 {
    529     if (paintingDisabled() || !image)
    530         return;
    531 
    532     float tsw = src.width();
    533     float tsh = src.height();
    534     float tw = dest.width();
    535     float th = dest.height();
    536 
    537     if (tsw == -1)
    538         tsw = image->width();
    539     if (tsh == -1)
    540         tsh = image->height();
    541 
    542     if (tw == -1)
    543         tw = image->width();
    544     if (th == -1)
    545         th = image->height();
    546 
    547     if (useLowQualityScale) {
    548         InterpolationQuality previousInterpolationQuality = imageInterpolationQuality();
    549         // FIXME: Should be InterpolationLow
    550         setImageInterpolationQuality(InterpolationNone);
    551         image->draw(this, styleColorSpace, FloatRect(dest.location(), FloatSize(tw, th)), FloatRect(src.location(), FloatSize(tsw, tsh)), op, useLowQualityScale);
    552         setImageInterpolationQuality(previousInterpolationQuality);
    553     } else
    554         image->draw(this, styleColorSpace, FloatRect(dest.location(), FloatSize(tw, th)), FloatRect(src.location(), FloatSize(tsw, tsh)), op, useLowQualityScale);
    555 }
    556 
    557 #if !PLATFORM(QT)
    558 void GraphicsContext::clip(const IntRect& rect)
    559 {
    560     clip(FloatRect(rect));
    561 }
    562 #endif
    563 
    564 void GraphicsContext::addRoundedRectClip(const RoundedIntRect& rect)
    565 {
    566     if (paintingDisabled())
    567         return;
    568 
    569     Path path;
    570     path.addRoundedRect(rect);
    571     clip(path);
    572 }
    573 
    574 void GraphicsContext::clipOutRoundedRect(const RoundedIntRect& rect)
    575 {
    576     if (paintingDisabled())
    577         return;
    578 
    579     Path path;
    580     path.addRoundedRect(rect);
    581     clipOut(path);
    582 }
    583 
    584 void GraphicsContext::clipToImageBuffer(ImageBuffer* buffer, const FloatRect& rect)
    585 {
    586     if (paintingDisabled())
    587         return;
    588     buffer->clip(this, rect);
    589 }
    590 
    591 #if !USE(CG)
    592 IntRect GraphicsContext::clipBounds() const
    593 {
    594     ASSERT_NOT_REACHED();
    595     return IntRect();
    596 }
    597 #endif
    598 
    599 TextDrawingModeFlags GraphicsContext::textDrawingMode() const
    600 {
    601     return m_state.textDrawingMode;
    602 }
    603 
    604 void GraphicsContext::setTextDrawingMode(TextDrawingModeFlags mode)
    605 {
    606     m_state.textDrawingMode = mode;
    607     if (paintingDisabled())
    608         return;
    609     setPlatformTextDrawingMode(mode);
    610 }
    611 
    612 void GraphicsContext::fillRect(const FloatRect& rect, Generator& generator)
    613 {
    614     if (paintingDisabled())
    615         return;
    616     generator.fill(this, rect);
    617 }
    618 
    619 void GraphicsContext::fillRoundedRect(const RoundedIntRect& rect, const Color& color, ColorSpace colorSpace)
    620 {
    621     fillRoundedRect(rect.rect(), rect.radii().topLeft(), rect.radii().topRight(), rect.radii().bottomLeft(), rect.radii().bottomRight(), color, colorSpace);
    622 }
    623 
    624 #if !USE(CG)
    625 void GraphicsContext::fillRectWithRoundedHole(const IntRect& rect, const RoundedIntRect& roundedHoleRect, const Color& color, ColorSpace colorSpace)
    626 {
    627     if (paintingDisabled())
    628         return;
    629 
    630     Path path;
    631     path.addRect(rect);
    632 
    633     if (!roundedHoleRect.radii().isZero())
    634         path.addRoundedRect(roundedHoleRect);
    635     else
    636         path.addRect(roundedHoleRect.rect());
    637 
    638     WindRule oldFillRule = fillRule();
    639     Color oldFillColor = fillColor();
    640     ColorSpace oldFillColorSpace = fillColorSpace();
    641 
    642     setFillRule(RULE_EVENODD);
    643     setFillColor(color, colorSpace);
    644 
    645     fillPath(path);
    646 
    647     setFillRule(oldFillRule);
    648     setFillColor(oldFillColor, oldFillColorSpace);
    649 }
    650 #endif
    651 
    652 void GraphicsContext::setCompositeOperation(CompositeOperator compositeOperation)
    653 {
    654     m_state.compositeOperator = compositeOperation;
    655     setPlatformCompositeOperation(compositeOperation);
    656 }
    657 
    658 CompositeOperator GraphicsContext::compositeOperation() const
    659 {
    660     return m_state.compositeOperator;
    661 }
    662 
    663 #if !(USE(SKIA) && !PLATFORM(ANDROID))
    664 void GraphicsContext::setPlatformFillGradient(Gradient*)
    665 {
    666 }
    667 
    668 void GraphicsContext::setPlatformFillPattern(Pattern*)
    669 {
    670 }
    671 
    672 void GraphicsContext::setPlatformStrokeGradient(Gradient*)
    673 {
    674 }
    675 
    676 void GraphicsContext::setPlatformStrokePattern(Pattern*)
    677 {
    678 }
    679 #endif
    680 
    681 #if !USE(CG) && !(USE(SKIA) && !PLATFORM(ANDROID))
    682 // Implement this if you want to go ahead and push the drawing mode into your native context
    683 // immediately.
    684 void GraphicsContext::setPlatformTextDrawingMode(TextDrawingModeFlags mode)
    685 {
    686 }
    687 #endif
    688 
    689 #if !PLATFORM(QT) && !USE(CAIRO) && !(USE(SKIA) && !PLATFORM(ANDROID)) && !PLATFORM(HAIKU) && !PLATFORM(OPENVG)
    690 void GraphicsContext::setPlatformStrokeStyle(StrokeStyle)
    691 {
    692 }
    693 #endif
    694 
    695 #if !USE(CG)
    696 void GraphicsContext::setPlatformShouldSmoothFonts(bool)
    697 {
    698 }
    699 #endif
    700 
    701 #if !USE(SKIA)
    702 void GraphicsContext::setSharedGraphicsContext3D(SharedGraphicsContext3D*, DrawingBuffer*, const IntSize&)
    703 {
    704 }
    705 
    706 void GraphicsContext::syncSoftwareCanvas()
    707 {
    708 }
    709 
    710 void GraphicsContext::markDirtyRect(const IntRect&)
    711 {
    712 }
    713 #endif
    714 
    715 
    716 void GraphicsContext::adjustLineToPixelBoundaries(FloatPoint& p1, FloatPoint& p2, float strokeWidth, StrokeStyle penStyle)
    717 {
    718     // For odd widths, we add in 0.5 to the appropriate x/y so that the float arithmetic
    719     // works out.  For example, with a border width of 3, WebKit will pass us (y1+y2)/2, e.g.,
    720     // (50+53)/2 = 103/2 = 51 when we want 51.5.  It is always true that an even width gave
    721     // us a perfect position, but an odd width gave us a position that is off by exactly 0.5.
    722     if (penStyle == DottedStroke || penStyle == DashedStroke) {
    723         if (p1.x() == p2.x()) {
    724             p1.setY(p1.y() + strokeWidth);
    725             p2.setY(p2.y() - strokeWidth);
    726         } else {
    727             p1.setX(p1.x() + strokeWidth);
    728             p2.setX(p2.x() - strokeWidth);
    729         }
    730     }
    731 
    732     if (static_cast<int>(strokeWidth) % 2) { //odd
    733         if (p1.x() == p2.x()) {
    734             // We're a vertical line.  Adjust our x.
    735             p1.setX(p1.x() + 0.5f);
    736             p2.setX(p2.x() + 0.5f);
    737         } else {
    738             // We're a horizontal line. Adjust our y.
    739             p1.setY(p1.y() + 0.5f);
    740             p2.setY(p2.y() + 0.5f);
    741         }
    742     }
    743 }
    744 
    745 }
    746