1 /*
2 * Copyright 2015 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8 #include "src/gpu/effects/GrXfermodeFragmentProcessor.h"
9
10 #include "src/core/SkXfermodePriv.h"
11 #include "src/gpu/GrFragmentProcessor.h"
12 #include "src/gpu/SkGr.h"
13 #include "src/gpu/effects/generated/GrConstColorProcessor.h"
14 #include "src/gpu/glsl/GrGLSLBlend.h"
15 #include "src/gpu/glsl/GrGLSLFragmentProcessor.h"
16 #include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
17
18 // Some of the cpu implementations of blend modes differ too much from the GPU enough that
19 // we can't use the cpu implementation to implement constantOutputForConstantInput.
does_cpu_blend_impl_match_gpu(SkBlendMode mode)20 static inline bool does_cpu_blend_impl_match_gpu(SkBlendMode mode) {
21 // The non-seperable modes differ too much. So does SoftLight. ColorBurn differs too much on our
22 // test iOS device (but we just disable it across the aboard since it may happen on untested
23 // GPUs).
24 return mode <= SkBlendMode::kLastSeparableMode && mode != SkBlendMode::kSoftLight &&
25 mode != SkBlendMode::kColorBurn;
26 }
27
28 //////////////////////////////////////////////////////////////////////////////
29
30 class ComposeTwoFragmentProcessor : public GrFragmentProcessor {
31 public:
Make(std::unique_ptr<GrFragmentProcessor> src,std::unique_ptr<GrFragmentProcessor> dst,SkBlendMode mode)32 static std::unique_ptr<GrFragmentProcessor> Make(std::unique_ptr<GrFragmentProcessor> src,
33 std::unique_ptr<GrFragmentProcessor> dst,
34 SkBlendMode mode) {
35 return std::unique_ptr<GrFragmentProcessor>(
36 new ComposeTwoFragmentProcessor(std::move(src), std::move(dst), mode));
37 }
38
name() const39 const char* name() const override { return "ComposeTwo"; }
40
41 #ifdef SK_DEBUG
dumpInfo() const42 SkString dumpInfo() const override {
43 SkString str;
44
45 str.appendf("Mode: %s", SkBlendMode_Name(fMode));
46
47 for (int i = 0; i < this->numChildProcessors(); ++i) {
48 str.appendf(" [%s %s]",
49 this->childProcessor(i).name(), this->childProcessor(i).dumpInfo().c_str());
50 }
51 return str;
52 }
53 #endif
54
55 std::unique_ptr<GrFragmentProcessor> clone() const override;
56
getMode() const57 SkBlendMode getMode() const { return fMode; }
58
59 private:
ComposeTwoFragmentProcessor(std::unique_ptr<GrFragmentProcessor> src,std::unique_ptr<GrFragmentProcessor> dst,SkBlendMode mode)60 ComposeTwoFragmentProcessor(std::unique_ptr<GrFragmentProcessor> src,
61 std::unique_ptr<GrFragmentProcessor> dst,
62 SkBlendMode mode)
63 : INHERITED(kComposeTwoFragmentProcessor_ClassID, OptFlags(src.get(), dst.get(), mode))
64 , fMode(mode) {
65 SkDEBUGCODE(int shaderAChildIndex = )this->registerChildProcessor(std::move(src));
66 SkDEBUGCODE(int shaderBChildIndex = )this->registerChildProcessor(std::move(dst));
67 SkASSERT(0 == shaderAChildIndex);
68 SkASSERT(1 == shaderBChildIndex);
69 }
70
OptFlags(const GrFragmentProcessor * src,const GrFragmentProcessor * dst,SkBlendMode mode)71 static OptimizationFlags OptFlags(const GrFragmentProcessor* src,
72 const GrFragmentProcessor* dst, SkBlendMode mode) {
73 OptimizationFlags flags;
74 switch (mode) {
75 case SkBlendMode::kClear:
76 case SkBlendMode::kSrc:
77 case SkBlendMode::kDst:
78 SK_ABORT("Should never create clear, src, or dst compose two FP.");
79 flags = kNone_OptimizationFlags;
80 break;
81
82 // Produces opaque if both src and dst are opaque.
83 case SkBlendMode::kSrcIn:
84 case SkBlendMode::kDstIn:
85 case SkBlendMode::kModulate:
86 flags = src->preservesOpaqueInput() && dst->preservesOpaqueInput()
87 ? kPreservesOpaqueInput_OptimizationFlag
88 : kNone_OptimizationFlags;
89 break;
90
91 // Produces zero when both are opaque, indeterminate if one is opaque.
92 case SkBlendMode::kSrcOut:
93 case SkBlendMode::kDstOut:
94 case SkBlendMode::kXor:
95 flags = kNone_OptimizationFlags;
96 break;
97
98 // Is opaque if the dst is opaque.
99 case SkBlendMode::kSrcATop:
100 flags = dst->preservesOpaqueInput() ? kPreservesOpaqueInput_OptimizationFlag
101 : kNone_OptimizationFlags;
102 break;
103
104 // DstATop is the converse of kSrcATop. Screen is also opaque if the src is a opaque.
105 case SkBlendMode::kDstATop:
106 case SkBlendMode::kScreen:
107 flags = src->preservesOpaqueInput() ? kPreservesOpaqueInput_OptimizationFlag
108 : kNone_OptimizationFlags;
109 break;
110
111 // These modes are all opaque if either src or dst is opaque. All the advanced modes
112 // compute alpha as src-over.
113 case SkBlendMode::kSrcOver:
114 case SkBlendMode::kDstOver:
115 case SkBlendMode::kPlus:
116 case SkBlendMode::kOverlay:
117 case SkBlendMode::kDarken:
118 case SkBlendMode::kLighten:
119 case SkBlendMode::kColorDodge:
120 case SkBlendMode::kColorBurn:
121 case SkBlendMode::kHardLight:
122 case SkBlendMode::kSoftLight:
123 case SkBlendMode::kDifference:
124 case SkBlendMode::kExclusion:
125 case SkBlendMode::kMultiply:
126 case SkBlendMode::kHue:
127 case SkBlendMode::kSaturation:
128 case SkBlendMode::kColor:
129 case SkBlendMode::kLuminosity:
130 flags = src->preservesOpaqueInput() || dst->preservesOpaqueInput()
131 ? kPreservesOpaqueInput_OptimizationFlag
132 : kNone_OptimizationFlags;
133 break;
134 }
135 if (does_cpu_blend_impl_match_gpu(mode) && src->hasConstantOutputForConstantInput() &&
136 dst->hasConstantOutputForConstantInput()) {
137 flags |= kConstantOutputForConstantInput_OptimizationFlag;
138 }
139 return flags;
140 }
141
onGetGLSLProcessorKey(const GrShaderCaps & caps,GrProcessorKeyBuilder * b) const142 void onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override {
143 b->add32((int)fMode);
144 }
145
onIsEqual(const GrFragmentProcessor & other) const146 bool onIsEqual(const GrFragmentProcessor& other) const override {
147 const ComposeTwoFragmentProcessor& cs = other.cast<ComposeTwoFragmentProcessor>();
148 return fMode == cs.fMode;
149 }
150
constantOutputForConstantInput(const SkPMColor4f & input) const151 SkPMColor4f constantOutputForConstantInput(const SkPMColor4f& input) const override {
152 SkPMColor4f opaqueInput = { input.fR, input.fG, input.fB, 1 };
153 SkPMColor4f src = ConstantOutputForConstantInput(this->childProcessor(0), opaqueInput);
154 SkPMColor4f dst = ConstantOutputForConstantInput(this->childProcessor(1), opaqueInput);
155 SkPMColor4f res = SkBlendMode_Apply(fMode, src, dst);
156 return res * input.fA;
157 }
158
159 GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
160
161 SkBlendMode fMode;
162
163 GR_DECLARE_FRAGMENT_PROCESSOR_TEST
164
165 typedef GrFragmentProcessor INHERITED;
166 };
167
168 /////////////////////////////////////////////////////////////////////
169
170 class GLComposeTwoFragmentProcessor : public GrGLSLFragmentProcessor {
171 public:
172 void emitCode(EmitArgs&) override;
173
174 private:
175 typedef GrGLSLFragmentProcessor INHERITED;
176 };
177
178 /////////////////////////////////////////////////////////////////////
179
180 GR_DEFINE_FRAGMENT_PROCESSOR_TEST(ComposeTwoFragmentProcessor);
181
182 #if GR_TEST_UTILS
TestCreate(GrProcessorTestData * d)183 std::unique_ptr<GrFragmentProcessor> ComposeTwoFragmentProcessor::TestCreate(
184 GrProcessorTestData* d) {
185 // Create two random frag procs.
186 std::unique_ptr<GrFragmentProcessor> fpA(GrProcessorUnitTest::MakeChildFP(d));
187 std::unique_ptr<GrFragmentProcessor> fpB(GrProcessorUnitTest::MakeChildFP(d));
188
189 SkBlendMode mode;
190 do {
191 mode = static_cast<SkBlendMode>(d->fRandom->nextRangeU(0, (int)SkBlendMode::kLastMode));
192 } while (SkBlendMode::kClear == mode || SkBlendMode::kSrc == mode || SkBlendMode::kDst == mode);
193 return std::unique_ptr<GrFragmentProcessor>(
194 new ComposeTwoFragmentProcessor(std::move(fpA), std::move(fpB), mode));
195 }
196 #endif
197
clone() const198 std::unique_ptr<GrFragmentProcessor> ComposeTwoFragmentProcessor::clone() const {
199 auto src = this->childProcessor(0).clone();
200 auto dst = this->childProcessor(1).clone();
201 return std::unique_ptr<GrFragmentProcessor>(
202 new ComposeTwoFragmentProcessor(std::move(src), std::move(dst), fMode));
203 }
204
onCreateGLSLInstance() const205 GrGLSLFragmentProcessor* ComposeTwoFragmentProcessor::onCreateGLSLInstance() const{
206 return new GLComposeTwoFragmentProcessor;
207 }
208
209 /////////////////////////////////////////////////////////////////////
210
emitCode(EmitArgs & args)211 void GLComposeTwoFragmentProcessor::emitCode(EmitArgs& args) {
212
213 GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
214 const ComposeTwoFragmentProcessor& cs = args.fFp.cast<ComposeTwoFragmentProcessor>();
215
216 const char* inputColor = nullptr;
217 if (args.fInputColor) {
218 inputColor = "inputColor";
219 fragBuilder->codeAppendf("half4 inputColor = half4(%s.rgb, 1.0);", args.fInputColor);
220 }
221
222 // declare outputColor and emit the code for each of the two children
223 SkString srcColor("xfer_src");
224 this->invokeChild(0, inputColor, &srcColor, args);
225
226 SkString dstColor("xfer_dst");
227 this->invokeChild(1, inputColor, &dstColor, args);
228
229 // emit blend code
230 SkBlendMode mode = cs.getMode();
231 fragBuilder->codeAppendf("// Compose Xfer Mode: %s\n", SkBlendMode_Name(mode));
232 GrGLSLBlend::AppendMode(fragBuilder,
233 srcColor.c_str(),
234 dstColor.c_str(),
235 args.fOutputColor,
236 mode);
237
238 // re-multiply the output color by the input color's alpha
239 if (args.fInputColor) {
240 fragBuilder->codeAppendf("%s *= %s.a;", args.fOutputColor, args.fInputColor);
241 }
242 }
243
MakeFromTwoProcessors(std::unique_ptr<GrFragmentProcessor> src,std::unique_ptr<GrFragmentProcessor> dst,SkBlendMode mode)244 std::unique_ptr<GrFragmentProcessor> GrXfermodeFragmentProcessor::MakeFromTwoProcessors(
245 std::unique_ptr<GrFragmentProcessor> src,
246 std::unique_ptr<GrFragmentProcessor> dst,
247 SkBlendMode mode) {
248 switch (mode) {
249 case SkBlendMode::kClear:
250 return GrConstColorProcessor::Make(SK_PMColor4fTRANSPARENT,
251 GrConstColorProcessor::InputMode::kIgnore);
252 case SkBlendMode::kSrc:
253 return src;
254 case SkBlendMode::kDst:
255 return dst;
256 default:
257 return ComposeTwoFragmentProcessor::Make(std::move(src), std::move(dst), mode);
258 }
259 }
260
261 //////////////////////////////////////////////////////////////////////////////
262
263 class ComposeOneFragmentProcessor : public GrFragmentProcessor {
264 public:
265 enum Child {
266 kDst_Child,
267 kSrc_Child,
268 };
269
Make(std::unique_ptr<GrFragmentProcessor> fp,SkBlendMode mode,Child child)270 static std::unique_ptr<GrFragmentProcessor> Make(std::unique_ptr<GrFragmentProcessor> fp,
271 SkBlendMode mode, Child child) {
272 if (!fp) {
273 return nullptr;
274 }
275 return std::unique_ptr<GrFragmentProcessor>(
276 new ComposeOneFragmentProcessor(std::move(fp), mode, child));
277 }
278
name() const279 const char* name() const override { return "ComposeOne"; }
280
281 #ifdef SK_DEBUG
dumpInfo() const282 SkString dumpInfo() const override {
283 SkString str;
284
285 str.appendf("Mode: %s, Child: %s",
286 SkBlendMode_Name(fMode), kDst_Child == fChild ? "Dst" : "Src");
287
288 for (int i = 0; i < this->numChildProcessors(); ++i) {
289 str.appendf(" [%s %s]",
290 this->childProcessor(i).name(), this->childProcessor(i).dumpInfo().c_str());
291 }
292 return str;
293 }
294 #endif
295
296 std::unique_ptr<GrFragmentProcessor> clone() const override;
297
mode() const298 SkBlendMode mode() const { return fMode; }
299
child() const300 Child child() const { return fChild; }
301
302 private:
OptFlags(const GrFragmentProcessor * fp,SkBlendMode mode,Child child)303 OptimizationFlags OptFlags(const GrFragmentProcessor* fp, SkBlendMode mode, Child child) {
304 OptimizationFlags flags;
305 switch (mode) {
306 case SkBlendMode::kClear:
307 SK_ABORT("Should never create clear compose one FP.");
308 flags = kNone_OptimizationFlags;
309 break;
310
311 case SkBlendMode::kSrc:
312 SkASSERT(child == kSrc_Child);
313 flags = fp->preservesOpaqueInput() ? kPreservesOpaqueInput_OptimizationFlag
314 : kNone_OptimizationFlags;
315 break;
316
317 case SkBlendMode::kDst:
318 SkASSERT(child == kDst_Child);
319 flags = fp->preservesOpaqueInput() ? kPreservesOpaqueInput_OptimizationFlag
320 : kNone_OptimizationFlags;
321 break;
322
323 // Produces opaque if both src and dst are opaque. These also will modulate the child's
324 // output by either the input color or alpha. However, if the child is not compatible
325 // with the coverage as alpha then it may produce a color that is not valid premul.
326 case SkBlendMode::kSrcIn:
327 case SkBlendMode::kDstIn:
328 case SkBlendMode::kModulate:
329 flags = ProcessorOptimizationFlags(fp) &
330 ~kConstantOutputForConstantInput_OptimizationFlag;
331 break;
332
333 // Produces zero when both are opaque, indeterminate if one is opaque.
334 case SkBlendMode::kSrcOut:
335 case SkBlendMode::kDstOut:
336 case SkBlendMode::kXor:
337 flags = kNone_OptimizationFlags;
338 break;
339
340 // Is opaque if the dst is opaque.
341 case SkBlendMode::kSrcATop:
342 if (child == kDst_Child) {
343 flags = fp->preservesOpaqueInput() ? kPreservesOpaqueInput_OptimizationFlag
344 : kNone_OptimizationFlags;
345 } else {
346 flags = kPreservesOpaqueInput_OptimizationFlag;
347 }
348 break;
349
350 // DstATop is the converse of kSrcATop. Screen is also opaque if the src is a opaque.
351 case SkBlendMode::kDstATop:
352 case SkBlendMode::kScreen:
353 if (child == kSrc_Child) {
354 flags = fp->preservesOpaqueInput() ? kPreservesOpaqueInput_OptimizationFlag
355 : kNone_OptimizationFlags;
356 } else {
357 flags = kPreservesOpaqueInput_OptimizationFlag;
358 }
359 break;
360
361 // These modes are all opaque if either src or dst is opaque. All the advanced modes
362 // compute alpha as src-over.
363 case SkBlendMode::kSrcOver:
364 case SkBlendMode::kDstOver:
365 case SkBlendMode::kPlus:
366 case SkBlendMode::kOverlay:
367 case SkBlendMode::kDarken:
368 case SkBlendMode::kLighten:
369 case SkBlendMode::kColorDodge:
370 case SkBlendMode::kColorBurn:
371 case SkBlendMode::kHardLight:
372 case SkBlendMode::kSoftLight:
373 case SkBlendMode::kDifference:
374 case SkBlendMode::kExclusion:
375 case SkBlendMode::kMultiply:
376 case SkBlendMode::kHue:
377 case SkBlendMode::kSaturation:
378 case SkBlendMode::kColor:
379 case SkBlendMode::kLuminosity:
380 flags = kPreservesOpaqueInput_OptimizationFlag;
381 break;
382 }
383 if (does_cpu_blend_impl_match_gpu(mode) && fp->hasConstantOutputForConstantInput()) {
384 flags |= kConstantOutputForConstantInput_OptimizationFlag;
385 }
386 return flags;
387 }
388
onGetGLSLProcessorKey(const GrShaderCaps & caps,GrProcessorKeyBuilder * b) const389 void onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override {
390 GR_STATIC_ASSERT(((int)SkBlendMode::kLastMode & UINT16_MAX) == (int)SkBlendMode::kLastMode);
391 b->add32((int)fMode | (fChild << 16));
392 }
393
onIsEqual(const GrFragmentProcessor & that) const394 bool onIsEqual(const GrFragmentProcessor& that) const override {
395 return fMode == that.cast<ComposeOneFragmentProcessor>().fMode;
396 }
397
constantOutputForConstantInput(const SkPMColor4f & inputColor) const398 SkPMColor4f constantOutputForConstantInput(const SkPMColor4f& inputColor) const override {
399 SkPMColor4f childColor = ConstantOutputForConstantInput(this->childProcessor(0),
400 SK_PMColor4fWHITE);
401 SkPMColor4f src, dst;
402 if (kSrc_Child == fChild) {
403 src = childColor;
404 dst = inputColor;
405 } else {
406 src = inputColor;
407 dst = childColor;
408 }
409 return SkBlendMode_Apply(fMode, src, dst);
410 }
411
412 private:
ComposeOneFragmentProcessor(std::unique_ptr<GrFragmentProcessor> fp,SkBlendMode mode,Child child)413 ComposeOneFragmentProcessor(std::unique_ptr<GrFragmentProcessor> fp, SkBlendMode mode,
414 Child child)
415 : INHERITED(kComposeOneFragmentProcessor_ClassID, OptFlags(fp.get(), mode, child))
416 , fMode(mode)
417 , fChild(child) {
418 SkDEBUGCODE(int dstIndex =) this->registerChildProcessor(std::move(fp));
419 SkASSERT(0 == dstIndex);
420 }
421
422 GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
423
424 SkBlendMode fMode;
425 Child fChild;
426
427 GR_DECLARE_FRAGMENT_PROCESSOR_TEST
428
429 typedef GrFragmentProcessor INHERITED;
430 };
431
432 //////////////////////////////////////////////////////////////////////////////
433
434 class GLComposeOneFragmentProcessor : public GrGLSLFragmentProcessor {
435 public:
emitCode(EmitArgs & args)436 void emitCode(EmitArgs& args) override {
437 GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
438 SkBlendMode mode = args.fFp.cast<ComposeOneFragmentProcessor>().mode();
439 ComposeOneFragmentProcessor::Child child =
440 args.fFp.cast<ComposeOneFragmentProcessor>().child();
441 SkString childColor("child");
442 this->invokeChild(0, &childColor, args);
443
444 // emit blend code
445 fragBuilder->codeAppendf("// Compose Xfer Mode: %s\n", SkBlendMode_Name(mode));
446 const char* childStr = childColor.c_str();
447 if (ComposeOneFragmentProcessor::kDst_Child == child) {
448 GrGLSLBlend::AppendMode(fragBuilder, args.fInputColor, childStr, args.fOutputColor, mode);
449 } else {
450 GrGLSLBlend::AppendMode(fragBuilder, childStr, args.fInputColor, args.fOutputColor, mode);
451 }
452 }
453
454 private:
455 typedef GrGLSLFragmentProcessor INHERITED;
456 };
457
458 /////////////////////////////////////////////////////////////////////
459
460 GR_DEFINE_FRAGMENT_PROCESSOR_TEST(ComposeOneFragmentProcessor);
461
462 #if GR_TEST_UTILS
TestCreate(GrProcessorTestData * d)463 std::unique_ptr<GrFragmentProcessor> ComposeOneFragmentProcessor::TestCreate(
464 GrProcessorTestData* d) {
465 // Create one random frag procs.
466 // For now, we'll prevent either children from being a shader with children to prevent the
467 // possibility of an arbitrarily large tree of procs.
468 std::unique_ptr<GrFragmentProcessor> dst(GrProcessorUnitTest::MakeChildFP(d));
469 SkBlendMode mode;
470 ComposeOneFragmentProcessor::Child child;
471 do {
472 mode = static_cast<SkBlendMode>(d->fRandom->nextRangeU(0, (int)SkBlendMode::kLastMode));
473 child = d->fRandom->nextBool() ? kDst_Child : kSrc_Child;
474 } while (SkBlendMode::kClear == mode || (SkBlendMode::kDst == mode && child == kSrc_Child) ||
475 (SkBlendMode::kSrc == mode && child == kDst_Child));
476 return std::unique_ptr<GrFragmentProcessor>(
477 new ComposeOneFragmentProcessor(std::move(dst), mode, child));
478 }
479 #endif
480
onCreateGLSLInstance() const481 GrGLSLFragmentProcessor* ComposeOneFragmentProcessor::onCreateGLSLInstance() const {
482 return new GLComposeOneFragmentProcessor;
483 }
484
clone() const485 std::unique_ptr<GrFragmentProcessor> ComposeOneFragmentProcessor::clone() const {
486 return std::unique_ptr<GrFragmentProcessor>(
487 new ComposeOneFragmentProcessor(this->childProcessor(0).clone(), fMode, fChild));
488 }
489
490 //////////////////////////////////////////////////////////////////////////////
491
492 // It may seems as though when the input FP is the dst and the mode is kDst (or same for src/kSrc)
493 // that these factories could simply return the input FP. However, that doesn't have quite
494 // the same effect as the returned compose FP will replace the FP's input with solid white and
495 // ignore the original input. This could be implemented as:
496 // RunInSeries(ConstColor(WHITE, kIgnoreInput), inputFP).
497
MakeFromDstProcessor(std::unique_ptr<GrFragmentProcessor> dst,SkBlendMode mode)498 std::unique_ptr<GrFragmentProcessor> GrXfermodeFragmentProcessor::MakeFromDstProcessor(
499 std::unique_ptr<GrFragmentProcessor> dst, SkBlendMode mode) {
500 switch (mode) {
501 case SkBlendMode::kClear:
502 return GrConstColorProcessor::Make(SK_PMColor4fTRANSPARENT,
503 GrConstColorProcessor::InputMode::kIgnore);
504 case SkBlendMode::kSrc:
505 return nullptr;
506 default:
507 return ComposeOneFragmentProcessor::Make(std::move(dst), mode,
508 ComposeOneFragmentProcessor::kDst_Child);
509 }
510 }
511
MakeFromSrcProcessor(std::unique_ptr<GrFragmentProcessor> src,SkBlendMode mode)512 std::unique_ptr<GrFragmentProcessor> GrXfermodeFragmentProcessor::MakeFromSrcProcessor(
513 std::unique_ptr<GrFragmentProcessor> src, SkBlendMode mode) {
514 switch (mode) {
515 case SkBlendMode::kClear:
516 return GrConstColorProcessor::Make(SK_PMColor4fTRANSPARENT,
517 GrConstColorProcessor::InputMode::kIgnore);
518 case SkBlendMode::kDst:
519 return nullptr;
520 default:
521 return ComposeOneFragmentProcessor::Make(std::move(src), mode,
522 ComposeOneFragmentProcessor::kSrc_Child);
523 }
524 }
525