Generate Type 4 function code to map t to the passed gradient, clamping at the ends. The types integer, real, and boolean are available. There are no string, array, procedure, variable, or name types available. The generated code will be of the following form with all values hard coded. if (t <= 0) { ret = color[0]; t = 0; } if (t > 0 && t <= stop[4]) { if (t <= stop[2
| 299 | 0 gt {1 1 1} if |
| 300 | */ |
| 301 | void GradientFunctionCode(const GradientInfo& info, |
| 302 | const std::shared_ptr<MemoryWriteStream>& result) { |
| 303 | // While looking for a hit the stack is [t]. After finding a hit the stack is [r g b 0]. The 0 is |
| 304 | // consumed just before returning. |
| 305 | |
| 306 | // The initial range has no previous and contains a solid color. |
| 307 | // Any t <= 0 will be handled by this initial range, so later t == 0 indicates a hit was found. |
| 308 | result->writeText("dup 0 le {pop "); |
| 309 | PDFUtils::AppendColorComponent(static_cast<uint8_t>(info.colors[0].red * 255), result); |
| 310 | result->writeText(" "); |
| 311 | PDFUtils::AppendColorComponent(static_cast<uint8_t>(info.colors[0].green * 255), result); |
| 312 | result->writeText(" "); |
| 313 | PDFUtils::AppendColorComponent(static_cast<uint8_t>(info.colors[0].blue * 255), result); |
| 314 | result->writeText(" 0} if\n"); |
| 315 | |
| 316 | // Optimize out ranges which don't make any visual difference. |
| 317 | std::vector<size_t> rangeEnds(info.colors.size()); |
| 318 | size_t rangeEndsCount = 0; |
| 319 | for (size_t i = 1; i < info.colors.size(); ++i) { |
| 320 | // Ignoring the alpha, is this range the same solid color as the next range? |
| 321 | // This optimizes gradients where sometimes only the color or only the alpha is changing. |
| 322 | auto eqIgnoringAlpha = [](Color a, Color b) { |
| 323 | return FloatNearlyEqual(a.red, b.red) && FloatNearlyEqual(a.green, b.green) && |
| 324 | FloatNearlyEqual(a.blue, b.blue); |
| 325 | }; |
| 326 | |
| 327 | bool constantColorBothSides = |
| 328 | eqIgnoringAlpha(info.colors[i - 1], info.colors[i]) && // This range is a solid color. |
| 329 | i != info.colors.size() - 1 && // This is not the last range. |
| 330 | eqIgnoringAlpha(info.colors[i], info.colors[i + 1]); // Next range is same solid color. |
| 331 | |
| 332 | // Does this range have zero size? |
| 333 | bool degenerateRange = info.positions[i - 1] == info.positions[i]; |
| 334 | |
| 335 | if (!degenerateRange && !constantColorBothSides) { |
| 336 | rangeEnds[rangeEndsCount] = i; |
| 337 | ++rangeEndsCount; |
| 338 | } |
| 339 | } |
| 340 | |
| 341 | // If a cap on depth is needed, loop here. |
| 342 | std::vector<size_t> range(rangeEnds.begin(), |
| 343 | rangeEnds.begin() + static_cast<std::ptrdiff_t>(rangeEndsCount)); |
| 344 | WriteGradientRanges(info, range, true, true, result); |
| 345 | |
| 346 | // Clamp the final color. |
| 347 | result->writeText("0 gt {"); |
| 348 | PDFUtils::AppendColorComponent(static_cast<uint8_t>(info.colors.back().red * 255), result); |
| 349 | result->writeText(" "); |
| 350 | PDFUtils::AppendColorComponent(static_cast<uint8_t>(info.colors.back().green * 255), result); |
| 351 | result->writeText(" "); |
| 352 | PDFUtils::AppendColorComponent(static_cast<uint8_t>(info.colors.back().blue * 255), result); |
| 353 | result->writeText("} if\n"); |
| 354 | } |
| 355 | |
| 356 | void LinearCode(const GradientInfo& info, const Matrix& /*perspectiveRemover*/, |
| 357 | const std::shared_ptr<MemoryWriteStream>& function) { |
no test coverage detected