Implement visibility css prop

This commit is contained in:
Niklas von Hertzen 2017-08-03 20:28:39 +08:00
parent f278ba4f22
commit f2b8c16c2c
4 changed files with 123 additions and 83 deletions

View File

@ -48,8 +48,10 @@ export default class CanvasRenderer {
} }
renderNode(container: NodeContainer) { renderNode(container: NodeContainer) {
this.renderNodeBackgroundAndBorders(container); if (container.isVisible()) {
this.renderNodeContent(container); this.renderNodeBackgroundAndBorders(container);
this.renderNodeContent(container);
}
} }
renderNodeContent(container: NodeContainer) { renderNodeContent(container: NodeContainer) {
@ -242,69 +244,71 @@ export default class CanvasRenderer {
} }
renderStack(stack: StackingContext) { renderStack(stack: StackingContext) {
this.ctx.globalAlpha = stack.getOpacity(); if (stack.container.isVisible()) {
const transform = stack.container.style.transform; this.ctx.globalAlpha = stack.getOpacity();
if (transform !== null) { const transform = stack.container.style.transform;
this.ctx.save(); if (transform !== null) {
this.ctx.translate( this.ctx.save();
stack.container.bounds.left + transform.transformOrigin[0].value, this.ctx.translate(
stack.container.bounds.top + transform.transformOrigin[1].value stack.container.bounds.left + transform.transformOrigin[0].value,
); stack.container.bounds.top + transform.transformOrigin[1].value
this.ctx.transform( );
transform.transform[0], this.ctx.transform(
transform.transform[1], transform.transform[0],
transform.transform[2], transform.transform[1],
transform.transform[3], transform.transform[2],
transform.transform[4], transform.transform[3],
transform.transform[5] transform.transform[4],
); transform.transform[5]
this.ctx.translate( );
-(stack.container.bounds.left + transform.transformOrigin[0].value), this.ctx.translate(
-(stack.container.bounds.top + transform.transformOrigin[1].value) -(stack.container.bounds.left + transform.transformOrigin[0].value),
); -(stack.container.bounds.top + transform.transformOrigin[1].value)
} );
const [ }
negativeZIndex, const [
zeroOrAutoZIndexOrTransformedOrOpacity, negativeZIndex,
positiveZIndex, zeroOrAutoZIndexOrTransformedOrOpacity,
nonPositionedFloats, positiveZIndex,
nonPositionedInlineLevel nonPositionedFloats,
] = splitStackingContexts(stack); nonPositionedInlineLevel
const [inlineLevel, nonInlineLevel] = splitDescendants(stack); ] = splitStackingContexts(stack);
const [inlineLevel, nonInlineLevel] = splitDescendants(stack);
// https://www.w3.org/TR/css-position-3/#painting-order // https://www.w3.org/TR/css-position-3/#painting-order
// 1. the background and borders of the element forming the stacking context. // 1. the background and borders of the element forming the stacking context.
this.renderNodeBackgroundAndBorders(stack.container); this.renderNodeBackgroundAndBorders(stack.container);
// 2. the child stacking contexts with negative stack levels (most negative first). // 2. the child stacking contexts with negative stack levels (most negative first).
negativeZIndex.sort(sortByZIndex).forEach(this.renderStack, this); negativeZIndex.sort(sortByZIndex).forEach(this.renderStack, this);
// 3. For all its in-flow, non-positioned, block-level descendants in tree order: // 3. For all its in-flow, non-positioned, block-level descendants in tree order:
this.renderNodeContent(stack.container); this.renderNodeContent(stack.container);
nonInlineLevel.forEach(this.renderNode, this); nonInlineLevel.forEach(this.renderNode, this);
// 4. All non-positioned floating descendants, in tree order. For each one of these, // 4. All non-positioned floating descendants, in tree order. For each one of these,
// treat the element as if it created a new stacking context, but any positioned descendants and descendants // treat the element as if it created a new stacking context, but any positioned descendants and descendants
// which actually create a new stacking context should be considered part of the parent stacking context, // which actually create a new stacking context should be considered part of the parent stacking context,
// not this new one. // not this new one.
nonPositionedFloats.forEach(this.renderStack, this); nonPositionedFloats.forEach(this.renderStack, this);
// 5. the in-flow, inline-level, non-positioned descendants, including inline tables and inline blocks. // 5. the in-flow, inline-level, non-positioned descendants, including inline tables and inline blocks.
nonPositionedInlineLevel.forEach(this.renderStack, this); nonPositionedInlineLevel.forEach(this.renderStack, this);
inlineLevel.forEach(this.renderNode, this); inlineLevel.forEach(this.renderNode, this);
// 6. All positioned, opacity or transform descendants, in tree order that fall into the following categories: // 6. All positioned, opacity or transform descendants, in tree order that fall into the following categories:
// All positioned descendants with 'z-index: auto' or 'z-index: 0', in tree order. // All positioned descendants with 'z-index: auto' or 'z-index: 0', in tree order.
// For those with 'z-index: auto', treat the element as if it created a new stacking context, // For those with 'z-index: auto', treat the element as if it created a new stacking context,
// but any positioned descendants and descendants which actually create a new stacking context should be // but any positioned descendants and descendants which actually create a new stacking context should be
// considered part of the parent stacking context, not this new one. For those with 'z-index: 0', // considered part of the parent stacking context, not this new one. For those with 'z-index: 0',
// treat the stacking context generated atomically. // treat the stacking context generated atomically.
// //
// All opacity descendants with opacity less than 1 // All opacity descendants with opacity less than 1
// //
// All transform descendants with transform other than none // All transform descendants with transform other than none
zeroOrAutoZIndexOrTransformedOrOpacity.forEach(this.renderStack, this); zeroOrAutoZIndexOrTransformedOrOpacity.forEach(this.renderStack, this);
// 7. Stacking contexts formed by positioned descendants with z-indices greater than or equal to 1 in z-index // 7. Stacking contexts formed by positioned descendants with z-indices greater than or equal to 1 in z-index
// order (smallest first) then tree order. // order (smallest first) then tree order.
positiveZIndex.sort(sortByZIndex).forEach(this.renderStack, this); positiveZIndex.sort(sortByZIndex).forEach(this.renderStack, this);
if (transform !== null) { if (transform !== null) {
this.ctx.restore(); this.ctx.restore();
}
} }
} }

View File

@ -13,6 +13,7 @@ import type {Position} from './parsing/position';
import type {TextTransform} from './parsing/textTransform'; import type {TextTransform} from './parsing/textTransform';
import type {TextDecoration} from './parsing/textDecoration'; import type {TextDecoration} from './parsing/textDecoration';
import type {Transform} from './parsing/transform'; import type {Transform} from './parsing/transform';
import type {Visibility} from './parsing/visibility';
import type {zIndex} from './parsing/zIndex'; import type {zIndex} from './parsing/zIndex';
import type {Bounds, BoundCurves, Path} from './Bounds'; import type {Bounds, BoundCurves, Path} from './Bounds';
@ -36,6 +37,7 @@ import {parsePosition, POSITION} from './parsing/position';
import {parseTextDecoration} from './parsing/textDecoration'; import {parseTextDecoration} from './parsing/textDecoration';
import {parseTextTransform} from './parsing/textTransform'; import {parseTextTransform} from './parsing/textTransform';
import {parseTransform} from './parsing/transform'; import {parseTransform} from './parsing/transform';
import {parseVisibility, VISIBILITY} from './parsing/visibility';
import {parseZIndex} from './parsing/zIndex'; import {parseZIndex} from './parsing/zIndex';
import {parseBounds, parseBoundCurves, calculatePaddingBoxPath} from './Bounds'; import {parseBounds, parseBoundCurves, calculatePaddingBoxPath} from './Bounds';
@ -56,6 +58,7 @@ type StyleDeclaration = {
textDecoration: TextDecoration, textDecoration: TextDecoration,
textTransform: TextTransform, textTransform: TextTransform,
transform: Transform, transform: Transform,
visibility: Visibility,
zIndex: zIndex zIndex: zIndex
}; };
@ -90,6 +93,7 @@ export default class NodeContainer {
textDecoration: parseTextDecoration(style), textDecoration: parseTextDecoration(style),
textTransform: parseTextTransform(style.textTransform), textTransform: parseTextTransform(style.textTransform),
transform: parseTransform(style), transform: parseTransform(style),
visibility: parseVisibility(style.visibility),
zIndex: parseZIndex(style.zIndex) zIndex: parseZIndex(style.zIndex)
}; };
@ -127,7 +131,11 @@ export default class NodeContainer {
return this.isRootElement() && !this.isFloating() && !this.isAbsolutelyPositioned(); return this.isRootElement() && !this.isFloating() && !this.isAbsolutelyPositioned();
} }
isVisible(): boolean { isVisible(): boolean {
return !contains(this.style.display, DISPLAY.NONE) && this.style.opacity > 0; return (
!contains(this.style.display, DISPLAY.NONE) &&
this.style.opacity > 0 &&
this.style.visibility === VISIBILITY.VISIBLE
);
} }
isAbsolutelyPositioned(): boolean { isAbsolutelyPositioned(): boolean {
return this.style.position !== POSITION.STATIC && this.style.position !== POSITION.RELATIVE; return this.style.position !== POSITION.STATIC && this.style.position !== POSITION.RELATIVE;

22
src/parsing/visibility.js Normal file
View File

@ -0,0 +1,22 @@
/* @flow */
'use strict';
export const VISIBILITY = {
VISIBLE: 0,
HIDDEN: 1,
COLLAPSE: 2
};
export type Visibility = $Values<typeof VISIBILITY>;
export const parseVisibility = (visibility: string): Visibility => {
switch (visibility) {
case 'hidden':
return VISIBILITY.HIDDEN;
case 'collapse':
return VISIBILITY.COLLAPSE;
case 'visible':
default:
return VISIBILITY.VISIBLE;
}
};

View File

@ -1,24 +1,30 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<head> <head>
<title>Visible elements tests</title> <title>Visible elements tests</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<script type="text/javascript" src="../test.js"></script> <script type="text/javascript" src="../test.js"></script>
<style> <style>
div{ div{
border:2px solid black; border:2px solid black;
} }
</style> .none {
display:none
}
</style>
</head> </head>
<body> <body>
<h1>Display:none and visible:hidden tests</h1> <div>
<div>This should be visible </div> <h1>Display:none and visible:hidden tests</h1>
<div style="display:none">display:none, This should be <b>hidden</b></div> <div>This should be visible </div>
<div style="visibility:hidden">visibility:hidden, This should be <b>hidden</b></div> <div class="none">display:none, This should be <b>hidden</b></div>
<hr /> <div style="visibility:hidden">visibility:hidden, This should be <b>hidden</b></div>
<div style="display:none">display:none, This should be <b>hidden</b></div> <hr />
<div style="visibility:hidden">visibility:hidden, This should be <b>hidden</b></div> <div class="none">display:none, This should be <b>hidden</b></div>
<div style="visibility:hidden">visibility:hidden, This should be <b>hidden</b></div>
</div>
</body>
</body>
</html> </html>