Changeset 225036 in webkit for trunk/Source/WebCore/css/CSSGradientValue.cpp
- Timestamp:
- Nov 19, 2017, 3:06:03 PM (7 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/WebCore/css/CSSGradientValue.cpp
r224165 r225036 136 136 } 137 137 138 void CSSGradientValue::addStops(Gradient& gradient, const CSSToLengthConversionData& conversionData, float maxLengthForRepeat) 138 class LinearGradientAdapter { 139 public: 140 explicit LinearGradientAdapter(Gradient::LinearData& data) 141 : m_data(data) 142 { 143 } 144 145 FloatPoint startPoint() const { return m_data.point0; } 146 FloatPoint endPoint() const { return m_data.point1; } 147 float maxExtent(float, float) const { return 1; } 148 149 void normalizeStopsAndEndpointsOutsideRange(Vector<GradientStop>& stops) 150 { 151 float firstOffset = stops.first().offset; 152 float lastOffset = stops.last().offset; 153 if (firstOffset != lastOffset) { 154 float scale = lastOffset - firstOffset; 155 156 for (auto& stop : stops) 157 stop.offset = (stop.offset - firstOffset) / scale; 158 159 auto p0 = m_data.point0; 160 auto p1 = m_data.point1; 161 m_data.point0 = { p0.x() + firstOffset * (p1.x() - p0.x()), p0.y() + firstOffset * (p1.y() - p0.y()) }; 162 m_data.point1 = { p1.x() + (lastOffset - 1) * (p1.x() - p0.x()), p1.y() + (lastOffset - 1) * (p1.y() - p0.y()) }; 163 } else { 164 // There's a single position that is outside the scale, clamp the positions to 1. 165 for (auto& stop : stops) 166 stop.offset = 1; 167 } 168 } 169 170 private: 171 Gradient::LinearData& m_data; 172 }; 173 174 class RadialGradientAdapter { 175 public: 176 explicit RadialGradientAdapter(Gradient::RadialData& data) 177 : m_data(data) 178 { 179 } 180 181 FloatPoint startPoint() const { return m_data.point0; } 182 FloatPoint endPoint() const { return m_data.point0 + FloatSize { m_data.endRadius, 0 }; } 183 184 // Radial gradients may need to extend further than the endpoints, because they have 185 // to repeat out to the corners of the box. 186 float maxExtent(float maxLengthForRepeat, float gradientLength) const 187 { 188 if (maxLengthForRepeat > gradientLength) 189 return gradientLength > 0 ? maxLengthForRepeat / gradientLength : 0; 190 return 1; 191 } 192 193 void normalizeStopsAndEndpointsOutsideRange(Vector<GradientStop>& stops) 194 { 195 auto numStops = stops.size(); 196 197 // Rather than scaling the points < 0, we truncate them, so only scale according to the largest point. 198 float firstOffset = 0; 199 float lastOffset = stops.last().offset; 200 float scale = lastOffset - firstOffset; 201 202 // Reset points below 0 to the first visible color. 203 size_t firstZeroOrGreaterIndex = numStops; 204 for (size_t i = 0; i < numStops; ++i) { 205 if (stops[i].offset >= 0) { 206 firstZeroOrGreaterIndex = i; 207 break; 208 } 209 } 210 211 if (firstZeroOrGreaterIndex > 0) { 212 if (firstZeroOrGreaterIndex < numStops && stops[firstZeroOrGreaterIndex].offset > 0) { 213 float prevOffset = stops[firstZeroOrGreaterIndex - 1].offset; 214 float nextOffset = stops[firstZeroOrGreaterIndex].offset; 215 216 float interStopProportion = -prevOffset / (nextOffset - prevOffset); 217 // FIXME: when we interpolate gradients using premultiplied colors, this should do premultiplication. 218 Color blendedColor = blend(stops[firstZeroOrGreaterIndex - 1].color, stops[firstZeroOrGreaterIndex].color, interStopProportion); 219 220 // Clamp the positions to 0 and set the color. 221 for (size_t i = 0; i < firstZeroOrGreaterIndex; ++i) { 222 stops[i].offset = 0; 223 stops[i].color = blendedColor; 224 } 225 } else { 226 // All stops are below 0; just clamp them. 227 for (size_t i = 0; i < firstZeroOrGreaterIndex; ++i) 228 stops[i].offset = 0; 229 } 230 } 231 232 for (auto& stop : stops) 233 stop.offset /= scale; 234 235 m_data.startRadius *= scale; 236 m_data.endRadius *= scale; 237 } 238 239 private: 240 Gradient::RadialData& m_data; 241 }; 242 243 template<typename GradientAdapter> 244 Gradient::ColorStopVector CSSGradientValue::computeStops(GradientAdapter& gradient, const CSSToLengthConversionData& conversionData, float maxLengthForRepeat) 139 245 { 140 246 if (m_gradientType == CSSDeprecatedLinearGradient || m_gradientType == CSSDeprecatedRadialGradient) { 141 247 sortStopsIfNeeded(); 142 248 143 for (unsigned i = 0; i < m_stops.size(); i++) { 144 const CSSGradientColorStop& stop = m_stops[i]; 145 249 Gradient::ColorStopVector result; 250 result.reserveInitialCapacity(m_stops.size()); 251 252 for (auto& stop : m_stops) { 146 253 float offset; 147 254 if (stop.m_position->isPercentage()) … … 150 257 offset = stop.m_position->floatValue(CSSPrimitiveValue::CSS_NUMBER); 151 258 152 gradient.addColorStop(offset, stop.m_resolvedColor); 153 } 154 155 // The back end already sorted the stops. 156 gradient.setStopsSorted(true); 157 return; 259 result.uncheckedAppend({ offset, stop.m_resolvedColor }); 260 } 261 262 return result; 158 263 } 159 264 160 265 size_t numStops = m_stops.size(); 161 162 266 Vector<GradientStop> stops(numStops); 163 267 164 float gradientLength = 0; 165 bool computedGradientLength = false; 166 167 FloatPoint gradientStart = gradient.p0(); 168 FloatPoint gradientEnd; 169 if (isLinearGradientValue()) 170 gradientEnd = gradient.p1(); 171 else if (isRadialGradientValue()) 172 gradientEnd = gradientStart + FloatSize(gradient.endRadius(), 0); 268 auto gradientStart = gradient.startPoint(); 269 auto gradientEnd = gradient.endPoint(); 270 271 auto gradientSize = gradientStart - gradientEnd; 272 float gradientLength = gradientSize.diagonalLength(); 173 273 174 274 for (size_t i = 0; i < numStops; ++i) { 175 const CSSGradientColorStop& stop = m_stops[i];275 auto& stop = m_stops[i]; 176 276 177 277 stops[i].isMidpoint = stop.isMidpoint; … … 179 279 180 280 if (stop.m_position) { 181 const CSSPrimitiveValue& positionValue = *stop.m_position;281 auto& positionValue = *stop.m_position; 182 282 if (positionValue.isPercentage()) 183 283 stops[i].offset = positionValue.floatValue(CSSPrimitiveValue::CSS_PERCENTAGE) / 100; 184 284 else if (positionValue.isLength() || positionValue.isViewportPercentageLength() || positionValue.isCalculatedPercentageWithLength()) { 185 if (!computedGradientLength) {186 FloatSize gradientSize(gradientStart - gradientEnd);187 gradientLength = gradientSize.diagonalLength();188 }189 285 float length; 190 286 if (positionValue.isLength()) … … 343 439 // If the difference in the positions of the first and last color-stops is 0, 344 440 // the gradient defines a solid-color image with the color of the last color-stop in the rule. 345 float gradientRange = stops [numStops - 1].offset - stops[0].offset;441 float gradientRange = stops.last().offset - stops.first().offset; 346 442 if (!gradientRange) { 347 443 stops.first().offset = 0; … … 350 446 numStops = 1; 351 447 } else { 352 float maxExtent = 1; 353 354 // Radial gradients may need to extend further than the endpoints, because they have 355 // to repeat out to the corners of the box. 356 if (isRadialGradientValue()) { 357 if (!computedGradientLength) { 358 FloatSize gradientSize(gradientStart - gradientEnd); 359 gradientLength = gradientSize.diagonalLength(); 360 } 361 362 if (maxLengthForRepeat > gradientLength) 363 maxExtent = gradientLength > 0 ? maxLengthForRepeat / gradientLength : 0; 364 } 448 float maxExtent = gradient.maxExtent(maxLengthForRepeat, gradientLength); 365 449 366 450 size_t originalNumStops = numStops; … … 408 492 } 409 493 410 numStops = stops.size();411 412 494 // If the gradient goes outside the 0-1 range, normalize it by moving the endpoints, and adjusting the stops. 413 if (numStops > 1 && (stops[0].offset < 0 || stops[numStops - 1].offset > 1)) { 414 if (isLinearGradientValue()) { 415 float firstOffset = stops[0].offset; 416 float lastOffset = stops[numStops - 1].offset; 417 if (firstOffset != lastOffset) { 418 float scale = lastOffset - firstOffset; 419 420 for (size_t i = 0; i < numStops; ++i) 421 stops[i].offset = (stops[i].offset - firstOffset) / scale; 422 423 FloatPoint p0 = gradient.p0(); 424 FloatPoint p1 = gradient.p1(); 425 gradient.setP0(FloatPoint(p0.x() + firstOffset * (p1.x() - p0.x()), p0.y() + firstOffset * (p1.y() - p0.y()))); 426 gradient.setP1(FloatPoint(p1.x() + (lastOffset - 1) * (p1.x() - p0.x()), p1.y() + (lastOffset - 1) * (p1.y() - p0.y()))); 427 } else { 428 // There's a single position that is outside the scale, clamp the positions to 1. 429 for (size_t i = 0; i < numStops; ++i) 430 stops[i].offset = 1; 431 } 432 } else if (isRadialGradientValue()) { 433 // Rather than scaling the points < 0, we truncate them, so only scale according to the largest point. 434 float firstOffset = 0; 435 float lastOffset = stops[numStops - 1].offset; 436 float scale = lastOffset - firstOffset; 437 438 // Reset points below 0 to the first visible color. 439 size_t firstZeroOrGreaterIndex = numStops; 440 for (size_t i = 0; i < numStops; ++i) { 441 if (stops[i].offset >= 0) { 442 firstZeroOrGreaterIndex = i; 443 break; 444 } 445 } 446 447 if (firstZeroOrGreaterIndex > 0) { 448 if (firstZeroOrGreaterIndex < numStops && stops[firstZeroOrGreaterIndex].offset > 0) { 449 float prevOffset = stops[firstZeroOrGreaterIndex - 1].offset; 450 float nextOffset = stops[firstZeroOrGreaterIndex].offset; 451 452 float interStopProportion = -prevOffset / (nextOffset - prevOffset); 453 // FIXME: when we interpolate gradients using premultiplied colors, this should do premultiplication. 454 Color blendedColor = blend(stops[firstZeroOrGreaterIndex - 1].color, stops[firstZeroOrGreaterIndex].color, interStopProportion); 455 456 // Clamp the positions to 0 and set the color. 457 for (size_t i = 0; i < firstZeroOrGreaterIndex; ++i) { 458 stops[i].offset = 0; 459 stops[i].color = blendedColor; 460 } 461 } else { 462 // All stops are below 0; just clamp them. 463 for (size_t i = 0; i < firstZeroOrGreaterIndex; ++i) 464 stops[i].offset = 0; 465 } 466 } 467 468 for (size_t i = 0; i < numStops; ++i) 469 stops[i].offset /= scale; 470 471 gradient.setStartRadius(gradient.startRadius() * scale); 472 gradient.setEndRadius(gradient.endRadius() * scale); 473 } 474 } 475 476 for (unsigned i = 0; i < numStops; i++) 477 gradient.addColorStop(stops[i].offset, stops[i].color); 478 479 gradient.setStopsSorted(true); 495 if (stops.size() > 1 && (stops.first().offset < 0 || stops.last().offset > 1)) 496 gradient.normalizeStopsAndEndpointsOutsideRange(stops); 497 498 Gradient::ColorStopVector result; 499 result.reserveInitialCapacity(stops.size()); 500 for (auto& stop : stops) 501 result.uncheckedAppend({ stop.offset, stop.color }); 502 503 return result; 480 504 } 481 505 … … 625 649 626 650 for (unsigned i = 0; i < m_stops.size(); i++) { 627 const CSSGradientColorStop& stop = m_stops[i];651 auto& stop = m_stops[i]; 628 652 result.appendLiteral(", "); 629 653 result.append(stop.m_color->cssText()); … … 802 826 ASSERT_NOT_REACHED(); 803 827 } 804 805 } 806 807 Ref<Gradient> gradient = Gradient::create(firstPoint, secondPoint);808 809 // Now add the stops. 810 a ddStops(gradient, conversionData, 1);811 828 } 829 830 Gradient::LinearData data { firstPoint, secondPoint }; 831 LinearGradientAdapter adapter { data }; 832 auto stops = computeStops(adapter, conversionData, 1); 833 834 auto gradient = Gradient::create(WTFMove(data)); 835 gradient->setSortedColorStops(WTFMove(stops)); 812 836 return gradient; 813 837 } … … 1214 1238 } 1215 1239 1216 Ref<Gradient> gradient = Gradient::create(firstPoint, firstRadius, secondPoint, secondRadius, aspectRatio); 1217 1218 // addStops() only uses maxExtent for repeating gradients. 1240 // computeStops() only uses maxExtent for repeating gradients. 1219 1241 float maxExtent = 0; 1220 1242 if (m_repeating) { … … 1223 1245 } 1224 1246 1225 // Now add the stops. 1226 addStops(gradient, conversionData, maxExtent); 1227 1247 Gradient::RadialData data { firstPoint, secondPoint, firstRadius, secondRadius, aspectRatio }; 1248 RadialGradientAdapter adapter { data }; 1249 auto stops = computeStops(adapter, conversionData, maxExtent); 1250 1251 auto gradient = Gradient::create(WTFMove(data)); 1252 gradient->setSortedColorStops(WTFMove(stops)); 1228 1253 return gradient; 1229 1254 } … … 1327 1352 { 1328 1353 // FIXME: Implement. 1329 return Gradient::create( FloatPoint { }, FloatPoint{ });1354 return Gradient::create(Gradient::LinearData { }); 1330 1355 } 1331 1356
Note:
See TracChangeset
for help on using the changeset viewer.