• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2003, 2004, 2005, 2006 Apple Computer, 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 COMPUTER, INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25 
26 #include "config.h"
27 #include "GraphicsContext.h"
28 
29 #include "BidiResolver.h"
30 #include "Generator.h"
31 #include "GraphicsContextPrivate.h"
32 #include "Font.h"
33 #include "NotImplemented.h"
34 
35 using namespace std;
36 
37 namespace WebCore {
38 
39 class TextRunIterator {
40 public:
TextRunIterator()41     TextRunIterator()
42         : m_textRun(0)
43         , m_offset(0)
44     {
45     }
46 
TextRunIterator(const TextRun * textRun,unsigned offset)47     TextRunIterator(const TextRun* textRun, unsigned offset)
48         : m_textRun(textRun)
49         , m_offset(offset)
50     {
51     }
52 
TextRunIterator(const TextRunIterator & other)53     TextRunIterator(const TextRunIterator& other)
54         : m_textRun(other.m_textRun)
55         , m_offset(other.m_offset)
56     {
57     }
58 
offset() const59     unsigned offset() const { return m_offset; }
increment()60     void increment() { m_offset++; }
atEnd() const61     bool atEnd() const { return !m_textRun || m_offset >= m_textRun->length(); }
current() const62     UChar current() const { return (*m_textRun)[m_offset]; }
direction() const63     WTF::Unicode::Direction direction() const { return atEnd() ? WTF::Unicode::OtherNeutral : WTF::Unicode::direction(current()); }
64 
operator ==(const TextRunIterator & other)65     bool operator==(const TextRunIterator& other)
66     {
67         return m_offset == other.m_offset && m_textRun == other.m_textRun;
68     }
69 
operator !=(const TextRunIterator & other)70     bool operator!=(const TextRunIterator& other) { return !operator==(other); }
71 
72 private:
73     const TextRun* m_textRun;
74     int m_offset;
75 };
76 
createGraphicsContextPrivate()77 GraphicsContextPrivate* GraphicsContext::createGraphicsContextPrivate()
78 {
79     return new GraphicsContextPrivate;
80 }
81 
destroyGraphicsContextPrivate(GraphicsContextPrivate * deleteMe)82 void GraphicsContext::destroyGraphicsContextPrivate(GraphicsContextPrivate* deleteMe)
83 {
84     delete deleteMe;
85 }
86 
save()87 void GraphicsContext::save()
88 {
89     if (paintingDisabled())
90         return;
91 
92     m_common->stack.append(m_common->state);
93 
94     savePlatformState();
95 }
96 
restore()97 void GraphicsContext::restore()
98 {
99     if (paintingDisabled())
100         return;
101 
102     if (m_common->stack.isEmpty()) {
103         LOG_ERROR("ERROR void GraphicsContext::restore() stack is empty");
104         return;
105     }
106     m_common->state = m_common->stack.last();
107     m_common->stack.removeLast();
108 
109     restorePlatformState();
110 }
111 
setStrokeThickness(float thickness)112 void GraphicsContext::setStrokeThickness(float thickness)
113 {
114     m_common->state.strokeThickness = thickness;
115     setPlatformStrokeThickness(thickness);
116 }
117 
setStrokeStyle(const StrokeStyle & style)118 void GraphicsContext::setStrokeStyle(const StrokeStyle& style)
119 {
120     m_common->state.strokeStyle = style;
121     setPlatformStrokeStyle(style);
122 }
123 
setStrokeColor(const Color & color)124 void GraphicsContext::setStrokeColor(const Color& color)
125 {
126     m_common->state.strokeColorSpace = SolidColorSpace;
127     m_common->state.strokeColor = color;
128     setPlatformStrokeColor(color);
129 }
130 
setShadow(const IntSize & size,int blur,const Color & color)131 void GraphicsContext::setShadow(const IntSize& size, int blur, const Color& color)
132 {
133     m_common->state.shadowSize = size;
134     m_common->state.shadowBlur = blur;
135     m_common->state.shadowColor = color;
136     setPlatformShadow(size, blur, color);
137 }
138 
clearShadow()139 void GraphicsContext::clearShadow()
140 {
141     m_common->state.shadowSize = IntSize();
142     m_common->state.shadowBlur = 0;
143     m_common->state.shadowColor = Color();
144     clearPlatformShadow();
145 }
146 
getShadow(IntSize & size,int & blur,Color & color) const147 bool GraphicsContext::getShadow(IntSize& size, int& blur, Color& color) const
148 {
149     size = m_common->state.shadowSize;
150     blur = m_common->state.shadowBlur;
151     color = m_common->state.shadowColor;
152 
153     return color.isValid() && color.alpha() && (blur || size.width() || size.height());
154 }
155 
strokeThickness() const156 float GraphicsContext::strokeThickness() const
157 {
158     return m_common->state.strokeThickness;
159 }
160 
strokeStyle() const161 StrokeStyle GraphicsContext::strokeStyle() const
162 {
163     return m_common->state.strokeStyle;
164 }
165 
strokeColor() const166 Color GraphicsContext::strokeColor() const
167 {
168     return m_common->state.strokeColor;
169 }
170 
fillRule() const171 WindRule GraphicsContext::fillRule() const
172 {
173     return m_common->state.fillRule;
174 }
175 
setFillRule(WindRule fillRule)176 void GraphicsContext::setFillRule(WindRule fillRule)
177 {
178     m_common->state.fillRule = fillRule;
179 }
180 
spreadMethod() const181 GradientSpreadMethod GraphicsContext::spreadMethod() const
182 {
183     return m_common->state.spreadMethod;
184 }
185 
setSpreadMethod(GradientSpreadMethod spreadMethod)186 void GraphicsContext::setSpreadMethod(GradientSpreadMethod spreadMethod)
187 {
188     m_common->state.spreadMethod = spreadMethod;
189 }
190 
setFillColor(const Color & color)191 void GraphicsContext::setFillColor(const Color& color)
192 {
193     m_common->state.fillColorSpace = SolidColorSpace;
194     m_common->state.fillColor = color;
195     setPlatformFillColor(color);
196 }
197 
fillColor() const198 Color GraphicsContext::fillColor() const
199 {
200     return m_common->state.fillColor;
201 }
202 
setShouldAntialias(bool b)203 void GraphicsContext::setShouldAntialias(bool b)
204 {
205     m_common->state.shouldAntialias = b;
206     setPlatformShouldAntialias(b);
207 }
208 
shouldAntialias() const209 bool GraphicsContext::shouldAntialias() const
210 {
211     return m_common->state.shouldAntialias;
212 }
213 
setStrokePattern(PassRefPtr<Pattern> pattern)214 void GraphicsContext::setStrokePattern(PassRefPtr<Pattern> pattern)
215 {
216     ASSERT(pattern);
217     if (!pattern) {
218         setStrokeColor(Color::black);
219         return;
220     }
221     m_common->state.strokeColorSpace = PatternColorSpace;
222     m_common->state.strokePattern = pattern;
223 }
224 
setFillPattern(PassRefPtr<Pattern> pattern)225 void GraphicsContext::setFillPattern(PassRefPtr<Pattern> pattern)
226 {
227     ASSERT(pattern);
228     if (!pattern) {
229         setFillColor(Color::black);
230         return;
231     }
232     m_common->state.fillColorSpace = PatternColorSpace;
233     m_common->state.fillPattern = pattern;
234 }
235 
setStrokeGradient(PassRefPtr<Gradient> gradient)236 void GraphicsContext::setStrokeGradient(PassRefPtr<Gradient> gradient)
237 {
238     ASSERT(gradient);
239     if (!gradient) {
240         setStrokeColor(Color::black);
241         return;
242     }
243     m_common->state.strokeColorSpace = GradientColorSpace;
244     m_common->state.strokeGradient = gradient;
245 }
246 
setFillGradient(PassRefPtr<Gradient> gradient)247 void GraphicsContext::setFillGradient(PassRefPtr<Gradient> gradient)
248 {
249     ASSERT(gradient);
250     if (!gradient) {
251         setFillColor(Color::black);
252         return;
253     }
254     m_common->state.fillColorSpace = GradientColorSpace;
255     m_common->state.fillGradient = gradient;
256 }
257 
setShadowsIgnoreTransforms(bool ignoreTransforms)258 void GraphicsContext::setShadowsIgnoreTransforms(bool ignoreTransforms)
259 {
260     m_common->state.shadowsIgnoreTransforms = ignoreTransforms;
261 }
262 
updatingControlTints() const263 bool GraphicsContext::updatingControlTints() const
264 {
265     return m_common->m_updatingControlTints;
266 }
267 
setUpdatingControlTints(bool b)268 void GraphicsContext::setUpdatingControlTints(bool b)
269 {
270     setPaintingDisabled(b);
271     m_common->m_updatingControlTints = b;
272 }
273 
setPaintingDisabled(bool f)274 void GraphicsContext::setPaintingDisabled(bool f)
275 {
276     m_common->state.paintingDisabled = f;
277 }
278 
paintingDisabled() const279 bool GraphicsContext::paintingDisabled() const
280 {
281     return m_common->state.paintingDisabled;
282 }
283 
drawImage(Image * image,const IntPoint & p,CompositeOperator op)284 void GraphicsContext::drawImage(Image* image, const IntPoint& p, CompositeOperator op)
285 {
286     drawImage(image, p, IntRect(0, 0, -1, -1), op);
287 }
288 
drawImage(Image * image,const IntRect & r,CompositeOperator op,bool useLowQualityScale)289 void GraphicsContext::drawImage(Image* image, const IntRect& r, CompositeOperator op, bool useLowQualityScale)
290 {
291     drawImage(image, r, IntRect(0, 0, -1, -1), op, useLowQualityScale);
292 }
293 
drawImage(Image * image,const IntPoint & dest,const IntRect & srcRect,CompositeOperator op)294 void GraphicsContext::drawImage(Image* image, const IntPoint& dest, const IntRect& srcRect, CompositeOperator op)
295 {
296     drawImage(image, IntRect(dest, srcRect.size()), srcRect, op);
297 }
298 
drawImage(Image * image,const IntRect & dest,const IntRect & srcRect,CompositeOperator op,bool useLowQualityScale)299 void GraphicsContext::drawImage(Image* image, const IntRect& dest, const IntRect& srcRect, CompositeOperator op, bool useLowQualityScale)
300 {
301     drawImage(image, FloatRect(dest), srcRect, op, useLowQualityScale);
302 }
303 
drawText(const Font & font,const TextRun & run,const IntPoint & point,int from,int to)304 void GraphicsContext::drawText(const Font& font, const TextRun& run, const IntPoint& point, int from, int to)
305 {
306     if (paintingDisabled())
307         return;
308 
309     font.drawText(this, run, point, from, to);
310 }
311 
drawBidiText(const Font & font,const TextRun & run,const FloatPoint & point)312 void GraphicsContext::drawBidiText(const Font& font, const TextRun& run, const FloatPoint& point)
313 {
314     if (paintingDisabled())
315         return;
316 
317     BidiResolver<TextRunIterator, BidiCharacterRun> bidiResolver;
318     WTF::Unicode::Direction paragraphDirection = run.ltr() ? WTF::Unicode::LeftToRight : WTF::Unicode::RightToLeft;
319 
320     bidiResolver.setStatus(BidiStatus(paragraphDirection, paragraphDirection, paragraphDirection, new BidiContext(run.ltr() ? 0 : 1, paragraphDirection, run.directionalOverride())));
321 
322     bidiResolver.setPosition(TextRunIterator(&run, 0));
323     bidiResolver.createBidiRunsForLine(TextRunIterator(&run, run.length()));
324 
325     if (!bidiResolver.runCount())
326         return;
327 
328     FloatPoint currPoint = point;
329     BidiCharacterRun* bidiRun = bidiResolver.firstRun();
330     while (bidiRun) {
331 
332         TextRun subrun = run;
333         subrun.setText(run.data(bidiRun->start()), bidiRun->stop() - bidiRun->start());
334         subrun.setRTL(bidiRun->level() % 2);
335         subrun.setDirectionalOverride(bidiRun->dirOverride(false));
336 
337         font.drawText(this, subrun, currPoint);
338 
339         bidiRun = bidiRun->next();
340         // FIXME: Have Font::drawText return the width of what it drew so that we don't have to re-measure here.
341         if (bidiRun)
342             currPoint.move(font.floatWidth(subrun), 0.f);
343     }
344 
345     bidiResolver.deleteRuns();
346 }
347 
drawHighlightForText(const Font & font,const TextRun & run,const IntPoint & point,int h,const Color & backgroundColor,int from,int to)348 void GraphicsContext::drawHighlightForText(const Font& font, const TextRun& run, const IntPoint& point, int h, const Color& backgroundColor, int from, int to)
349 {
350     if (paintingDisabled())
351         return;
352 
353     fillRect(font.selectionRectForText(run, point, h, from, to), backgroundColor);
354 }
355 
initFocusRing(int width,int offset)356 void GraphicsContext::initFocusRing(int width, int offset)
357 {
358     if (paintingDisabled())
359         return;
360     clearFocusRing();
361 
362     m_common->m_focusRingWidth = width;
363     m_common->m_focusRingOffset = offset;
364 }
365 
clearFocusRing()366 void GraphicsContext::clearFocusRing()
367 {
368     m_common->m_focusRingRects.clear();
369 }
370 
focusRingBoundingRect()371 IntRect GraphicsContext::focusRingBoundingRect()
372 {
373     IntRect result = IntRect(0, 0, 0, 0);
374 
375     const Vector<IntRect>& rects = focusRingRects();
376     unsigned rectCount = rects.size();
377     for (unsigned i = 0; i < rectCount; i++)
378         result.unite(rects[i]);
379 
380     return result;
381 }
382 
addFocusRingRect(const IntRect & rect)383 void GraphicsContext::addFocusRingRect(const IntRect& rect)
384 {
385     if (paintingDisabled() || rect.isEmpty())
386         return;
387     m_common->m_focusRingRects.append(rect);
388 }
389 
focusRingWidth() const390 int GraphicsContext::focusRingWidth() const
391 {
392     return m_common->m_focusRingWidth;
393 }
394 
focusRingOffset() const395 int GraphicsContext::focusRingOffset() const
396 {
397     return m_common->m_focusRingOffset;
398 }
399 
focusRingRects() const400 const Vector<IntRect>& GraphicsContext::focusRingRects() const
401 {
402     return m_common->m_focusRingRects;
403 }
404 
drawImage(Image * image,const FloatRect & dest,const FloatRect & src,CompositeOperator op,bool useLowQualityScale)405 void GraphicsContext::drawImage(Image* image, const FloatRect& dest, const FloatRect& src, CompositeOperator op, bool useLowQualityScale)
406 {
407     if (paintingDisabled() || !image)
408         return;
409 
410     float tsw = src.width();
411     float tsh = src.height();
412     float tw = dest.width();
413     float th = dest.height();
414 
415     if (tsw == -1)
416         tsw = image->width();
417     if (tsh == -1)
418         tsh = image->height();
419 
420     if (tw == -1)
421         tw = image->width();
422     if (th == -1)
423         th = image->height();
424 
425     if (useLowQualityScale) {
426         save();
427         setImageInterpolationQuality(InterpolationNone);
428     }
429     image->draw(this, FloatRect(dest.location(), FloatSize(tw, th)), FloatRect(src.location(), FloatSize(tsw, tsh)), op);
430     if (useLowQualityScale)
431         restore();
432 }
433 
drawTiledImage(Image * image,const IntRect & rect,const IntPoint & srcPoint,const IntSize & tileSize,CompositeOperator op)434 void GraphicsContext::drawTiledImage(Image* image, const IntRect& rect, const IntPoint& srcPoint, const IntSize& tileSize, CompositeOperator op)
435 {
436     if (paintingDisabled() || !image)
437         return;
438 
439     image->drawTiled(this, rect, srcPoint, tileSize, op);
440 }
441 
drawTiledImage(Image * image,const IntRect & dest,const IntRect & srcRect,Image::TileRule hRule,Image::TileRule vRule,CompositeOperator op)442 void GraphicsContext::drawTiledImage(Image* image, const IntRect& dest, const IntRect& srcRect, Image::TileRule hRule, Image::TileRule vRule, CompositeOperator op)
443 {
444     if (paintingDisabled() || !image)
445         return;
446 
447     if (hRule == Image::StretchTile && vRule == Image::StretchTile)
448         // Just do a scale.
449         return drawImage(image, dest, srcRect, op);
450 
451     image->drawTiled(this, dest, srcRect, hRule, vRule, op);
452 }
453 
addRoundedRectClip(const IntRect & rect,const IntSize & topLeft,const IntSize & topRight,const IntSize & bottomLeft,const IntSize & bottomRight)454 void GraphicsContext::addRoundedRectClip(const IntRect& rect, const IntSize& topLeft, const IntSize& topRight,
455     const IntSize& bottomLeft, const IntSize& bottomRight)
456 {
457     if (paintingDisabled())
458         return;
459 
460     clip(Path::createRoundedRectangle(rect, topLeft, topRight, bottomLeft, bottomRight));
461 }
462 
clipOutRoundedRect(const IntRect & rect,const IntSize & topLeft,const IntSize & topRight,const IntSize & bottomLeft,const IntSize & bottomRight)463 void GraphicsContext::clipOutRoundedRect(const IntRect& rect, const IntSize& topLeft, const IntSize& topRight,
464                                          const IntSize& bottomLeft, const IntSize& bottomRight)
465 {
466     if (paintingDisabled())
467         return;
468 
469     clipOut(Path::createRoundedRectangle(rect, topLeft, topRight, bottomLeft, bottomRight));
470 }
471 
textDrawingMode()472 int GraphicsContext::textDrawingMode()
473 {
474     return m_common->state.textDrawingMode;
475 }
476 
setTextDrawingMode(int mode)477 void GraphicsContext::setTextDrawingMode(int mode)
478 {
479     m_common->state.textDrawingMode = mode;
480     if (paintingDisabled())
481         return;
482     setPlatformTextDrawingMode(mode);
483 }
484 
fillRect(const FloatRect & rect,Generator & generator)485 void GraphicsContext::fillRect(const FloatRect& rect, Generator& generator)
486 {
487     if (paintingDisabled())
488         return;
489     generator.fill(this, rect);
490 }
491 
492 #if !PLATFORM(CG) && !PLATFORM(SKIA)
493 // Implement this if you want to go ahead and push the drawing mode into your native context
494 // immediately.
setPlatformTextDrawingMode(int mode)495 void GraphicsContext::setPlatformTextDrawingMode(int mode)
496 {
497 }
498 #endif
499 
500 #if !PLATFORM(QT) && !PLATFORM(CAIRO) && !PLATFORM(SKIA)
setPlatformStrokeStyle(const StrokeStyle &)501 void GraphicsContext::setPlatformStrokeStyle(const StrokeStyle&)
502 {
503 }
504 #endif
505 
506 }
507