Changeset 177658 in webkit
- Timestamp:
- Dec 22, 2014 3:18:59 PM (9 years ago)
- Location:
- trunk
- Files:
-
- 6 added
- 4 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/LayoutTests/ChangeLog
r177653 r177658 1 2014-12-22 Zalan Bujtas <zalan@apple.com> 2 3 Incorrect dashed and dotted border painting. 4 https://bugs.webkit.org/show_bug.cgi?id=139872 5 rdar://problem/18024205 6 7 Reviewed by Simon Fraser. 8 9 This patch makes dashed/dotted border painting symmetric and consistent. 10 It also works with subpixel positioning. 11 12 * fast/borders/border-painting-correctness-dashed-expected.html: Added. 13 * fast/borders/border-painting-correctness-dashed.html: Added. 14 * fast/borders/border-painting-correctness-dotted-expected.html: Added. 15 * fast/borders/border-painting-correctness-dotted.html: Added. 16 * fast/borders/resources/border-painting-correctness-dashed-expected.png: Added. 17 * fast/borders/resources/border-painting-correctness-dotted-expected.png: Added. 18 1 19 2014-12-22 Alexey Proskuryakov <ap@apple.com> 2 20 -
trunk/Source/WebCore/ChangeLog
r177656 r177658 1 2014-12-22 Zalan Bujtas <zalan@apple.com> 2 3 Incorrect dashed and dotted border painting. 4 https://bugs.webkit.org/show_bug.cgi?id=139872 5 rdar://problem/18024205 6 7 Reviewed by Simon Fraser. 8 9 This patch makes dashed/dotted border painting symmetric and consistent. 10 It also works with subpixel positioning. 11 12 Tests: fast/borders/border-painting-correctness-dashed.html 13 fast/borders/border-painting-correctness-dotted.html 14 15 * platform/graphics/cg/GraphicsContextCG.cpp: 16 (WebCore::GraphicsContext::drawLine): 17 * rendering/RenderObject.cpp: 18 (WebCore::RenderObject::drawLineForBoxSide): 19 1 20 2014-12-22 Timothy Horton <timothy_horton@apple.com> 2 21 -
trunk/Source/WebCore/platform/graphics/cg/GraphicsContextCG.cpp
r176140 r177658 286 286 return; 287 287 288 float width = strokeThickness(); 288 CGContextRef context = platformContext(); 289 float thickness = strokeThickness(); 290 ASSERT(thickness); 291 bool isVerticalLine = (point1.x() + thickness == point2.x()); 292 StrokeStyle strokeStyle = this->strokeStyle(); 293 float strokeWidth = isVerticalLine ? point2.y() - point1.y() : point2.x() - point1.x(); 294 ASSERT(strokeWidth); 295 float cornerWidth = 0; 296 297 if (strokeStyle == DottedStroke || strokeStyle == DashedStroke) { 298 // Figure out end points to ensure we always paint corners. 299 cornerWidth = strokeStyle == DottedStroke ? thickness : std::min(2 * thickness, std::max(thickness, strokeWidth / 3)); 300 CGContextSaveGState(context); 301 setCGFillColor(context, strokeColor(), strokeColorSpace()); 302 if (isVerticalLine) { 303 CGContextFillRect(context, FloatRect(point1.x(), point1.y(), thickness, cornerWidth)); 304 CGContextFillRect(context, FloatRect(point1.x(), point2.y() - cornerWidth, thickness, cornerWidth)); 305 } else { 306 CGContextFillRect(context, FloatRect(point1.x(), point1.y(), cornerWidth, thickness)); 307 CGContextFillRect(context, FloatRect(point2.x() - cornerWidth, point1.y(), cornerWidth, thickness)); 308 } 309 CGContextRestoreGState(context); 310 strokeWidth -= 2 * cornerWidth; 311 float patternWidth = strokeStyle == DottedStroke ? thickness : std::min(3 * thickness, std::max(thickness, strokeWidth / 3)); 312 // Check if corner drawing sufficiently covers the line. 313 if (strokeWidth <= patternWidth + 1) 314 return; 315 316 // Pattern starts with full fill and ends with the empty fill. 317 // 1. Let's start with the empty phase after the corner. 318 // 2. Check if we've got odd or even number of patterns and whether they fully cover the line. 319 // 3. In case of even number of patterns and/or remainder, move the pattern start position 320 // so that the pattern is balanced between the corners. 321 float patternOffset = patternWidth; 322 int numberOfSegments = floorf(strokeWidth / patternWidth); 323 bool oddNumberOfSegments = numberOfSegments % 2; 324 float remainder = strokeWidth - (numberOfSegments * patternWidth); 325 if (oddNumberOfSegments && remainder) 326 patternOffset -= remainder / 2; 327 else if (!oddNumberOfSegments) { 328 if (remainder) 329 patternOffset += patternOffset - (patternWidth + remainder) / 2; 330 else 331 patternOffset += patternWidth / 2; 332 } 333 const CGFloat dashedLine[2] = { static_cast<CGFloat>(patternWidth), static_cast<CGFloat>(patternWidth) }; 334 CGContextSetLineDash(context, patternOffset, dashedLine, 2); 335 } 289 336 290 337 FloatPoint p1 = point1; 291 338 FloatPoint p2 = point2; 292 bool isVerticalLine = (p1.x() == p2.x()); 293 294 // For odd widths, we add in 0.5 to the appropriate x/y so that the float arithmetic 295 // works out. For example, with a border width of 3, KHTML will pass us (y1+y2)/2, e.g., 296 // (50+53)/2 = 103/2 = 51 when we want 51.5. It is always true that an even width gave 297 // us a perfect position, but an odd width gave us a position that is off by exactly 0.5. 298 if (strokeStyle() == DottedStroke || strokeStyle() == DashedStroke) { 299 if (isVerticalLine) { 300 p1.move(0, width); 301 p2.move(0, -width); 302 } else { 303 p1.move(width, 0); 304 p2.move(-width, 0); 305 } 306 } 307 308 if (((int)width) % 2) { 309 if (isVerticalLine) { 310 // We're a vertical line. Adjust our x. 311 p1.move(0.5f, 0.0f); 312 p2.move(0.5f, 0.0f); 313 } else { 314 // We're a horizontal line. Adjust our y. 315 p1.move(0.0f, 0.5f); 316 p2.move(0.0f, 0.5f); 317 } 318 } 319 320 int patWidth = 0; 321 switch (strokeStyle()) { 322 case NoStroke: 323 case SolidStroke: 324 case DoubleStroke: 325 case WavyStroke: // FIXME: https://bugs.webkit.org/show_bug.cgi?id=94112 - Needs platform support. 326 break; 327 case DottedStroke: 328 patWidth = (int)width; 329 break; 330 case DashedStroke: 331 patWidth = 3 * (int)width; 332 break; 333 } 334 335 CGContextRef context = platformContext(); 339 // Center line and cut off corners for pattern patining. 340 if (isVerticalLine) { 341 float centerOffset = (p2.x() - p1.x()) / 2; 342 p1.move(centerOffset, cornerWidth); 343 p2.move(-centerOffset, -cornerWidth); 344 } else { 345 float centerOffset = (p2.y() - p1.y()) / 2; 346 p1.move(cornerWidth, centerOffset); 347 p2.move(-cornerWidth, -centerOffset); 348 } 336 349 337 350 if (shouldAntialias()) { 338 bool willAntialias = false;339 351 #if PLATFORM(IOS) 340 352 // Force antialiasing on for line patterns as they don't look good with it turned off (<rdar://problem/5459772>). 341 willAntialias = patWidth; 353 CGContextSetShouldAntialias(context, strokeStyle == DottedStroke || strokeStyle == DashedStroke); 354 #else 355 CGContextSetShouldAntialias(context, false); 342 356 #endif 343 CGContextSetShouldAntialias(context, willAntialias); 344 } 345 346 if (patWidth) { 347 CGContextSaveGState(context); 348 349 // Do a rect fill of our endpoints. This ensures we always have the 350 // appearance of being a border. We then draw the actual dotted/dashed line. 351 setCGFillColor(context, strokeColor(), strokeColorSpace()); // The save/restore make it safe to mutate the fill color here without setting it back to the old color. 352 if (isVerticalLine) { 353 CGContextFillRect(context, FloatRect(p1.x() - width / 2, p1.y() - width, width, width)); 354 CGContextFillRect(context, FloatRect(p2.x() - width / 2, p2.y(), width, width)); 355 } else { 356 CGContextFillRect(context, FloatRect(p1.x() - width, p1.y() - width / 2, width, width)); 357 CGContextFillRect(context, FloatRect(p2.x(), p2.y() - width / 2, width, width)); 358 } 359 360 // Example: 80 pixels with a width of 30 pixels. 361 // Remainder is 20. The maximum pixels of line we could paint 362 // will be 50 pixels. 363 int distance = (isVerticalLine ? (int)(point2.y() - point1.y()) : (point2.x() - point1.x())) - 2*(int)width; 364 int remainder = distance % patWidth; 365 int coverage = distance - remainder; 366 int numSegments = coverage / patWidth; 367 368 float patternOffset = 0.0f; 369 // Special case 1px dotted borders for speed. 370 if (patWidth == 1) 371 patternOffset = 1.0f; 372 else { 373 bool evenNumberOfSegments = !(numSegments % 2); 374 if (remainder) 375 evenNumberOfSegments = !evenNumberOfSegments; 376 if (evenNumberOfSegments) { 377 if (remainder) { 378 patternOffset += patWidth - remainder; 379 patternOffset += remainder / 2; 380 } else 381 patternOffset = patWidth / 2; 382 } else { 383 if (remainder) 384 patternOffset = (patWidth - remainder)/2; 385 } 386 } 387 388 const CGFloat dottedLine[2] = { static_cast<CGFloat>(patWidth), static_cast<CGFloat>(patWidth) }; 389 CGContextSetLineDash(context, patternOffset, dottedLine, 2); 390 } 391 357 } 392 358 CGContextBeginPath(context); 393 359 CGContextMoveToPoint(context, p1.x(), p1.y()); 394 360 CGContextAddLineToPoint(context, p2.x(), p2.y()); 395 396 361 CGContextStrokePath(context); 397 398 if (patWidth)399 CGContextRestoreGState(context);400 401 362 if (shouldAntialias()) 402 363 CGContextSetShouldAntialias(context, true); -
trunk/Source/WebCore/rendering/RenderObject.cpp
r177200 r177658 734 734 case DOTTED: 735 735 case DASHED: { 736 if (thickness > 0) { 737 bool wasAntialiased = graphicsContext->shouldAntialias(); 738 StrokeStyle oldStrokeStyle = graphicsContext->strokeStyle(); 739 graphicsContext->setShouldAntialias(antialias); 740 graphicsContext->setStrokeColor(color, style.colorSpace()); 741 graphicsContext->setStrokeThickness(thickness); 742 graphicsContext->setStrokeStyle(borderStyle == DASHED ? DashedStroke : DottedStroke); 743 744 // FIXME: There's some odd adjustment in GraphicsContext::drawLine() that disables device pixel precision line drawing. 745 int adjustedX = floorToInt((x1 + x2) / 2); 746 int adjustedY = floorToInt((y1 + y2) / 2); 747 748 switch (side) { 749 case BSBottom: 750 case BSTop: 751 graphicsContext->drawLine(FloatPoint(x1, adjustedY), FloatPoint(x2, adjustedY)); 752 break; 753 case BSRight: 754 case BSLeft: 755 graphicsContext->drawLine(FloatPoint(adjustedX, y1), FloatPoint(adjustedX, y2)); 756 break; 757 } 758 graphicsContext->setShouldAntialias(wasAntialiased); 759 graphicsContext->setStrokeStyle(oldStrokeStyle); 760 } 736 bool wasAntialiased = graphicsContext->shouldAntialias(); 737 StrokeStyle oldStrokeStyle = graphicsContext->strokeStyle(); 738 graphicsContext->setShouldAntialias(antialias); 739 graphicsContext->setStrokeColor(color, style.colorSpace()); 740 graphicsContext->setStrokeThickness(thickness); 741 graphicsContext->setStrokeStyle(borderStyle == DASHED ? DashedStroke : DottedStroke); 742 graphicsContext->drawLine(roundPointToDevicePixels(LayoutPoint(x1, y1), deviceScaleFactor), roundPointToDevicePixels(LayoutPoint(x2, y2), deviceScaleFactor)); 743 graphicsContext->setShouldAntialias(wasAntialiased); 744 graphicsContext->setStrokeStyle(oldStrokeStyle); 761 745 break; 762 746 }
Note: See TracChangeset
for help on using the changeset viewer.