Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: style fail after resize #916

Merged
merged 18 commits into from
Dec 9, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
40 changes: 40 additions & 0 deletions integration_tests/specs/css/css-flexbox/align-items.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1130,6 +1130,46 @@ describe('align-items', () => {
await snapshot();
});

it('does not work with stretch when align-self of flex item changed from auto to flex-start', async (done) => {
let flexbox;
let flexitem;

flexbox = createElement(
'div',
{
style: {
display: 'flex',
'background-color': '#aaa',
position: 'relative',
flexDirection: 'column',
width: '200px',
height: '120px',
'box-sizing': 'border-box',
},
},
[
(flexitem = createElement('div', {
style: {
'height': '50px',
'background-color': 'lightblue',
'box-sizing': 'border-box',
// 'align-self': 'flex-start',
},
})),
]
);

BODY.appendChild(flexbox);

await snapshot();

requestAnimationFrame(async () => {
flexitem.style.alignSelf = 'flex-start';
await snapshot();
done();
});
});

it('should works with img with no size set', async () => {
const container = createElement(
'div',
Expand Down
29 changes: 29 additions & 0 deletions integration_tests/specs/dom/elements/img.ts
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,35 @@ describe('Tags img', () => {
img.src = imageURL;
});

it('width property change should work when width of style is not set', async (done) => {
let img = createElement('img', {
src: 'assets/300x150-green.png',
width: 100,
height: 100,
});
BODY.appendChild(img);

requestAnimationFrame(async () => {
img.width = 200;
await snapshot(0.1);
done();
});
});

it('width property should not work when width of style is auto', async () => {
let img = createElement('img', {
src: 'assets/300x150-green.png',
width: 100,
height: 100,
style: {
width: 'auto'
}
});
BODY.appendChild(img);

await snapshot(0.1);
});

it('can get natualSize from repeat image url', async (done) => {
const flutterContainer = document.createElement('div');
flutterContainer.style.height = '100vh';
Expand Down
1 change: 1 addition & 0 deletions kraken/lib/rendering.dart
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,4 @@ export 'src/rendering/opacity.dart';
export 'src/rendering/transform.dart';
export 'src/rendering/viewport.dart';
export 'src/rendering/paragraph.dart';
export 'src/rendering/image.dart';
6 changes: 4 additions & 2 deletions kraken/lib/src/css/display.dart
Original file line number Diff line number Diff line change
Expand Up @@ -86,10 +86,12 @@ mixin CSSDisplayMixin on RenderStyle {
parentRenderStyle.flexDirection == FlexDirection.columnReverse;
// Flex item will not stretch in stretch alignment when flex wrap is set to wrap or wrap-reverse
bool isFlexNoWrap = parentRenderStyle.flexWrap == FlexWrap.nowrap;
bool isAlignItemsStretch = parentRenderStyle.effectiveAlignItems == AlignItems.stretch;
bool isStretchSelf = alignSelf != AlignSelf.auto
? alignSelf == AlignSelf.stretch
: parentRenderStyle.effectiveAlignItems == AlignItems.stretch;

// Display as block if flex vertical layout children and stretch children
if (!marginLeft.isAuto && !marginRight.isAuto && isVerticalDirection && isFlexNoWrap && isAlignItemsStretch) {
if (!marginLeft.isAuto && !marginRight.isAuto && isVerticalDirection && isFlexNoWrap && isStretchSelf) {
transformedDisplay = CSSDisplay.block;
}
}
Expand Down
6 changes: 0 additions & 6 deletions kraken/lib/src/dom/elements/body.dart
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,6 @@ class BodyElement extends Element {
BodyElement(int targetId, Pointer<NativeEventTarget> nativePtr, ElementManager elementManager)
: super( targetId, nativePtr, elementManager, defaultStyle: _defaultStyle);

@override
void willAttachRenderer() {
super.willAttachRenderer();
renderBoxModel!.renderStyle.width = CSSLengthValue(elementManager.viewportWidth, CSSLengthType.PX);
}

@override
void addEvent(String eventType) {
// Scroll event not working on body.
Expand Down
105 changes: 43 additions & 62 deletions kraken/lib/src/dom/elements/img.dart
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ import 'package:kraken/painting.dart';
import 'package:kraken/rendering.dart';

const String IMAGE = 'IMG';
const String NATURAL_WIDTH = 'naturalWidth';
const String NATURAL_HEIGHT = 'naturalHeight';

// FIXME: should be inline default.
const Map<String, dynamic> _defaultStyle = {
Expand All @@ -25,7 +27,7 @@ const Map<String, dynamic> _defaultStyle = {
// The HTMLImageElement.
class ImageElement extends Element {
// The render box to draw image.
RenderImage? _renderImage;
KrakenRenderImage? _renderImage;

ImageProvider? _cachedImageProvider;
dynamic _imageProviderKey;
Expand All @@ -34,9 +36,14 @@ class ImageElement extends Element {
ImageInfo? _cachedImageInfo;
Uri? _resolvedUri;

// Width and height set through property.
double? _propertyWidth;
double? _propertyHeight;

// Width and height set through style.
double? _styleWidth;
double? _styleHeight;

ui.Image? get image => _cachedImageInfo?.image;

/// Number of image frame, used to identify multi frame image after loaded.
Expand Down Expand Up @@ -133,29 +140,33 @@ class ImageElement extends Element {
}

double get width {
if (_renderImage != null && _renderImage!.width != null) {
return _renderImage!.width!;
}
double? width = _styleWidth ?? _propertyWidth;

if (width == null) {
width = naturalWidth;
double? height = _styleHeight ?? _propertyHeight;

if (renderBoxModel != null && renderBoxModel!.hasSize) {
return renderBoxModel!.clientWidth;
if (height != null && naturalHeight != 0) {
width = height * naturalWidth / naturalHeight;
}
}

// Fallback to natural width, if image is not on screen.
return naturalWidth;
return width;
}

double get height {
if (_renderImage != null && _renderImage!.height != null) {
return _renderImage!.height!;
}
double? height = _styleHeight ?? _propertyHeight;

if (renderBoxModel != null && renderBoxModel!.hasSize) {
return renderBoxModel!.clientHeight;
if (height == null) {
height = naturalHeight;
double? width = _styleWidth ?? _propertyWidth;

if (width != null && naturalWidth != 0) {
height = width * naturalHeight / naturalWidth;
}
}

// Fallback to natural height, if image is not on screen.
return naturalHeight;
return height;
}

double get naturalWidth {
Expand Down Expand Up @@ -223,38 +234,15 @@ class ImageElement extends Element {
void _resizeImage() {
assert(isRendererAttached);

double? width = renderStyle.width.isAuto ? _propertyWidth : renderStyle.width.computedValue;
double? height = renderStyle.height.isAuto ? _propertyHeight : renderStyle.height.computedValue;

if (renderStyle.width.isAuto && _propertyWidth != null) {
if (_styleWidth == null && _propertyWidth != null) {
// The intrinsic width of the image in pixels. Must be an integer without a unit.
renderStyle.width = CSSLengthValue(_propertyWidth, CSSLengthType.PX);
}
if (renderStyle.height.isAuto && _propertyHeight != null) {
if (_styleHeight == null && _propertyHeight != null) {
// The intrinsic height of the image, in pixels. Must be an integer without a unit.
renderStyle.height = CSSLengthValue(_propertyHeight, CSSLengthType.PX);
}

if (width == null && height == null) {
width = naturalWidth;
height = naturalHeight;
} else if (width != null && height == null && naturalWidth != 0) {
height = width * naturalHeight / naturalWidth;
} else if (width == null && height != null && naturalHeight != 0) {
width = height * naturalWidth / naturalHeight;
}

if (height == null || !height.isFinite) {
height = 0.0;
}

if (width == null || !width.isFinite) {
width = 0.0;
}

// Try to update image size if image already resolved.
_renderImage?.width = width;
_renderImage?.height = height;
renderStyle.intrinsicWidth = naturalWidth;
renderStyle.intrinsicHeight = naturalHeight;

Expand All @@ -265,12 +253,12 @@ class ImageElement extends Element {
}
}

RenderImage _createRenderImageBox() {
KrakenRenderImage _createRenderImageBox() {
RenderStyle renderStyle = renderBoxModel!.renderStyle;
BoxFit objectFit = renderStyle.objectFit;
Alignment objectPosition = renderStyle.objectPosition;

return RenderImage(
return KrakenRenderImage(
image: _cachedImageInfo?.image,
fit: objectFit,
alignment: objectPosition,
Expand Down Expand Up @@ -338,19 +326,8 @@ class ImageElement extends Element {
if (resolvedUri == null) return;

// Try to make sure that this image can be encoded into a smaller size.
double? width = null;
double? height = null;

if (isRendererAttached) {
width = renderStyle.width.isAuto ? _propertyWidth : renderStyle.width.computedValue;
height = renderStyle.height.isAuto ? _propertyHeight : renderStyle.height.computedValue;
} else {
width = _propertyWidth;
height = _propertyHeight;
}

int? cachedWidth = (width != null && width > 0) ? (width * ui.window.devicePixelRatio).toInt() : null;
int? cachedHeight = (height != null && height > 0) ? (height * ui.window.devicePixelRatio).toInt() : null;
int? cachedWidth = width > 0 ? (width * ui.window.devicePixelRatio).toInt() : null;
int? cachedHeight = height > 0 ? (height * ui.window.devicePixelRatio).toInt() : null;

ImageProvider? provider = _cachedImageProvider;
if (updateImageProvider || provider == null) {
Expand Down Expand Up @@ -465,22 +442,26 @@ class ImageElement extends Element {
dynamic getProperty(String key) {
switch (key) {
case WIDTH:
return _renderImage?.width ?? 0;
return width;
case HEIGHT:
return _renderImage?.height ?? 0;
case 'naturalWidth':
return height;
case NATURAL_WIDTH:
return naturalWidth;
case 'naturalHeight':
case NATURAL_HEIGHT:
return naturalHeight;
}

return super.getProperty(key);
}

void _stylePropertyChanged(String property, String? original, String present) {
if (property == WIDTH || property == HEIGHT) {
// Resize renderBox
if (isRendererAttached) _resizeImage();
if (property == WIDTH) {
_styleWidth = renderStyle.width.value == null && renderStyle.width.isNotAuto
? null : renderStyle.width.computedValue;
} else if (property == HEIGHT) {
_styleHeight = renderStyle.height.value == null && renderStyle.height.isNotAuto
? null : renderStyle.height.computedValue;
}
// Resize image
_resolveImage(_resolvedUri, updateImageProvider: true);
} else if (property == OBJECT_FIT && _renderImage != null) {
Expand Down
26 changes: 26 additions & 0 deletions kraken/lib/src/rendering/image.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/*
* Copyright (C) 2019-present Alibaba Inc. All rights reserved.
* Author: Kraken Team.
*/
import 'dart:ui' as ui show Image;
import 'package:flutter/rendering.dart';

class KrakenRenderImage extends RenderImage {
KrakenRenderImage({
ui.Image? image,
BoxFit? fit,
AlignmentGeometry alignment = Alignment.center,
}) : super(
image: image,
fit: fit,
alignment: alignment,
);

@override
void performLayout() {
Size trySize = constraints.biggest;
size = trySize.isInfinite ? constraints.smallest : trySize;
}
}