Changeset 85279 in webkit
- Timestamp:
- Apr 28, 2011 5:57:22 PM (13 years ago)
- Location:
- trunk
- Files:
-
- 5 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/LayoutTests/ChangeLog
r85276 r85279 1 2011-04-28 Martin Robinson <mrobinson@igalia.com> 2 3 Reviewed by Dirk Schulze. 4 5 [Cairo] Text underline is not shadowed when text-shadow is enabled 6 https://bugs.webkit.org/show_bug.cgi?id=48074 7 8 Updated pixel results for this test. They were previously incorrect 9 because text underlines were not shadowed. 10 11 * platform/gtk/fast/text/stroking-decorations-expected.png: 12 1 13 2011-04-28 Dirk Pranke <dpranke@chromium.org> 2 14 -
trunk/Source/WebCore/ChangeLog
r85277 r85279 1 2011-04-28 Martin Robinson <mrobinson@igalia.com> 2 3 Reviewed by Dirk Schulze. 4 5 [Cairo] Text underline is not shadowed when text-shadow is enabled 6 https://bugs.webkit.org/show_bug.cgi?id=48074 7 8 Use ShadowContext to enable shadows for text underlines. Also remove quite a bit 9 of duplicate code in GraphicsContext used for stroking lines. This code looks like it was 10 originally copied from the CG GraphicsContext. 11 12 * platform/graphics/GraphicsContext.h: Make adjustLineToPixelBoundaries so that we 13 can call it from a static helper function. 14 * platform/graphics/cairo/GraphicsContextCairo.cpp: 15 (WebCore::calculateStrokePatternOffset): Abstracted this code into a helper. 16 (WebCore::drawLineOnCairoContext): Abstracted this code into a helper. We need to 17 call it multiple times when shadowing text underlines. 18 (WebCore::GraphicsContext::drawLine): Use drawLineOnCairoContext. 19 (WebCore::GraphicsContext::strokeArc): Use calculateStrokePatternOffset. 20 (WebCore::GraphicsContext::drawLineForText): Use drawLineOnCairoContext. 21 1 22 2011-04-28 Sam Weinig <sam@webkit.org> 2 23 -
trunk/Source/WebCore/platform/graphics/GraphicsContext.h
r84504 r85279 513 513 void markDirtyRect(const IntRect&); // Hints that a portion of the backing store is dirty. 514 514 515 static void adjustLineToPixelBoundaries(FloatPoint& p1, FloatPoint& p2, float strokeWidth, StrokeStyle); 516 515 517 private: 516 518 void platformInit(PlatformGraphicsContext*); … … 544 546 545 547 void setPlatformCompositeOperation(CompositeOperator); 546 547 static void adjustLineToPixelBoundaries(FloatPoint& p1, FloatPoint& p2, float strokeWidth, StrokeStyle);548 548 549 549 GraphicsContextPlatformPrivate* m_data; -
trunk/Source/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp
r84088 r85279 278 278 } 279 279 280 // This is only used to draw borders. 281 void GraphicsContext::drawLine(const IntPoint& point1, const IntPoint& point2) 282 { 283 if (paintingDisabled()) 284 return; 285 286 StrokeStyle style = strokeStyle(); 280 static double calculateStrokePatternOffset(int distance, int patternWidth) 281 { 282 // Example: 80 pixels with a width of 30 pixels. Remainder is 20. 283 // The maximum pixels of line we could paint will be 50 pixels. 284 int remainder = distance % patternWidth; 285 int numSegments = (distance - remainder) / patternWidth; 286 287 // Special case 1px dotted borders for speed. 288 if (patternWidth == 1) 289 return 1; 290 291 bool evenNumberOfSegments = !(numSegments % 2); 292 if (remainder) 293 evenNumberOfSegments = !evenNumberOfSegments; 294 295 if (evenNumberOfSegments) { 296 if (remainder) 297 return (patternWidth - remainder) + (remainder / 2); 298 return patternWidth / 2; 299 } 300 301 // Odd number of segments. 302 if (remainder) 303 return (patternWidth - remainder) / 2.f; 304 return 0; 305 } 306 307 static void drawLineOnCairoContext(GraphicsContext* graphicsContext, cairo_t* context, const FloatPoint& point1, const FloatPoint& point2) 308 { 309 StrokeStyle style = graphicsContext->strokeStyle(); 287 310 if (style == NoStroke) 288 311 return; 289 312 290 cairo_t* cr = platformContext()->cr(); 291 cairo_save(cr); 292 293 float width = strokeThickness(); 294 if (width < 1) 295 width = 1; 296 297 FloatPoint p1 = point1; 298 FloatPoint p2 = point2; 299 bool isVerticalLine = (p1.x() == p2.x()); 300 301 adjustLineToPixelBoundaries(p1, p2, width, style); 302 cairo_set_line_width(cr, width); 303 304 int patWidth = 0; 305 switch (style) { 306 case NoStroke: 307 case SolidStroke: 308 break; 309 case DottedStroke: 310 patWidth = static_cast<int>(width); 311 break; 312 case DashedStroke: 313 patWidth = 3*static_cast<int>(width); 314 break; 315 } 316 317 setSourceRGBAFromColor(cr, strokeColor()); 318 319 cairo_set_antialias(cr, CAIRO_ANTIALIAS_NONE); 320 321 if (patWidth) { 313 const Color& strokeColor = graphicsContext->strokeColor(); 314 int strokeThickness = floorf(graphicsContext->strokeThickness()); 315 if (graphicsContext->strokeThickness() < 1) 316 strokeThickness = 1; 317 318 int patternWidth = 0; 319 if (style == DottedStroke) 320 patternWidth = strokeThickness; 321 else if (style == DashedStroke) 322 patternWidth = 3 * strokeThickness; 323 324 bool isVerticalLine = point1.x() == point2.x(); 325 FloatPoint point1OnPixelBoundaries = point1; 326 FloatPoint point2OnPixelBoundaries = point2; 327 GraphicsContext::adjustLineToPixelBoundaries(point1OnPixelBoundaries, point2OnPixelBoundaries, strokeThickness, style); 328 329 cairo_set_antialias(context, CAIRO_ANTIALIAS_NONE); 330 if (patternWidth) { 322 331 // Do a rect fill of our endpoints. This ensures we always have the 323 332 // appearance of being a border. We then draw the actual dotted/dashed line. 333 FloatRect firstRect(point1OnPixelBoundaries, FloatSize(strokeThickness, strokeThickness)); 334 FloatRect secondRect(point2OnPixelBoundaries, FloatSize(strokeThickness, strokeThickness)); 324 335 if (isVerticalLine) { 325 fi llRectSourceOver(cr, FloatRect(p1.x() - width/2, p1.y() - width, width, width), strokeColor());326 fillRectSourceOver(cr, FloatRect(p2.x() - width/2, p2.y(), width, width), strokeColor());336 firstRect.move(-strokeThickness / 2, -strokeThickness); 337 secondRect.move(-strokeThickness / 2, 0); 327 338 } else { 328 fi llRectSourceOver(cr, FloatRect(p1.x() - width, p1.y() - width/2, width, width), strokeColor());329 fillRectSourceOver(cr, FloatRect(p2.x(), p2.y() - width/2, width, width), strokeColor());339 firstRect.move(-strokeThickness, -strokeThickness / 2); 340 secondRect.move(0, -strokeThickness / 2); 330 341 } 331 332 // Example: 80 pixels with a width of 30 pixels. 333 // Remainder is 20. The maximum pixels of line we could paint 334 // will be 50 pixels. 335 int distance = (isVerticalLine ? (point2.y() - point1.y()) : (point2.x() - point1.x())) - 2*static_cast<int>(width); 336 int remainder = distance%patWidth; 337 int coverage = distance-remainder; 338 int numSegments = coverage/patWidth; 339 340 float patternOffset = 0; 341 // Special case 1px dotted borders for speed. 342 if (patWidth == 1) 343 patternOffset = 1.0; 344 else { 345 bool evenNumberOfSegments = !(numSegments % 2); 346 if (remainder) 347 evenNumberOfSegments = !evenNumberOfSegments; 348 if (evenNumberOfSegments) { 349 if (remainder) { 350 patternOffset += patWidth - remainder; 351 patternOffset += remainder / 2; 352 } else 353 patternOffset = patWidth / 2; 354 } else if (!evenNumberOfSegments) { 355 if (remainder) 356 patternOffset = (patWidth - remainder) / 2; 357 } 358 } 359 360 double dash = patWidth; 361 cairo_set_dash(cr, &dash, 1, patternOffset); 362 } 363 364 cairo_move_to(cr, p1.x(), p1.y()); 365 cairo_line_to(cr, p2.x(), p2.y()); 366 367 cairo_stroke(cr); 368 cairo_restore(cr); 342 fillRectSourceOver(context, firstRect, strokeColor); 343 fillRectSourceOver(context, secondRect, strokeColor); 344 345 int distance = (isVerticalLine ? (point2.y() - point1.y()) : (point2.x() - point1.x())) - 2 * strokeThickness; 346 double patternOffset = calculateStrokePatternOffset(distance, patternWidth); 347 double patternWidthAsDouble = patternWidth; 348 cairo_set_dash(context, &patternWidthAsDouble, 1, patternOffset); 349 } 350 351 setSourceRGBAFromColor(context, strokeColor); 352 cairo_set_line_width(context, strokeThickness); 353 cairo_move_to(context, point1OnPixelBoundaries.x(), point1OnPixelBoundaries.y()); 354 cairo_line_to(context, point2OnPixelBoundaries.x(), point2OnPixelBoundaries.y()); 355 cairo_stroke(context); 356 } 357 358 // This is only used to draw borders, so we should not draw shadows. 359 void GraphicsContext::drawLine(const IntPoint& point1, const IntPoint& point2) 360 { 361 if (paintingDisabled()) 362 return; 363 364 cairo_t* cairoContext = platformContext()->cr(); 365 cairo_save(cairoContext); 366 drawLineOnCairoContext(this, cairoContext, point1, point2); 367 cairo_restore(cairoContext); 369 368 } 370 369 … … 425 424 cairo_scale(cr, 1., reverseScaleFactor); 426 425 427 float width = strokeThickness(); 428 int patWidth = 0; 429 426 int patternWidth = 0; 430 427 switch (strokeStyle()) { 431 428 case DottedStroke: 432 pat Width = static_cast<int>(width / 2);429 patternWidth = floorf(strokeThickness() / 2.f); 433 430 break; 434 431 case DashedStroke: 435 pat Width = 3 * static_cast<int>(width / 2);432 patternWidth = 3 * floorf(strokeThickness() / 2.f); 436 433 break; 437 434 default: … … 441 438 setSourceRGBAFromColor(cr, strokeColor()); 442 439 443 if (patWidth) { 444 // Example: 80 pixels with a width of 30 pixels. 445 // Remainder is 20. The maximum pixels of line we could paint 446 // will be 50 pixels. 447 int distance; 440 if (patternWidth) { 441 float distance = 0; 448 442 if (hRadius == vRadius) 449 distance = static_cast<int>((M_PI * hRadius) / 2.0);443 distance = (piFloat * hRadius) / 2.f; 450 444 else // We are elliptical and will have to estimate the distance 451 distance = static_cast<int>((M_PI * sqrtf((hRadius * hRadius + vRadius * vRadius) / 2.0)) / 2.0); 452 453 int remainder = distance % patWidth; 454 int coverage = distance - remainder; 455 int numSegments = coverage / patWidth; 456 457 float patternOffset = 0.0; 458 // Special case 1px dotted borders for speed. 459 if (patWidth == 1) 460 patternOffset = 1.0; 461 else { 462 bool evenNumberOfSegments = !(numSegments % 2); 463 if (remainder) 464 evenNumberOfSegments = !evenNumberOfSegments; 465 if (evenNumberOfSegments) { 466 if (remainder) { 467 patternOffset += patWidth - remainder; 468 patternOffset += remainder / 2.0; 469 } else 470 patternOffset = patWidth / 2.0; 471 } else { 472 if (remainder) 473 patternOffset = (patWidth - remainder) / 2.0; 474 } 475 } 476 477 double dash = patWidth; 478 cairo_set_dash(cr, &dash, 1, patternOffset); 445 distance = (piFloat * sqrtf((hRadius * hRadius + vRadius * vRadius) / 2.f)) / 2.f; 446 double patternOffset = calculateStrokePatternOffset(floorf(distance), patternWidth); 447 double patternWidthAsDouble = patternWidth; 448 cairo_set_dash(cr, &patternWidthAsDouble, 1, patternOffset); 479 449 } 480 450 … … 716 686 return; 717 687 718 FloatPoint endPoint = origin + FloatSize(width, 0); 719 720 // FIXME: Loss of precision here. Might consider rounding. 721 drawLine(IntPoint(origin.x(), origin.y()), IntPoint(endPoint.x(), endPoint.y())); 688 cairo_t* cairoContext = platformContext()->cr(); 689 cairo_save(cairoContext); 690 691 // This bumping of <1 stroke thicknesses matches the one in drawLineOnCairoContext. 692 FloatPoint endPoint(origin + IntSize(width, 0)); 693 FloatRect lineExtents(origin, FloatSize(width, strokeThickness())); 694 695 ContextShadow* shadow = contextShadow(); 696 ASSERT(shadow); 697 cairo_t* shadowContext = shadow->beginShadowLayer(this, lineExtents); 698 if (shadowContext) { 699 drawLineOnCairoContext(this, shadowContext, origin, endPoint); 700 shadow->endShadowLayer(this); 701 } 702 703 drawLineOnCairoContext(this, cairoContext, origin, endPoint); 704 cairo_restore(cairoContext); 722 705 } 723 706
Note: See TracChangeset
for help on using the changeset viewer.