1/* 2 * Copyright (C) 2007 Ryan Leavengood <leavengood@gmail.com> 3 * 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY 16 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 18 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR 19 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 20 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 22 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 23 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28#include "config.h" 29#include "GraphicsContext.h" 30 31#include "AffineTransform.h" 32#include "CString.h" 33#include "Color.h" 34#include "Font.h" 35#include "FontData.h" 36#include "NotImplemented.h" 37#include "Path.h" 38#include "Pen.h" 39#include <GraphicsDefs.h> 40#include <Region.h> 41#include <View.h> 42#include <Window.h> 43#include <stdio.h> 44 45 46namespace WebCore { 47 48class GraphicsContextPlatformPrivate { 49public: 50 GraphicsContextPlatformPrivate(BView* view); 51 ~GraphicsContextPlatformPrivate(); 52 53 BView* m_view; 54}; 55 56GraphicsContextPlatformPrivate::GraphicsContextPlatformPrivate(BView* view) 57 : m_view(view) 58{ 59} 60 61GraphicsContextPlatformPrivate::~GraphicsContextPlatformPrivate() 62{ 63} 64 65GraphicsContext::GraphicsContext(PlatformGraphicsContext* context) 66 : m_common(createGraphicsContextPrivate()) 67 , m_data(new GraphicsContextPlatformPrivate(context)) 68{ 69 setPaintingDisabled(!context); 70} 71 72GraphicsContext::~GraphicsContext() 73{ 74 destroyGraphicsContextPrivate(m_common); 75 delete m_data; 76} 77 78PlatformGraphicsContext* GraphicsContext::platformContext() const 79{ 80 return m_data->m_view; 81} 82 83void GraphicsContext::savePlatformState() 84{ 85 m_data->m_view->PushState(); 86} 87 88void GraphicsContext::restorePlatformState() 89{ 90 m_data->m_view->PopState(); 91} 92 93// Draws a filled rectangle with a stroked border. 94void GraphicsContext::drawRect(const IntRect& rect) 95{ 96 if (paintingDisabled()) 97 return; 98 99 m_data->m_view->FillRect(rect); 100 if (strokeStyle() != NoStroke) 101 m_data->m_view->StrokeRect(rect, getHaikuStrokeStyle()); 102} 103 104// This is only used to draw borders. 105void GraphicsContext::drawLine(const IntPoint& point1, const IntPoint& point2) 106{ 107 if (paintingDisabled()) 108 return; 109 110 if (strokeStyle() == NoStroke) 111 return; 112 113 m_data->m_view->StrokeLine(point1, point2, getHaikuStrokeStyle()); 114} 115 116// This method is only used to draw the little circles used in lists. 117void GraphicsContext::drawEllipse(const IntRect& rect) 118{ 119 if (paintingDisabled()) 120 return; 121 122 m_data->m_view->FillEllipse(rect); 123 if (strokeStyle() != NoStroke) 124 m_data->m_view->StrokeEllipse(rect, getHaikuStrokeStyle()); 125} 126 127void GraphicsContext::strokeArc(const IntRect& rect, int startAngle, int angleSpan) 128{ 129 if (paintingDisabled()) 130 return; 131 132 m_data->m_view->StrokeArc(rect, startAngle, angleSpan, getHaikuStrokeStyle()); 133} 134 135void GraphicsContext::strokePath() 136{ 137 notImplemented(); 138} 139 140void GraphicsContext::drawConvexPolygon(size_t pointsLength, const FloatPoint* points, bool shouldAntialias) 141{ 142 if (paintingDisabled()) 143 return; 144 145 BPoint bPoints[pointsLength]; 146 for (size_t i = 0; i < pointsLength; i++) 147 bPoints[i] = points[i]; 148 149 m_data->m_view->FillPolygon(bPoints, pointsLength); 150 if (strokeStyle() != NoStroke) 151 // Stroke with low color 152 m_data->m_view->StrokePolygon(bPoints, pointsLength, true, getHaikuStrokeStyle()); 153} 154 155void GraphicsContext::fillRect(const FloatRect& rect, const Color& color, ColorSpace colorSpace) 156{ 157 if (paintingDisabled()) 158 return; 159 160 rgb_color oldColor = m_data->m_view->HighColor(); 161 m_data->m_view->SetHighColor(color); 162 m_data->m_view->FillRect(rect); 163 m_data->m_view->SetHighColor(oldColor); 164} 165 166void GraphicsContext::fillRect(const FloatRect& rect) 167{ 168 if (paintingDisabled()) 169 return; 170} 171 172void GraphicsContext::fillRoundedRect(const IntRect& rect, const IntSize& topLeft, const IntSize& topRight, const IntSize& bottomLeft, const IntSize& bottomRight, const Color& color, ColorSpace colorSpace) 173{ 174 if (paintingDisabled() || !color.alpha()) 175 return; 176 177 notImplemented(); 178 // FIXME: A simple implementation could just use FillRoundRect if all 179 // the sizes are the same, or even if they are not. Otherwise several 180 // FillRect and FillArc calls are needed. 181} 182 183void GraphicsContext::fillPath() 184{ 185 notImplemented(); 186} 187 188void GraphicsContext::beginPath() 189{ 190 notImplemented(); 191} 192 193void GraphicsContext::addPath(const Path& path) 194{ 195 notImplemented(); 196} 197 198void GraphicsContext::clip(const FloatRect& rect) 199{ 200 if (paintingDisabled()) 201 return; 202 203 BRegion region(rect); 204 m_data->m_view->ConstrainClippingRegion(®ion); 205} 206 207void GraphicsContext::drawFocusRing(const Vector<Path>& paths, int width, int offset, const Color& color) 208{ 209 // FIXME: implement 210} 211 212void GraphicsContext::drawFocusRing(const Vector<IntRect>& rects, int /* width */, int /* offset */, const Color& color) 213{ 214 if (paintingDisabled()) 215 return; 216 217 unsigned rectCount = rects.size(); 218 219 // FIXME: maybe we should implement this with BShape? 220 221 if (rects.size() > 1) { 222 BRegion region; 223 for (int i = 0; i < rectCount; ++i) 224 region.Include(BRect(rects[i])); 225 226 m_data->m_view->SetHighColor(color); 227 m_data->m_view->StrokeRect(region.Frame(), B_MIXED_COLORS); 228 } 229} 230 231void GraphicsContext::drawLineForText(const IntPoint& origin, int width, bool printing) 232{ 233 if (paintingDisabled()) 234 return; 235 236 IntPoint endPoint = origin + IntSize(width, 0); 237 drawLine(origin, endPoint); 238} 239 240void GraphicsContext::drawLineForMisspellingOrBadGrammar(const IntPoint&, int width, bool grammar) 241{ 242 if (paintingDisabled()) 243 return; 244 245 notImplemented(); 246} 247 248FloatRect GraphicsContext::roundToDevicePixels(const FloatRect& rect) 249{ 250 notImplemented(); 251 return rect; 252} 253 254void GraphicsContext::beginTransparencyLayer(float opacity) 255{ 256 if (paintingDisabled()) 257 return; 258 259 notImplemented(); 260} 261 262void GraphicsContext::endTransparencyLayer() 263{ 264 if (paintingDisabled()) 265 return; 266 267 notImplemented(); 268} 269 270void GraphicsContext::clearRect(const FloatRect& rect) 271{ 272 if (paintingDisabled()) 273 return; 274 275 notImplemented(); 276} 277 278void GraphicsContext::strokeRect(const FloatRect& rect, float width) 279{ 280 if (paintingDisabled()) 281 return; 282 283 float oldSize = m_data->m_view->PenSize(); 284 m_data->m_view->SetPenSize(width); 285 m_data->m_view->StrokeRect(rect, getHaikuStrokeStyle()); 286 m_data->m_view->SetPenSize(oldSize); 287} 288 289void GraphicsContext::setLineCap(LineCap lineCap) 290{ 291 if (paintingDisabled()) 292 return; 293 294 cap_mode mode = B_BUTT_CAP; 295 switch (lineCap) { 296 case RoundCap: 297 mode = B_ROUND_CAP; 298 break; 299 case SquareCap: 300 mode = B_SQUARE_CAP; 301 break; 302 case ButtCap: 303 default: 304 break; 305 } 306 307 m_data->m_view->SetLineMode(mode, m_data->m_view->LineJoinMode(), m_data->m_view->LineMiterLimit()); 308} 309 310void GraphicsContext::setLineJoin(LineJoin lineJoin) 311{ 312 if (paintingDisabled()) 313 return; 314 315 join_mode mode = B_MITER_JOIN; 316 switch (lineJoin) { 317 case RoundJoin: 318 mode = B_ROUND_JOIN; 319 break; 320 case BevelJoin: 321 mode = B_BEVEL_JOIN; 322 break; 323 case MiterJoin: 324 default: 325 break; 326 } 327 328 m_data->m_view->SetLineMode(m_data->m_view->LineCapMode(), mode, m_data->m_view->LineMiterLimit()); 329} 330 331void GraphicsContext::setMiterLimit(float limit) 332{ 333 if (paintingDisabled()) 334 return; 335 336 m_data->m_view->SetLineMode(m_data->m_view->LineCapMode(), m_data->m_view->LineJoinMode(), limit); 337} 338 339void GraphicsContext::setAlpha(float opacity) 340{ 341 if (paintingDisabled()) 342 return; 343 344 notImplemented(); 345} 346 347void GraphicsContext::setCompositeOperation(CompositeOperator op) 348{ 349 if (paintingDisabled()) 350 return; 351 352 drawing_mode mode = B_OP_COPY; 353 switch (op) { 354 case CompositeClear: 355 case CompositeCopy: 356 // Use the default above 357 break; 358 case CompositeSourceOver: 359 mode = B_OP_OVER; 360 break; 361 default: 362 printf("GraphicsContext::setCompositeOperation: Unsupported composite operation %s\n", 363 compositeOperatorName(op).utf8().data()); 364 } 365 m_data->m_view->SetDrawingMode(mode); 366} 367 368void GraphicsContext::clip(const Path& path) 369{ 370 if (paintingDisabled()) 371 return; 372 373 m_data->m_view->ConstrainClippingRegion(path.platformPath()); 374} 375 376void GraphicsContext::canvasClip(const Path& path) 377{ 378 clip(path); 379} 380 381void GraphicsContext::clipOut(const Path& path) 382{ 383 if (paintingDisabled()) 384 return; 385 386 notImplemented(); 387} 388 389void GraphicsContext::clipToImageBuffer(const FloatRect&, const ImageBuffer*) 390{ 391 notImplemented(); 392} 393 394AffineTransform GraphicsContext::getCTM() const 395{ 396 notImplemented(); 397 return AffineTransform(); 398} 399 400void GraphicsContext::translate(float x, float y) 401{ 402 if (paintingDisabled()) 403 return; 404 405 notImplemented(); 406} 407 408IntPoint GraphicsContext::origin() 409{ 410 notImplemented(); 411 return IntPoint(0, 0); 412} 413 414void GraphicsContext::rotate(float radians) 415{ 416 if (paintingDisabled()) 417 return; 418 419 notImplemented(); 420} 421 422void GraphicsContext::scale(const FloatSize& size) 423{ 424 if (paintingDisabled()) 425 return; 426 427 notImplemented(); 428} 429 430void GraphicsContext::clipOut(const IntRect& rect) 431{ 432 if (paintingDisabled()) 433 return; 434 435 notImplemented(); 436} 437 438void GraphicsContext::clipOutEllipseInRect(const IntRect& rect) 439{ 440 if (paintingDisabled()) 441 return; 442 443 notImplemented(); 444} 445 446void GraphicsContext::addInnerRoundedRectClip(const IntRect& rect, int thickness) 447{ 448 if (paintingDisabled()) 449 return; 450 451 notImplemented(); 452} 453 454void GraphicsContext::concatCTM(const AffineTransform& transform) 455{ 456 if (paintingDisabled()) 457 return; 458 459 notImplemented(); 460} 461 462void GraphicsContext::setPlatformShouldAntialias(bool enable) 463{ 464 if (paintingDisabled()) 465 return; 466 467 notImplemented(); 468} 469 470void GraphicsContext::setImageInterpolationQuality(InterpolationQuality) 471{ 472} 473 474void GraphicsContext::setURLForRect(const KURL& link, const IntRect& destRect) 475{ 476 notImplemented(); 477} 478 479void GraphicsContext::setPlatformFont(const Font& font) 480{ 481 m_data->m_view->SetFont(font.primaryFont()->platformData().font()); 482} 483 484void GraphicsContext::setPlatformStrokeColor(const Color& color, ColorSpace colorSpace) 485{ 486 if (paintingDisabled()) 487 return; 488 489 m_data->m_view->SetHighColor(color); 490} 491 492pattern GraphicsContext::getHaikuStrokeStyle() 493{ 494 switch (strokeStyle()) { 495 case SolidStroke: 496 return B_SOLID_HIGH; 497 break; 498 case DottedStroke: 499 return B_MIXED_COLORS; 500 break; 501 case DashedStroke: 502 // FIXME: use a better dashed stroke! 503 notImplemented(); 504 return B_MIXED_COLORS; 505 break; 506 default: 507 return B_SOLID_LOW; 508 break; 509 } 510} 511 512void GraphicsContext::setPlatformStrokeStyle(const StrokeStyle& strokeStyle) 513{ 514 // FIXME: see getHaikuStrokeStyle. 515 notImplemented(); 516} 517 518void GraphicsContext::setPlatformStrokeThickness(float thickness) 519{ 520 if (paintingDisabled()) 521 return; 522 523 m_data->m_view->SetPenSize(thickness); 524} 525 526void GraphicsContext::setPlatformFillColor(const Color& color, ColorSpace colorSpace) 527{ 528 if (paintingDisabled()) 529 return; 530 531 m_data->m_view->SetHighColor(color); 532} 533 534void GraphicsContext::clearPlatformShadow() 535{ 536 notImplemented(); 537} 538 539void GraphicsContext::setPlatformShadow(IntSize const&, int, Color const&, ColorSpace) 540{ 541 notImplemented(); 542} 543 544} // namespace WebCore 545 546