// FIXME: Merge with the other drawTiled eventually, since we need a combination of both for some things. void Image::drawTiled(GraphicsContext* ctxt, const FloatRect& dstRect, const FloatRect& srcRect, TileRule hRule, TileRule vRule, CompositeOperator op) { if (mayFillWithSolidColor()) { fillWithSolidColor(ctxt, dstRect, solidColor(), op); return; } // FIXME: We do not support 'round' yet. For now just map it to 'repeat'. if (hRule == RoundTile) hRule = RepeatTile; if (vRule == RoundTile) vRule = RepeatTile; FloatSize scale = calculatePatternScale(dstRect, srcRect, hRule, vRule); AffineTransform patternTransform = AffineTransform().scale(scale.width(), scale.height()); // We want to construct the phase such that the pattern is centered (when stretch is not // set for a particular rule). float hPhase = scale.width() * srcRect.x(); float vPhase = scale.height() * srcRect.y(); if (hRule == Image::RepeatTile) hPhase -= fmodf(dstRect.width(), scale.width() * srcRect.width()) / 2.0f; if (vRule == Image::RepeatTile) vPhase -= fmodf(dstRect.height(), scale.height() * srcRect.height()) / 2.0f; FloatPoint patternPhase(dstRect.x() - hPhase, dstRect.y() - vPhase); drawPattern(ctxt, srcRect, patternTransform, patternPhase, op, dstRect); startAnimation(); }
// FIXME: Merge with the other drawTiled eventually, since we need a combination of both for some things. void Image::drawTiled(GraphicsContext* ctxt, const FloatRect& dstRect, const FloatRect& srcRect, const FloatSize& tileScaleFactor, TileRule hRule, TileRule vRule, ColorSpace styleColorSpace, CompositeOperator op) { if (mayFillWithSolidColor()) { fillWithSolidColor(ctxt, dstRect, solidColor(), styleColorSpace, op); return; } // FIXME: We do not support 'round' or 'space' yet. For now just map them to 'repeat'. if (hRule == RoundTile || hRule == SpaceTile) hRule = RepeatTile; if (vRule == RoundTile || vRule == SpaceTile) vRule = RepeatTile; AffineTransform patternTransform = AffineTransform().scaleNonUniform(tileScaleFactor.width(), tileScaleFactor.height()); // We want to construct the phase such that the pattern is centered (when stretch is not // set for a particular rule). float hPhase = tileScaleFactor.width() * srcRect.x(); float vPhase = tileScaleFactor.height() * srcRect.y(); float scaledTileWidth = tileScaleFactor.width() * srcRect.width(); float scaledTileHeight = tileScaleFactor.height() * srcRect.height(); if (hRule == Image::RepeatTile) hPhase -= (dstRect.width() - scaledTileWidth) / 2; if (vRule == Image::RepeatTile) vPhase -= (dstRect.height() - scaledTileHeight) / 2; FloatPoint patternPhase(dstRect.x() - hPhase, dstRect.y() - vPhase); drawPattern(ctxt, srcRect, patternTransform, patternPhase, styleColorSpace, op, dstRect); startAnimation(); }
// FIXME: Merge with the other drawTiled eventually, since we need a combination of both for some things. void Image::drawTiled(GraphicsContext* ctxt, const FloatRect& dstRect, const FloatRect& srcRect, const FloatSize& providedTileScaleFactor, TileRule hRule, TileRule vRule, CompositeOperator op) { if (mayFillWithSolidColor()) { fillWithSolidColor(ctxt, dstRect, solidColor(), op); return; } // FIXME: We do not support 'space' yet. For now just map it to 'repeat'. if (hRule == SpaceTile) hRule = RepeatTile; if (vRule == SpaceTile) vRule = RepeatTile; // FIXME: if this code is used for background-repeat: round (in addition to // border-image-repeat), then add logic to deal with the background-size: auto // special case. The aspect ratio should be maintained in this case. FloatSize tileScaleFactor = providedTileScaleFactor; bool useLowInterpolationQuality = false; if (hRule == RoundTile) { float hRepetitions = std::max(1.0f, roundf(dstRect.width() / (tileScaleFactor.width() * srcRect.width()))); tileScaleFactor.setWidth(dstRect.width() / (srcRect.width() * hRepetitions)); } if (vRule == RoundTile) { float vRepetitions = std::max(1.0f, roundf(dstRect.height() / (tileScaleFactor.height() * srcRect.height()))); tileScaleFactor.setHeight(dstRect.height() / (srcRect.height() * vRepetitions)); } if (hRule == RoundTile || vRule == RoundTile) { // High interpolation quality rounds the scaled tile to an integer size (see Image::drawPattern). // To avoid causing a visual problem, linear interpolation must be used instead. // FIXME: Allow using high-quality interpolation in this case, too. useLowInterpolationQuality = true; } // We want to construct the phase such that the pattern is centered (when stretch is not // set for a particular rule). float hPhase = tileScaleFactor.width() * srcRect.x(); float vPhase = tileScaleFactor.height() * srcRect.y(); float scaledTileWidth = tileScaleFactor.width() * srcRect.width(); float scaledTileHeight = tileScaleFactor.height() * srcRect.height(); if (hRule == Image::RepeatTile) hPhase -= (dstRect.width() - scaledTileWidth) / 2; if (vRule == Image::RepeatTile) vPhase -= (dstRect.height() - scaledTileHeight) / 2; FloatPoint patternPhase(dstRect.x() - hPhase, dstRect.y() - vPhase); if (useLowInterpolationQuality) { InterpolationQuality previousInterpolationQuality = ctxt->imageInterpolationQuality(); ctxt->setImageInterpolationQuality(InterpolationLow); drawPattern(ctxt, srcRect, tileScaleFactor, patternPhase, op, dstRect); ctxt->setImageInterpolationQuality(previousInterpolationQuality); } else { drawPattern(ctxt, srcRect, tileScaleFactor, patternPhase, op, dstRect); } startAnimation(); }
// FIXME: Merge with the other drawTiled eventually, since we need a combination of both for some things. void Image::drawTiled(GraphicsContext& ctxt, const FloatRect& dstRect, const FloatRect& srcRect, const FloatSize& tileScaleFactor, TileRule hRule, TileRule vRule, CompositeOperator op) { if (mayFillWithSolidColor()) { fillWithSolidColor(ctxt, dstRect, solidColor(), op); return; } FloatSize tileScale = tileScaleFactor; FloatSize spacing; // FIXME: These rules follow CSS border-image rules, but they should not be down here in Image. bool centerOnGapHorizonally = false; bool centerOnGapVertically = false; switch (hRule) { case RoundTile: { int numItems = std::max<int>(floorf(dstRect.width() / srcRect.width()), 1); tileScale.setWidth(dstRect.width() / (srcRect.width() * numItems)); break; } case SpaceTile: { int numItems = floorf(dstRect.width() / srcRect.width()); if (!numItems) return; spacing.setWidth((dstRect.width() - srcRect.width() * numItems) / (numItems + 1)); tileScale.setWidth(1); centerOnGapHorizonally = !(numItems & 1); break; } case StretchTile: case RepeatTile: break; } switch (vRule) { case RoundTile: { int numItems = std::max<int>(floorf(dstRect.height() / srcRect.height()), 1); tileScale.setHeight(dstRect.height() / (srcRect.height() * numItems)); break; } case SpaceTile: { int numItems = floorf(dstRect.height() / srcRect.height()); if (!numItems) return; spacing.setHeight((dstRect.height() - srcRect.height() * numItems) / (numItems + 1)); tileScale.setHeight(1); centerOnGapVertically = !(numItems & 1); break; } case StretchTile: case RepeatTile: break; } AffineTransform patternTransform = AffineTransform().scaleNonUniform(tileScale.width(), tileScale.height()); // We want to construct the phase such that the pattern is centered (when stretch is not // set for a particular rule). float hPhase = tileScale.width() * srcRect.x(); float vPhase = tileScale.height() * srcRect.y(); float scaledTileWidth = tileScale.width() * srcRect.width(); float scaledTileHeight = tileScale.height() * srcRect.height(); if (centerOnGapHorizonally) hPhase -= spacing.width(); else if (hRule == Image::RepeatTile || hRule == Image::SpaceTile) hPhase -= (dstRect.width() - scaledTileWidth) / 2; if (centerOnGapVertically) vPhase -= spacing.height(); else if (vRule == Image::RepeatTile || vRule == Image::SpaceTile) vPhase -= (dstRect.height() - scaledTileHeight) / 2; FloatPoint patternPhase(dstRect.x() - hPhase, dstRect.y() - vPhase); drawPattern(ctxt, srcRect, patternTransform, patternPhase, spacing, op, dstRect); #if PLATFORM(IOS) startAnimation(DoNotCatchUp); #else startAnimation(); #endif }
// TODO(cavalcantii): see crbug.com/662504. void Image::drawTiled(GraphicsContext& ctxt, const FloatRect& dstRect, const FloatRect& srcRect, const FloatSize& providedTileScaleFactor, TileRule hRule, TileRule vRule, SkBlendMode op) { // TODO(cavalcantii): see crbug.com/662513. FloatSize tileScaleFactor = providedTileScaleFactor; if (vRule == RoundTile) { float vRepetitions = std::max(1.0f, roundf(dstRect.height() / (tileScaleFactor.height() * srcRect.height()))); tileScaleFactor.setHeight(dstRect.height() / (srcRect.height() * vRepetitions)); } if (hRule == RoundTile) { float hRepetitions = std::max( 1.0f, roundf(dstRect.width() / (tileScaleFactor.width() * srcRect.width()))); tileScaleFactor.setWidth(dstRect.width() / (srcRect.width() * hRepetitions)); } // We want to construct the phase such that the pattern is centered (when // stretch is not set for a particular rule). float vPhase = tileScaleFactor.height() * srcRect.y(); float hPhase = tileScaleFactor.width() * srcRect.x(); if (vRule == Image::RepeatTile) { float scaledTileHeight = tileScaleFactor.height() * srcRect.height(); vPhase -= (dstRect.height() - scaledTileHeight) / 2; } if (hRule == Image::RepeatTile) { float scaledTileWidth = tileScaleFactor.width() * srcRect.width(); hPhase -= (dstRect.width() - scaledTileWidth) / 2; } FloatSize spacing; auto calculateSpaceNeeded = []( const float destination, const float source) -> std::tuple<bool, float> { DCHECK_GT(source, 0); DCHECK_GT(destination, 0); float repeatTilesCount = floorf(destination / source); if (!repeatTilesCount) return std::make_tuple(false, -1); float space = destination; space -= source * repeatTilesCount; space /= repeatTilesCount + 1.0; return std::make_tuple(true, space); }; if (vRule == SpaceTile) { std::tuple<bool, float> space = calculateSpaceNeeded(dstRect.height(), srcRect.height()); if (!std::get<0>(space)) return; spacing.setHeight(std::get<1>(space)); tileScaleFactor.setHeight(1.0); vPhase = srcRect.y(); vPhase -= spacing.height(); } if (hRule == SpaceTile) { std::tuple<bool, float> space = calculateSpaceNeeded(dstRect.width(), srcRect.width()); if (!std::get<0>(space)) return; spacing.setWidth(std::get<1>(space)); tileScaleFactor.setWidth(1.0); hPhase = srcRect.x(); hPhase -= spacing.width(); } FloatPoint patternPhase(dstRect.x() - hPhase, dstRect.y() - vPhase); // TODO(cavalcantii): see crbug.com/662507. if ((hRule == RoundTile || vRule == RoundTile)) { InterpolationQuality previousInterpolationQuality = ctxt.imageInterpolationQuality(); ctxt.setImageInterpolationQuality(InterpolationLow); drawPattern(ctxt, srcRect, tileScaleFactor, patternPhase, op, dstRect); ctxt.setImageInterpolationQuality(previousInterpolationQuality); } else { drawPattern(ctxt, srcRect, tileScaleFactor, patternPhase, op, dstRect, spacing); } startAnimation(); }