Changeset 282443 in webkit
- Timestamp:
- Sep 15, 2021 12:26:18 AM (10 months ago)
- Location:
- trunk
- Files:
-
- 2 added
- 3 edited
-
LayoutTests/ChangeLog (modified) (1 diff)
-
LayoutTests/svg/gradients/gradient-flipped-start-end-points-expected.svg (added)
-
LayoutTests/svg/gradients/gradient-flipped-start-end-points.svg (added)
-
Source/WebCore/ChangeLog (modified) (1 diff)
-
Source/WebCore/platform/graphics/cg/GradientCG.cpp (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
trunk/LayoutTests/ChangeLog
r282442 r282443 1 2021-09-15 Said Abou-Hallawa <said@apple.com> 2 3 Linear gradient sometimes is drawn incorrectly and sometimes hangs 4 https://bugs.webkit.org/show_bug.cgi?id=230145 5 <rdar://82428383> 6 7 Reviewed by Simon Fraser. 8 9 * svg/gradients/gradient-flipped-start-end-points-expected.svg: Added. 10 * svg/gradients/gradient-flipped-start-end-points.svg: Added. 11 1 12 2021-09-15 Myles C. Maxfield <mmaxfield@apple.com> 2 13 -
trunk/Source/WebCore/ChangeLog
r282441 r282443 1 2021-09-15 Said Abou-Hallawa <said@apple.com> 2 3 Linear gradient sometimes is drawn incorrectly and sometimes hangs 4 https://bugs.webkit.org/show_bug.cgi?id=230145 5 <rdar://82428383> 6 7 Reviewed by Simon Fraser. 8 9 Gradient::paint() has a few flaws: 10 11 1) We have to use atan2() instead of acos() to get the angle of the vector 12 (p0, p1) in the correct quadrant. acos() returns an angle between [0, pi]. 13 14 2) The order in the case of 'repeat' and 'reflect' should be the following: 15 -- Move the points forward towards the bounding box. 16 -- Draw gradient and move the points forward till they are not 17 intersecting the bounding box. 18 -- Move the points backward towards the bounding box. 19 -- Draw gradient and move the points backward till they are not 20 intersecting the bounding box. 21 22 Tests: svg/gradients/gradient-flipped-start-end-points-expected.svg 23 svg/gradients/gradient-flipped-start-end-points.svg 24 25 * platform/graphics/cg/GradientCG.cpp: 26 (WebCore::Gradient::paint): 27 1 28 2021-09-14 Simon Fraser <simon.fraser@apple.com> 2 29 -
trunk/Source/WebCore/platform/graphics/cg/GradientCG.cpp
r281488 r282443 120 120 case GradientSpreadMethod::Reflect: { 121 121 CGContextStateSaver saveState(platformContext); 122 extendOptions = 0; 122 123 123 124 FloatPoint gradientVectorNorm(data.point1 - data.point0); 124 125 gradientVectorNorm.normalize(); 125 CGFloat angle = acos(gradientVectorNorm.dot({ 1, 0 }));126 CGFloat angle = gradientVectorNorm.isZero() ? 0 : atan2(gradientVectorNorm.y(), gradientVectorNorm.x()); 126 127 CGContextRotateCTM(platformContext, angle); 128 129 CGRect boundingBox = CGContextGetClipBoundingBox(platformContext); 130 if (CGRectIsInfinite(boundingBox) || CGRectIsEmpty(boundingBox)) 131 break; 127 132 128 133 CGAffineTransform transform = CGAffineTransformMakeRotation(-angle); 129 134 FloatPoint point0 = CGPointApplyAffineTransform(data.point0, transform); 130 135 FloatPoint point1 = CGPointApplyAffineTransform(data.point1, transform); 131 132 CGRect boundingBox = CGContextGetClipBoundingBox(platformContext); 133 CGFloat width = point1.x() - point0.x(); 136 CGFloat dx = point1.x() - point0.x(); 137 134 138 CGFloat pixelSize = CGFAbs(CGContextConvertSizeToUserSpace(platformContext, CGSizeMake(1, 1)).width); 135 136 if (width > 0 && !CGRectIsInfinite(boundingBox) && !CGRectIsEmpty(boundingBox)) { 137 extendOptions = 0; 138 if (width < pixelSize) 139 width = pixelSize; 140 141 CGFloat gradientStart = point0.x(); 142 CGFloat gradientEnd = point1.x(); 143 bool flip = m_spreadMethod == GradientSpreadMethod::Reflect; 144 145 // Find first gradient position to the left of the bounding box 146 int n = CGFloor((boundingBox.origin.x - gradientStart) / width); 147 gradientStart += n * width; 148 if (!(n % 2)) 149 flip = false; 150 151 gradientEnd -= CGFloor((gradientEnd - CGRectGetMaxX(boundingBox)) / width) * width; 152 153 for (CGFloat start = gradientStart; start <= gradientEnd; start += width) { 154 CGPoint left = CGPointMake(flip ? start + width : start, boundingBox.origin.y); 155 CGPoint right = CGPointMake(flip ? start : start + width, boundingBox.origin.y); 156 157 CGContextDrawLinearGradient(platformContext, m_gradient.get(), left, right, extendOptions); 158 159 if (m_spreadMethod == GradientSpreadMethod::Reflect) 160 flip = !flip; 161 } 162 163 break; 164 } 165 166 FALLTHROUGH; 139 if (CGFAbs(dx) < pixelSize) 140 dx = dx < 0 ? -pixelSize : pixelSize; 141 142 auto drawLinearGradient = [&](CGFloat start, CGFloat end, bool flip) { 143 CGPoint left = CGPointMake(flip ? end : start, 0); 144 CGPoint right = CGPointMake(flip ? start : end, 0); 145 146 CGContextDrawLinearGradient(platformContext, m_gradient.get(), left, right, extendOptions); 147 }; 148 149 auto isLeftOf = [](CGFloat start, CGFloat end, CGRect boundingBox) -> bool { 150 return std::max(start, end) <= CGRectGetMinX(boundingBox); 151 }; 152 153 auto isRightOf = [](CGFloat start, CGFloat end, CGRect boundingBox) -> bool { 154 return std::min(start, end) >= CGRectGetMaxX(boundingBox); 155 }; 156 157 auto isIntersecting = [](CGFloat start, CGFloat end, CGRect boundingBox) -> bool { 158 return std::min(start, end) < CGRectGetMaxX(boundingBox) && CGRectGetMinX(boundingBox) < std::max(start, end); 159 }; 160 161 bool flip = false; 162 CGFloat start = point0.x(); 163 164 // Should the points be moved forward towards boundingBox? 165 if ((dx > 0 && isLeftOf(start, start + dx, boundingBox)) || (dx < 0 && isRightOf(start, start + dx, boundingBox))) { 166 // Move the 'start' point towards boundingBox. 167 for (; !isIntersecting(start, start + dx, boundingBox); start += dx) 168 flip = !flip && m_spreadMethod == GradientSpreadMethod::Reflect; 169 } 170 171 // Draw gradient forward till the points are outside boundingBox. 172 for (; isIntersecting(start, start + dx, boundingBox); start += dx) { 173 drawLinearGradient(start, start + dx, flip); 174 flip = !flip && m_spreadMethod == GradientSpreadMethod::Reflect; 175 } 176 177 flip = m_spreadMethod == GradientSpreadMethod::Reflect; 178 CGFloat end = point0.x(); 179 180 // Should the points be moved backward towards boundingBox? 181 if ((dx < 0 && isLeftOf(end, end - dx, boundingBox)) || (dx > 0 && isRightOf(end, end - dx, boundingBox))) { 182 // Move the 'end' point towards boundingBox. 183 for (; !isIntersecting(end, end - dx, boundingBox); end -= dx) 184 flip = !flip && m_spreadMethod == GradientSpreadMethod::Reflect; 185 } 186 187 // Draw gradient backward till the points are outside boundingBox. 188 for (; isIntersecting(end, end - dx, boundingBox); end -= dx) { 189 drawLinearGradient(end - dx, end, flip); 190 flip = !flip && m_spreadMethod == GradientSpreadMethod::Reflect; 191 } 192 193 break; 167 194 } 168 195 case GradientSpreadMethod::Pad:
Note: See TracChangeset
for help on using the changeset viewer.