* Assumes t - startOffset is on the stack and does a linear interpolation on t between startOffset * and endOffset from prevColor to curColor (for each color component), leaving the result in * component order on the stack. It assumes there are always 3 components per color. */
| 142 | * component order on the stack. It assumes there are always 3 components per color. |
| 143 | */ |
| 144 | void InterpolateColorCode(float range, Color beginColor, Color endColor, |
| 145 | const std::shared_ptr<MemoryWriteStream>& result) { |
| 146 | // Linearly interpolate from the previous color to the current. Scale the colors from 0..255 to |
| 147 | // 0..1 and determine the multipliers for interpolation. |
| 148 | // C{r,g,b}(t, section) = t - offset_(section-1) + t * Multiplier{r,g,b}. |
| 149 | |
| 150 | // Figure out how to scale each color component. |
| 151 | constexpr int ColorComponents = 3; |
| 152 | float multiplier[ColorComponents]; |
| 153 | for (int i = 0; i < ColorComponents; i++) { |
| 154 | multiplier[i] = (endColor[i] - beginColor[i]) / range; |
| 155 | } |
| 156 | |
| 157 | // Calculate when we no longer need to keep a copy of the input parameter t. If the last component |
| 158 | // to use t is i, then dupInput[0..i - 1] = true and dupInput[i .. components] = false. |
| 159 | bool dupInput[ColorComponents]; |
| 160 | dupInput[ColorComponents - 1] = false; |
| 161 | for (int i = ColorComponents - 2; i >= 0; i--) { |
| 162 | dupInput[i] = dupInput[i + 1] || multiplier[i + 1] != 0; |
| 163 | } |
| 164 | |
| 165 | if (!dupInput[0] && multiplier[0] == 0) { |
| 166 | result->writeText("pop "); |
| 167 | } |
| 168 | |
| 169 | for (int i = 0; i < ColorComponents; i++) { |
| 170 | // If the next components needs t and this component will consume a |
| 171 | // copy, make another copy. |
| 172 | if (dupInput[i] && multiplier[i] != 0) { |
| 173 | result->writeText("dup "); |
| 174 | } |
| 175 | |
| 176 | auto colorComponent = static_cast<uint8_t>(beginColor[i] * 255); |
| 177 | if (multiplier[i] == 0) { |
| 178 | PDFUtils::AppendColorComponent(colorComponent, result); |
| 179 | result->writeText(" "); |
| 180 | } else { |
| 181 | if (multiplier[i] != 1) { |
| 182 | PDFUtils::AppendFloat(multiplier[i], result); |
| 183 | result->writeText(" mul "); |
| 184 | } |
| 185 | if (colorComponent != 0) { |
| 186 | PDFUtils::AppendColorComponent(colorComponent, result); |
| 187 | result->writeText(" add "); |
| 188 | } |
| 189 | } |
| 190 | |
| 191 | if (dupInput[i]) { |
| 192 | result->writeText("exch "); |
| 193 | } |
| 194 | } |
| 195 | } |
| 196 | |
| 197 | void WriteGradientRanges(const GradientInfo& info, const std::vector<size_t>& rangeEnds, bool top, |
| 198 | bool first, const std::shared_ptr<MemoryWriteStream>& result) { |
no test coverage detected