Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions php-transformer/src/HtmlToBlocks/Style/EngineSupportCss.php
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,13 @@ public function beforeAuthorCss(string $serializedBlocks, string $layoutShellBlo
if ( str_contains($serializedBlocks, SourceBlockAttributeProjector::SYNTHETIC_IMAGE_FIGURE_CLASS) ) {
$parts[] = '.' . SourceBlockAttributeProjector::SYNTHETIC_IMAGE_FIGURE_CLASS . '{margin:0}';
}
if ( str_contains($serializedBlocks, SourceBlockAttributeProjector::SYNTHETIC_FILL_IMAGE_FIGURE_CLASS) ) {
// The source image fills both axes of its parent. Its core/image
// figure is an extra box; give that box the source's full inline
// extent so the image's percentage width does not size from an
// aspect-ratio-constrained, shrink-to-fit figure instead.
$parts[] = ':root :where(figure.' . SourceBlockAttributeProjector::SYNTHETIC_FILL_IMAGE_FIGURE_CLASS . '){width:100%}';
}
if ( str_contains($serializedBlocks, '<video') ) {
$parts[] = 'video{max-width:100%}';
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ final class SourceBlockAttributeProjector
public const SYNTHETIC_ANCHOR_BLOCK_DISPLAY_CLASS = 'blocks-engine-synthetic-anchor-block-display';
public const SYNTHETIC_IMAGE_FIGURE_CLASS = 'blocks-engine-synthetic-image-figure';
public const SYNTHETIC_INLINE_IMAGE_FIGURE_CLASS = 'blocks-engine-synthetic-image-figure-inline';
public const SYNTHETIC_FILL_IMAGE_FIGURE_CLASS = 'blocks-engine-synthetic-image-figure-fill';
public const SYNTHETIC_EMBED_FIGURE_CLASS = 'blocks-engine-synthetic-embed-figure';
public const CSS_OWNED_INLINE_FLOW_CLASS = 'blocks-engine-css-owned-inline-flow';
public const CSS_OWNED_LAYOUT_ITEM_CLASS = 'blocks-engine-css-owned-layout-item';
Expand Down Expand Up @@ -52,6 +53,8 @@ public function project(
// so the alignment has nothing left to move.
if ( $facts->syntheticImageFigureFollowsInlineFlow ) {
$attrs['className'] = SourceDom::mergeClassNames((string) ($attrs['className'] ?? ''), self::SYNTHETIC_INLINE_IMAGE_FIGURE_CLASS);
} elseif ( $this->sourceImageFillsParent($sourceElement) ) {
$attrs['className'] = SourceDom::mergeClassNames((string) ($attrs['className'] ?? ''), self::SYNTHETIC_FILL_IMAGE_FIGURE_CLASS);
}
}
if ( 'core/paragraph' === $name && $facts->isInlineSourceElement ) {
Expand Down Expand Up @@ -119,6 +122,21 @@ public function project(
return ( new EditorListViewContainerNamer() )->apply($name, $attrs, $sourceElement);
}

private function sourceImageFillsParent(DOMElement $image): bool
{
if ( 'img' !== strtolower($image->tagName) ) {
return false;
}
$shape = $this->styleResolver->imageShapeDeclarations($image);
foreach ( array( 'width', 'height' ) as $axis ) {
$value = $this->styleResolver->resolveCssVariablesInValue((string) ($shape[$axis]['value'] ?? ''), $image);
if ( '100%' !== CssValueInspector::comparable($value) ) {
return false;
}
}
return true;
}

private static function isHiddenAccessibilitySupportElement(DOMElement $element): bool
{
$identity = strtolower(SourceDom::attr($element, 'id') . ' ' . SourceDom::attr($element, 'class'));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@
{
"path": "serialized_blocks",
"assert": "contains",
"value": "<figure class=\"wp-block-image is-resized fill top-crop be-inline-geometry-0920923a5c6cf48a blocks-engine-synthetic-image-figure\"><img src=\"https://example.com/offsite.jpg\""
"value": "<figure class=\"wp-block-image is-resized fill top-crop be-inline-geometry-0920923a5c6cf48a blocks-engine-synthetic-image-figure blocks-engine-synthetic-image-figure-fill\"><img src=\"https://example.com/offsite.jpg\""
},
{
"path": "assets.0.content",
Expand Down
39 changes: 39 additions & 0 deletions php-transformer/tests/unit/section-background-object-fit.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
require dirname(__DIR__, 2) . '/vendor/autoload.php';

use Automattic\BlocksEngine\PhpTransformer\HtmlToBlocks\HtmlTransformer;
use Automattic\BlocksEngine\PhpTransformer\HtmlToBlocks\Style\SourceBlockAttributeProjector;

$out = ( new HtmlTransformer() )->transform(
'<style>.section-background img{object-fit:cover;width:100%;height:100%}</style>'
Expand All @@ -17,4 +18,42 @@
exit(1);
}

$transform = static function (string $html): array {
$result = ( new HtmlTransformer() )->transform($html)->toArray();
$css = implode("\n", array_map(
static fn (array $asset): string => 'css' === ($asset['kind'] ?? '') ? (string) ($asset['content'] ?? '') : '',
$result['assets'] ?? array()
));
return array( (string) ($result['serialized_blocks'] ?? ''), $css );
};
$fillClass = SourceBlockAttributeProjector::SYNTHETIC_FILL_IMAGE_FIGURE_CLASS;
$fillRule = ':root :where(figure.' . $fillClass . '){width:100%}';

// A source image explicitly fills both axes of its parent. The aspect ratio
// belongs to the image, while the extra core/image figure needs the parent's
// full inline extent rather than an intrinsic/shrink-to-fit width.
list( $fillMarkup, $fillCss ) = $transform(
'<style>.media-frame{height:562px}.media-frame img{width:100%;height:100%;aspect-ratio:1440/562;object-fit:cover}</style>'
. '<main><div class="media-frame"><img src="landscape.jpg" alt="Landscape" width="1440" height="562"></div></main>'
);
if ( ! preg_match('/<figure[^>]*\b' . preg_quote($fillClass, '/') . '\b[^>]*><img[^>]*style="[^"]*width:100%;height:100%/', $fillMarkup)
|| ! str_contains($fillMarkup, '"aspectRatio":"1440/562"')
|| ! str_contains($fillCss, $fillRule)
) {
fwrite(STDERR, "FAIL: source-owned fill image needs a full-width synthetic figure without altering native image height\n" . $fillMarkup . "\n" . $fillCss . "\n");
exit(1);
}

foreach ( array(
'<style>.media-frame img{width:100%;object-fit:cover}</style><main><div class="media-frame"><img src="wide.jpg" alt="Wide"></div></main>',
'<style>.media-frame img{width:100%;height:100%;object-fit:cover}</style><main><figure class="media-frame"><img src="authored.jpg" alt="Authored"></figure></main>',
'<main><div><img src="ordinary.jpg" alt="Ordinary" width="800" height="400"></div></main>',
) as $source ) {
list( $otherMarkup, $otherCss ) = $transform($source);
if ( str_contains($otherMarkup, $fillClass) || str_contains($otherCss, $fillRule) ) {
fwrite(STDERR, "FAIL: full-width figure sizing must require a synthetic figure and source-owned two-axis fill\n" . $otherMarkup . "\n" . $otherCss . "\n");
exit(1);
}
}

fwrite(STDOUT, "section background object-fit tests: passed\n");
Loading