/* * Checks if a (mergeable) op can be merged into this batch * * If true, the op's multiDraw must be guaranteed to handle both ops simultaneously, so it is * important to consider all paint attributes used in the draw calls in deciding both a) if an * op tries to merge at all, and b) if the op can merge with another set of ops * * False positives can lead to information from the paints of subsequent merged operations being * dropped, so we make simplifying qualifications on the ops that can merge, per op type. */ bool canMergeWith(BakedOpState* op) const { bool isTextBatch = getBatchId() == OpBatchType::Text || getBatchId() == OpBatchType::ColorText; // Overlapping other operations is only allowed for text without shadow. For other ops, // multiDraw isn't guaranteed to overdraw correctly if (!isTextBatch || PaintUtils::hasTextShadow(op->op->paint)) { if (intersects(op->computedState.clippedBounds)) return false; } const BakedOpState* lhs = op; const BakedOpState* rhs = mOps[0]; if (!MathUtils::areEqual(lhs->alpha, rhs->alpha)) return false; // Identical round rect clip state means both ops will clip in the same way, or not at all. // As the state objects are const, we can compare their pointers to determine mergeability if (lhs->roundRectClipState != rhs->roundRectClipState) return false; // Local masks prevent merge, since they're potentially in different coordinate spaces if (lhs->computedState.localProjectionPathMask || rhs->computedState.localProjectionPathMask) return false; /* Clipping compatibility check * * Exploits the fact that if a op or batch is clipped on a side, its bounds will equal its * clip for that side. */ const int currentFlags = mClipSideFlags; const int newFlags = op->computedState.clipSideFlags; if (currentFlags != OpClipSideFlags::None || newFlags != OpClipSideFlags::None) { const Rect& opBounds = op->computedState.clippedBounds; float boundsDelta = mBounds.left - opBounds.left; if (!checkSide(currentFlags, newFlags, OpClipSideFlags::Left, boundsDelta)) return false; boundsDelta = mBounds.top - opBounds.top; if (!checkSide(currentFlags, newFlags, OpClipSideFlags::Top, boundsDelta)) return false; // right and bottom delta calculation reversed to account for direction boundsDelta = opBounds.right - mBounds.right; if (!checkSide(currentFlags, newFlags, OpClipSideFlags::Right, boundsDelta)) return false; boundsDelta = opBounds.bottom - mBounds.bottom; if (!checkSide(currentFlags, newFlags, OpClipSideFlags::Bottom, boundsDelta)) return false; } const SkPaint* newPaint = op->op->paint; const SkPaint* oldPaint = mOps[0]->op->paint; if (newPaint == oldPaint) { // if paints are equal, then modifiers + paint attribs don't need to be compared return true; } else if (newPaint && !oldPaint) { return paintIsDefault(*newPaint); } else if (!newPaint && oldPaint) { return paintIsDefault(*oldPaint); } return paintsAreEquivalent(*newPaint, *oldPaint); }
Batch *readBatch(char *str, FILE *file) { int id = getBatchId(str); Batch *batch = createBatch(id); readMessages(batch, file); return batch; }