|
@@ -0,0 +1,2742 @@
|
|
|
|
+{
|
|
|
|
+ *****************************************************************************
|
|
|
|
+ This file is part of Fresnel.
|
|
|
|
+
|
|
|
|
+ See the file COPYING.modifiedLGPL.txt, included in this distribution,
|
|
|
|
+ for details about the license.
|
|
|
|
+ *****************************************************************************
|
|
|
|
+
|
|
|
|
+ToDo:
|
|
|
|
+- speed up GetCSSIndex
|
|
|
|
+- speed up GetCSSDepth
|
|
|
|
+- speed up GetCSSNextOfType
|
|
|
|
+- speed up GetCSSPreviousOfType
|
|
|
|
+- invalid CSS values must be skipped, so validity check must be done during css resolver
|
|
|
|
+ e.g. negative border-left-width is ignored
|
|
|
|
+-
|
|
|
|
+}
|
|
|
|
+unit FresnelDOM;
|
|
|
|
+
|
|
|
|
+{$mode ObjFPC}{$H+}
|
|
|
|
+{$WARN 6060 off} // Case statement does not handle all possible cases
|
|
|
|
+
|
|
|
|
+interface
|
|
|
|
+
|
|
|
|
+uses
|
|
|
|
+ Classes, SysUtils, Math, sortbase, LazLoggerBase, fpCSSResolver,
|
|
|
|
+ fpCSSTree, fpCSSParser, FPImage;
|
|
|
|
+
|
|
|
|
+type
|
|
|
|
+ TFresnelLength = double;
|
|
|
|
+ TFresnelPoint = record
|
|
|
|
+ X, Y: TFresnelLength;
|
|
|
|
+ end;
|
|
|
|
+ TFresnelRect = record
|
|
|
|
+ Left, Top, Right, Bottom: TFresnelLength;
|
|
|
|
+ end;
|
|
|
|
+
|
|
|
|
+ EFresnelFont = class(Exception)
|
|
|
|
+ end;
|
|
|
|
+
|
|
|
|
+const
|
|
|
|
+ MaxFresnelLength = TFresnelLength(high(longint));
|
|
|
|
+ FresnelDefaultDPI = 96;
|
|
|
|
+
|
|
|
|
+type
|
|
|
|
+ // CSS attributes of the TFresnelElement class
|
|
|
|
+ TFresnelCSSAttribute = (
|
|
|
|
+ fcaDisplay,
|
|
|
|
+ fcaDisplayBox,
|
|
|
|
+ fcaDisplayInside,
|
|
|
|
+ fcaDisplayOutside,
|
|
|
|
+ fcaPosition,
|
|
|
|
+ fcaOverflow, // x y
|
|
|
|
+ fcaOverflowX, // visible|hidden|clip|scroll|auto
|
|
|
|
+ fcaOverflowY,
|
|
|
|
+ fcaZIndex,
|
|
|
|
+ fcaClear,
|
|
|
|
+ fcaDirection,
|
|
|
|
+ fcaLeft,
|
|
|
|
+ fcaTop,
|
|
|
|
+ fcaRight,
|
|
|
|
+ fcaBottom,
|
|
|
|
+ fcaWidth,
|
|
|
|
+ fcaHeight,
|
|
|
|
+ fcaBorder, // shorthand
|
|
|
|
+ fcaBorderLeft, // shorthand
|
|
|
|
+ fcaBorderRight, // shorthand
|
|
|
|
+ fcaBorderTop, // shorthand
|
|
|
|
+ fcaBorderBottom, // shorthand
|
|
|
|
+ fcaBorderWidth, // shorthand
|
|
|
|
+ fcaBorderLeftWidth,
|
|
|
|
+ fcaBorderRightWidth,
|
|
|
|
+ fcaBorderTopWidth,
|
|
|
|
+ fcaBorderBottomWidth,
|
|
|
|
+ fcaBorderColor,
|
|
|
|
+ fcaBoxSizing,
|
|
|
|
+ fcaFloat,
|
|
|
|
+ fcaFont, // shorthand
|
|
|
|
+ fcaFontFamily,
|
|
|
|
+ fcaFontFeatureSettings,
|
|
|
|
+ fcaFontKerning, // auto|normal|none
|
|
|
|
+ fcaFontSize, // medium|xx-small|x-small|small|large|x-large|xx-large|smaller|larger|LengthUnit|%
|
|
|
|
+ fcaFontStyle, // normal|italic|oblique
|
|
|
|
+ fcaFontWeight, // normal|bold|bolder|lighter|number
|
|
|
|
+ fcaFontVariant,
|
|
|
|
+ fcaLineHeight,
|
|
|
|
+ fcaMargin, // shorthand
|
|
|
|
+ fcaMarginLeft,
|
|
|
|
+ fcaMarginTop,
|
|
|
|
+ fcaMarginRight,
|
|
|
|
+ fcaMarginBottom,
|
|
|
|
+ fcaMarginBlock, // shorthand
|
|
|
|
+ fcaMarginBlockEnd,
|
|
|
|
+ fcaMarginBlockStart,
|
|
|
|
+ fcaMarginInline,
|
|
|
|
+ fcaMarginInlineEnd,
|
|
|
|
+ fcaMarginInlineStart,
|
|
|
|
+ fcaMinWidth,
|
|
|
|
+ fcaMaxWidth,
|
|
|
|
+ fcaMinHeight,
|
|
|
|
+ fcaMaxHeight,
|
|
|
|
+ fcaOpacity,
|
|
|
|
+ fcaPadding, // shorthand
|
|
|
|
+ fcaPaddingLeft,
|
|
|
|
+ fcaPaddingTop,
|
|
|
|
+ fcaPaddingRight,
|
|
|
|
+ fcaPaddingBottom,
|
|
|
|
+ fcaVisibility,
|
|
|
|
+ fcaBackgroundColor
|
|
|
|
+ );
|
|
|
|
+ TFresnelCSSAttributes = set of TFresnelCSSAttribute;
|
|
|
|
+
|
|
|
|
+const
|
|
|
|
+ FresnelCSSAttributeNames: array[TFresnelCSSAttribute] of string = (
|
|
|
|
+ // case sensitive!
|
|
|
|
+ 'display',
|
|
|
|
+ 'display-box',
|
|
|
|
+ 'display-inside',
|
|
|
|
+ 'display-outside',
|
|
|
|
+ 'position',
|
|
|
|
+ 'overflow',
|
|
|
|
+ 'overflow-x',
|
|
|
|
+ 'overflow-y',
|
|
|
|
+ 'z-index',
|
|
|
|
+ 'clear',
|
|
|
|
+ 'direction',
|
|
|
|
+ 'left',
|
|
|
|
+ 'top',
|
|
|
|
+ 'right',
|
|
|
|
+ 'bottom',
|
|
|
|
+ 'width',
|
|
|
|
+ 'height',
|
|
|
|
+ 'border',
|
|
|
|
+ 'border-left',
|
|
|
|
+ 'border-right',
|
|
|
|
+ 'border-top',
|
|
|
|
+ 'border-bottom',
|
|
|
|
+ 'border-width',
|
|
|
|
+ 'border-left-width',
|
|
|
|
+ 'border-right-width',
|
|
|
|
+ 'border-top-width',
|
|
|
|
+ 'border-bottom-width',
|
|
|
|
+ 'border-color',
|
|
|
|
+ 'box-sizing',
|
|
|
|
+ 'float',
|
|
|
|
+ 'font',
|
|
|
|
+ 'font-family',
|
|
|
|
+ 'font-feature-settings',
|
|
|
|
+ 'font-kerning',
|
|
|
|
+ 'font-size',
|
|
|
|
+ 'font-style',
|
|
|
|
+ 'font-weight',
|
|
|
|
+ 'font-variant',
|
|
|
|
+ 'line-height',
|
|
|
|
+ 'margin',
|
|
|
|
+ 'margin-left',
|
|
|
|
+ 'margin-top',
|
|
|
|
+ 'margin-right',
|
|
|
|
+ 'margin-bottom',
|
|
|
|
+ 'margin-block',
|
|
|
|
+ 'margin-block-end',
|
|
|
|
+ 'margin-block-start',
|
|
|
|
+ 'margin-inline',
|
|
|
|
+ 'margin-inline-end',
|
|
|
|
+ 'margin-inline-start',
|
|
|
|
+ 'min-width',
|
|
|
|
+ 'max-width',
|
|
|
|
+ 'min-height',
|
|
|
|
+ 'max-height',
|
|
|
|
+ 'opacity',
|
|
|
|
+ 'padding',
|
|
|
|
+ 'padding-left',
|
|
|
|
+ 'padding-top',
|
|
|
|
+ 'padding-right',
|
|
|
|
+ 'padding-bottom',
|
|
|
|
+ 'visibility',
|
|
|
|
+ 'background-color'
|
|
|
|
+ );
|
|
|
|
+
|
|
|
|
+type
|
|
|
|
+ TFresnelCSSUnit = (
|
|
|
|
+ fcuPercent,
|
|
|
|
+ fcu_cm, // centimeters
|
|
|
|
+ fcu_mm, // milimeters
|
|
|
|
+ fcu_ch, // relative to the width of the "0" (zero)
|
|
|
|
+ fcu_em, // relative to the font-size of the element
|
|
|
|
+ fcu_ex, // relative to the x-height of the current font
|
|
|
|
+ fcu_in, // inches
|
|
|
|
+ fcu_px, // pixels
|
|
|
|
+ fcu_pt, // points (1pt = 1/72 of 1in)
|
|
|
|
+ fcu_pc, // picas (1pc = 12 pt)
|
|
|
|
+ fcu_rem,// relative to font-size of the root element
|
|
|
|
+ fcu_vw, // relative to 1% of the width of the viewport
|
|
|
|
+ fcu_vh, // relative to 1% of the height of the viewport
|
|
|
|
+ fcu_vmax,// relative to 1% of viewport's larger dimension
|
|
|
|
+ fcu_vmin // relative to 1% of viewport's smaller dimension
|
|
|
|
+ );
|
|
|
|
+ TFresnelCSSUnits = set of TFresnelCSSUnit;
|
|
|
|
+
|
|
|
|
+type
|
|
|
|
+ TFresnelCSSPseudo = (
|
|
|
|
+ fcpaLang
|
|
|
|
+ );
|
|
|
|
+ TFresnelCSSPseudoAttributes = set of TFresnelCSSPseudo;
|
|
|
|
+
|
|
|
|
+const
|
|
|
|
+ FresnelCSSPseudoNames: array[TFresnelCSSPseudo] of string = (
|
|
|
|
+ ':visible'
|
|
|
|
+ );
|
|
|
|
+
|
|
|
|
+type
|
|
|
|
+ TFresnelViewport = class;
|
|
|
|
+ TFresnelElement = class;
|
|
|
|
+
|
|
|
|
+ { TFresnelLayoutNode }
|
|
|
|
+
|
|
|
|
+ TFresnelLayoutNode = class(TComponent)
|
|
|
|
+ private
|
|
|
|
+ FElement: TFresnelElement;
|
|
|
|
+ FParent: TFresnelLayoutNode;
|
|
|
|
+ FNodes: TFPList; // list of TFresnelLayoutNode
|
|
|
|
+ function GetNodeCount: integer;
|
|
|
|
+ function GetNodes(Index: integer): TFresnelLayoutNode;
|
|
|
|
+ procedure SetElement(const AValue: TFresnelElement);
|
|
|
|
+ procedure SetParent(const AValue: TFresnelLayoutNode);
|
|
|
|
+ public
|
|
|
|
+ constructor Create(AOwner: TComponent); override;
|
|
|
|
+ destructor Destroy; override;
|
|
|
|
+ function GetRoot: TFresnelLayoutNode;
|
|
|
|
+ procedure SortNodes(const Compare: TListSortComparer_Context; Context: Pointer); virtual;
|
|
|
|
+ property Parent: TFresnelLayoutNode read FParent write SetParent;
|
|
|
|
+ property Element: TFresnelElement read FElement write SetElement;
|
|
|
|
+ property NodeCount: integer read GetNodeCount;
|
|
|
|
+ property Nodes[Index: integer]: TFresnelLayoutNode read GetNodes;
|
|
|
|
+ end;
|
|
|
|
+ TFresnelLayoutElDataClass = class of TFresnelLayoutNode;
|
|
|
|
+
|
|
|
|
+ { TFresnelLayouter }
|
|
|
|
+
|
|
|
|
+ TFresnelLayouter = class(TComponent)
|
|
|
|
+ public
|
|
|
|
+ procedure ComputeCSS(El: TFresnelElement); virtual; abstract;
|
|
|
|
+ procedure ComputedChildrenCSS(El: TFresnelElement); virtual; abstract;
|
|
|
|
+ end;
|
|
|
|
+ TFresnelLayouterClass = class of TFresnelLayouter;
|
|
|
|
+
|
|
|
|
+ IFresnelFont = interface
|
|
|
|
+ ['{6B53C662-5598-419B-996B-7E839271B64E}']
|
|
|
|
+ function GetFamily: string;
|
|
|
|
+ function GetKerning: string;
|
|
|
|
+ function GetSize: string;
|
|
|
|
+ function GetStyle: string;
|
|
|
|
+ function GetVariant: string;
|
|
|
|
+ function GetWeight: string;
|
|
|
|
+ function TextSize(const aText: string): TFresnelPoint;
|
|
|
|
+ function TextSizeMaxWidth(const aText: string; MaxWidth: TFresnelLength): TFresnelPoint;
|
|
|
|
+ function GetTool: TObject;
|
|
|
|
+ end;
|
|
|
|
+
|
|
|
|
+ TFresnelFontDesc = record
|
|
|
|
+ Family: string;
|
|
|
|
+ Kerning: string;
|
|
|
|
+ Size: string;
|
|
|
|
+ Style: string;
|
|
|
|
+ Variant_: string;
|
|
|
|
+ Weight: string;
|
|
|
|
+ end;
|
|
|
|
+ PFresnelFontDesc = ^TFresnelFontDesc;
|
|
|
|
+
|
|
|
|
+ TFresnelLengthCheck = (
|
|
|
|
+ flcNoNegative,
|
|
|
|
+ flcNoPercentage,
|
|
|
|
+ flcInteger
|
|
|
|
+ );
|
|
|
|
+ TFresnelLengthChecks = set of TFresnelLengthCheck;
|
|
|
|
+
|
|
|
|
+ { TFresnelElement }
|
|
|
|
+
|
|
|
|
+ TFresnelElement = class(TComponent, ICSSNode)
|
|
|
|
+ private
|
|
|
|
+ function GetCSSPseudo(Pseudo: TFresnelCSSPseudo): string;
|
|
|
|
+ function GetNodeCount: integer;
|
|
|
|
+ function GetNodes(Index: integer): TFresnelElement;
|
|
|
|
+ function GetCSSElAttribute(Attr: TFresnelCSSAttribute): string;
|
|
|
|
+ function GetCSSElComputedAttribute(Attr: TFresnelCSSAttribute): string;
|
|
|
|
+ procedure SetCSSElComputedAttribute(Attr: TFresnelCSSAttribute; AValue: string);
|
|
|
|
+ private
|
|
|
|
+ FDOMIndex: integer;
|
|
|
|
+ FFont: IFresnelFont;
|
|
|
|
+ FLayoutNode: TFresnelLayoutNode;
|
|
|
|
+ FFontDesc: TFresnelFontDesc;
|
|
|
|
+ FFontDescValid: boolean;
|
|
|
|
+ class var
|
|
|
|
+ // Stuff for registering CSS numerical IDs
|
|
|
|
+ FCSSNumericalIDs: array[TCSSNumericalIDKind] of TCSSNumericalIDs;
|
|
|
|
+ FCSSIDToName: array[TCSSNumericalIDKind] of TCSSStringDynArray;
|
|
|
|
+ FCSSIDToNameCount: array[TCSSNumericalIDKind] of integer;
|
|
|
|
+ FFresnelElementTypeID: TCSSNumericalID;
|
|
|
|
+ FFresnelElementBaseAttrID: TCSSNumericalID;
|
|
|
|
+ FFresnelElementBasePseudoID: TCSSNumericalID;
|
|
|
|
+ protected
|
|
|
|
+ FCSSAttributes: array[TFresnelCSSAttribute] of string;
|
|
|
|
+ FCSSClasses: TStrings;
|
|
|
|
+ FCSSComputed: array[TFresnelCSSAttribute] of string;
|
|
|
|
+ FChildren: TFPList; // list of TFresnelElement
|
|
|
|
+ FParent: TFresnelElement;
|
|
|
|
+ FStyle: string;
|
|
|
|
+ FStyleElements: TCSSElement;
|
|
|
|
+ FCSSPosElement: TCSSElement;
|
|
|
|
+ procedure SetCSSElAttribute(Attr: TFresnelCSSAttribute; const AValue: string); virtual;
|
|
|
|
+ function CheckCSSClear(const AValue: string): boolean; virtual;
|
|
|
|
+ function CheckOrSetCSSDisplay(const AValue: string; Check: boolean): boolean; virtual;
|
|
|
|
+ function CheckCSSDisplayBox(const AValue: string): boolean; virtual;
|
|
|
|
+ function CheckCSSDisplayInside(const AValue: string): boolean; virtual;
|
|
|
|
+ function CheckCSSDisplayOutside(const AValue: string): boolean; virtual;
|
|
|
|
+ function CheckCSSPosition(const AValue: string): boolean; virtual;
|
|
|
|
+ function CheckOrSetCSSOverflow(const AValue: string; Check: boolean): boolean; virtual;
|
|
|
|
+ function CheckCSSOverflowX(const AValue: string): boolean; virtual;
|
|
|
|
+ function CheckCSSOverflowY(const AValue: string): boolean; virtual;
|
|
|
|
+ function CheckCSSZIndex(const AValue: string): boolean; virtual;
|
|
|
|
+ function CheckCSSDirection(const AValue: string): boolean; virtual;
|
|
|
|
+ function CheckOrSetCSSBorder(const AValue: string; Check: boolean): boolean; virtual;
|
|
|
|
+ function CheckOrSetCSSBorderLeft(const AValue: string; Check: boolean): boolean; virtual;
|
|
|
|
+ function CheckOrSetCSSBorderTop(const AValue: string; Check: boolean): boolean; virtual;
|
|
|
|
+ function CheckOrSetCSSBorderRight(const AValue: string; Check: boolean): boolean; virtual;
|
|
|
|
+ function CheckOrSetCSSBorderBottom(const AValue: string; Check: boolean): boolean; virtual;
|
|
|
|
+ function CheckOrSetCSSBorderWidth(const AValue: string; Check: boolean): boolean; virtual;
|
|
|
|
+ function CheckCSSBorderXWidth(Attr: TFresnelCSSAttribute; const AValue: string): boolean; virtual;
|
|
|
|
+ function CheckCSSBorderColor(const AValue: string): boolean; virtual;
|
|
|
|
+ function CheckCSSBoxSizing(const AValue: string): boolean; virtual;
|
|
|
|
+ function CheckCSSFloat(const AValue: string): boolean; virtual;
|
|
|
|
+ function CheckCSSLineHeight(const AValue: string): boolean; virtual;
|
|
|
|
+ function CheckOrSetCSSMargin(const AValue: string; Check: boolean): boolean; virtual;
|
|
|
|
+ function CheckOrSetCSSMarginBlock(const AValue: string; Check: boolean): boolean; virtual;
|
|
|
|
+ function CheckOrSetCSSMarginInline(const AValue: string; Check: boolean): boolean; virtual;
|
|
|
|
+ function CheckCSSMinMaxWidthHeight(Attr: TFresnelCSSAttribute; const AValue: string): boolean; virtual;
|
|
|
|
+ function CheckCSSOpacity(const AValue: string): boolean; virtual;
|
|
|
|
+ function CheckOrSetCSSFont(const AValue: string; Check: boolean): boolean; virtual;
|
|
|
|
+ function CheckCSSFontKerning(const AValue: string): boolean; virtual;
|
|
|
|
+ function CheckCSSFontSize(const AValue: string): boolean; virtual;
|
|
|
|
+ function CheckCSSFontStyle(const AValue: string): boolean; virtual;
|
|
|
|
+ function CheckCSSFontWeight(const AValue: string): boolean; virtual;
|
|
|
|
+ function CheckCSSFontVariant(const AValue: string): boolean; virtual;
|
|
|
|
+ function CheckOrSetCSSPadding(const AValue: string; Check: boolean): boolean; virtual;
|
|
|
|
+ function CheckCSSVisibility(const AValue: string): boolean; virtual;
|
|
|
|
+ function CheckCSSBackgroundColor(const AValue: string): boolean; virtual;
|
|
|
|
+ function GetComputedCSSValue(AttrID: TCSSNumericalID): TCSSString;
|
|
|
|
+ procedure SetComputedCSSValue(AttrID: TCSSNumericalID; const Value: TCSSString);
|
|
|
|
+ procedure SetCSSClasses(const AValue: TStrings);
|
|
|
|
+ procedure SetParent(const AValue: TFresnelElement);
|
|
|
|
+ procedure SetStyle(const AValue: string);
|
|
|
|
+ procedure SetStyleElements(const AValue: TCSSElement);
|
|
|
|
+ class constructor InitFresnelElementClass;
|
|
|
|
+ class destructor FinalFresnelElementClass;
|
|
|
|
+ class function RegisterCSSType(const aName: string): TCSSNumericalID;
|
|
|
|
+ class function RegisterCSSAttr(const aName: string): TCSSNumericalID;
|
|
|
|
+ class function RegisterCSSPseudo(const aName: string): TCSSNumericalID;
|
|
|
|
+ procedure InitCSSResolver(aResolver: TCSSResolver); virtual;
|
|
|
|
+ procedure Notification(AComponent: TComponent; Operation: TOperation);
|
|
|
|
+ override;
|
|
|
|
+ function CSSReadNextValue(const aValue: string; var p: integer): string;
|
|
|
|
+ function CheckCSSLength(Attr: TFresnelCSSAttribute; const AValue: string; const Checks: TFresnelLengthChecks = []): boolean; virtual;
|
|
|
|
+ procedure ComputeCSSAttribute(Attr: TFresnelCSSAttribute); virtual;
|
|
|
|
+ function GetDPI(IsHorizontal: boolean): TFresnelLength; virtual;
|
|
|
|
+ function GetViewport: TFresnelViewport; virtual;
|
|
|
|
+ function ElementAttrToAttrId(Attr: TFresnelCSSAttribute): TCSSNumericalID;
|
|
|
|
+ function GetFont: IFresnelFont; virtual;
|
|
|
|
+ protected
|
|
|
|
+ procedure GetChildren(Proc: TGetChildProc; Root: TComponent); override;
|
|
|
|
+ procedure SetParentComponent(Value: TComponent); override;
|
|
|
|
+ public
|
|
|
|
+ constructor Create(AOwner: TComponent); override;
|
|
|
|
+ destructor Destroy; override;
|
|
|
|
+ procedure Clear;
|
|
|
|
+ function GetParentComponent: TComponent; override;
|
|
|
|
+ function HasParent: Boolean; override;
|
|
|
|
+ function GetRoot: TFresnelElement;
|
|
|
|
+ function GetPath: string; virtual;
|
|
|
|
+ property Parent: TFresnelElement read FParent write SetParent;
|
|
|
|
+ property NodeCount: integer read GetNodeCount;
|
|
|
|
+ property Nodes[Index: integer]: TFresnelElement read GetNodes; default;
|
|
|
|
+ // CSS
|
|
|
|
+ class function CSSTypeID: TCSSNumericalID; virtual;
|
|
|
|
+ class function CSSTypeName: TCSSString; virtual;
|
|
|
|
+ procedure ClearCSSValues; virtual;
|
|
|
|
+ function GetCSSAttribute(const AttrID: TCSSNumericalID): TCSSString; virtual;
|
|
|
|
+ function GetCSSAttributeClass: TCSSString; virtual;
|
|
|
|
+ function GetCSSChild(const anIndex: integer): ICSSNode; virtual;
|
|
|
|
+ function GetCSSChildCount: integer; virtual;
|
|
|
|
+ function GetCSSDepth: integer; virtual;
|
|
|
|
+ function GetCSSEmpty: boolean; virtual;
|
|
|
|
+ function GetCSSID: TCSSString; virtual;
|
|
|
|
+ function GetCSSIndex: integer; virtual;
|
|
|
|
+ function GetCSSNextOfType: ICSSNode; virtual;
|
|
|
|
+ function GetCSSNextSibling: ICSSNode; virtual;
|
|
|
|
+ function GetCSSParent: ICSSNode; virtual;
|
|
|
|
+ function GetCSSPreviousOfType: ICSSNode; virtual;
|
|
|
|
+ function GetCSSPreviousSibling: ICSSNode; virtual;
|
|
|
|
+ function GetCSSPseudo(const AttrID: TCSSNumericalID): TCSSString; virtual;
|
|
|
|
+ function GetCSSTypeID: TCSSNumericalID; virtual;
|
|
|
|
+ function GetCSSTypeName: TCSSString; virtual;
|
|
|
|
+ function HasCSSAttribute(const AttrID: TCSSNumericalID): boolean; virtual;
|
|
|
|
+ function HasCSSClass(const aClassName: TCSSString): boolean; virtual;
|
|
|
|
+ function HasCSSPseudo(const AttrID: TCSSNumericalID): boolean; virtual;
|
|
|
|
+ procedure SetCSSValue(AttrID: TCSSNumericalID; Value: TCSSElement); virtual;
|
|
|
|
+ function CheckCSSValue(AttrID: TCSSNumericalID; Value: TCSSElement
|
|
|
|
+ ): boolean; virtual;
|
|
|
|
+ function GetCSSInitialAttribute(const AttrID: TCSSNumericalID): TCSSString; virtual;
|
|
|
|
+ function GetCSSInheritAttribute(const AttrID: TCSSNumericalID): TCSSString; virtual;
|
|
|
|
+ procedure ComputeCSS; virtual;
|
|
|
|
+ procedure CSSWarning(const ID: int64; Msg: string); virtual;
|
|
|
|
+ procedure CSSInvalidValueWarning(const ID: int64; Attr: TFresnelCSSAttribute; const aValue: string); virtual;
|
|
|
|
+ // CSS classes and inline style
|
|
|
|
+ property StyleElements: TCSSElement read FStyleElements write SetStyleElements;
|
|
|
|
+ // CSS attributes
|
|
|
|
+ function GetComputedCSSLength(Attr: TFresnelCSSAttribute; UseInherited: boolean; UseNaNOnFail: boolean = false): TFresnelLength; virtual; // on fail returns NaN
|
|
|
|
+ function GetComputedCSString(Attr: TFresnelCSSAttribute; UseInherited: boolean): string; virtual;
|
|
|
|
+ procedure WriteComputedAttributes(Title: string);
|
|
|
|
+ property CSSAttribute[Attr: TFresnelCSSAttribute]: string read GetCSSElAttribute write SetCSSElAttribute;
|
|
|
|
+ property CSSComputedAttribute[Attr: TFresnelCSSAttribute]: string read GetCSSElComputedAttribute write SetCSSElComputedAttribute;
|
|
|
|
+ property CSSPseudo[Pseudo: TFresnelCSSPseudo]: string read GetCSSPseudo;
|
|
|
|
+ class property FresnelElementBaseAttrID: TCSSNumericalID read FFresnelElementBaseAttrID;
|
|
|
|
+ class property FresnelElementBasePseudoID: TCSSNumericalID read FFresnelElementBasePseudoID;
|
|
|
|
+ // layouter
|
|
|
|
+ function GetMaxWidthIntrinsicContentBox: TFresnelLength; virtual; // this element, excluding children, ignoring min-width
|
|
|
|
+ function GetMaxWidthContentBox: TFresnelLength; virtual; // this element, excluding children
|
|
|
|
+ function GetMaxWidthBorderBox: TFresnelLength; virtual; // this element, excluding children
|
|
|
|
+ function GetMinWidthIntrinsicContentBox: TFresnelLength; virtual; // this element, excluding children, ignoring min-width
|
|
|
|
+ function GetMinWidthContentBox: TFresnelLength; virtual; // this element, excluding children
|
|
|
|
+ function GetMinWidthBorderBox: TFresnelLength; virtual; // this element, excluding children
|
|
|
|
+ function GetPreferredContentBox_MaxWidth(MaxWidth: TFresnelLength): TFresnelPoint; virtual; // this element, excluding children
|
|
|
|
+ function GetPreferredBorderBox_MaxWidth(MaxWidth: TFresnelLength): TFresnelPoint; virtual; // this element, excluding children
|
|
|
|
+ property DOMIndex: integer read FDOMIndex write FDOMIndex;
|
|
|
|
+ property LayoutNode: TFresnelLayoutNode read FLayoutNode write FLayoutNode;
|
|
|
|
+ // font
|
|
|
|
+ property Font: IFresnelFont read GetFont write FFont;
|
|
|
|
+ published
|
|
|
|
+ property CSSClasses: TStrings read FCSSClasses write SetCSSClasses;
|
|
|
|
+ property Style: string read FStyle write SetStyle;
|
|
|
|
+ end;
|
|
|
|
+ TFresnelElementClass = class of TFresnelElement;
|
|
|
|
+ TFresnelElementArray = array of TFresnelElement;
|
|
|
|
+
|
|
|
|
+ TFresnelViewportLength = (
|
|
|
|
+ vlFontMinSize,
|
|
|
|
+ vlDPIHorizontal,
|
|
|
|
+ vlDPIVertical,
|
|
|
|
+ vlHorizontalScrollbarWidth,
|
|
|
|
+ vlVerticalScrollbarWidth
|
|
|
|
+ );
|
|
|
|
+ TFresnelViewportLengths = set of TFresnelViewportLength;
|
|
|
|
+
|
|
|
|
+ { TFresnelFontEngine }
|
|
|
|
+
|
|
|
|
+ TFresnelFontEngine = class(TComponent)
|
|
|
|
+ public
|
|
|
|
+ function Allocate(const Desc: TFresnelFontDesc): IFresnelFont; virtual; abstract;
|
|
|
|
+ end;
|
|
|
|
+
|
|
|
|
+ { TFresnelViewport }
|
|
|
|
+
|
|
|
|
+ TFresnelViewport = class(TFresnelElement,IFPObserver)
|
|
|
|
+ private
|
|
|
|
+ FCSSResolver: TCSSResolver;
|
|
|
|
+ FFontEngine: TFresnelFontEngine;
|
|
|
|
+ FLayouter: TFresnelLayouter;
|
|
|
|
+ FStylesheetElements: TCSSElement;
|
|
|
|
+ FStylesheet: TStrings;
|
|
|
|
+ FDPI: array[boolean] of TFresnelLength;
|
|
|
|
+ FFontMinSize: TFresnelLength;
|
|
|
|
+ FScrollbarWidth: array[boolean] of TFresnelLength;
|
|
|
|
+ FHeight: TFresnelLength;
|
|
|
|
+ FWidth: TFresnelLength;
|
|
|
|
+ FMaxPreferredWidth: TFresnelLength;
|
|
|
|
+ function GetHeight: TFresnelLength;
|
|
|
|
+ function GetMaxPreferredWidth: TFresnelLength;
|
|
|
|
+ function GetScrollbarWidth(IsHorizontal: boolean): TFresnelLength;
|
|
|
|
+ function GetVPLength(l: TFresnelViewportLength): TFresnelLength;
|
|
|
|
+ function GetWidth: TFresnelLength;
|
|
|
|
+ procedure SetFontMinSize(const AValue: TFresnelLength);
|
|
|
|
+ procedure SetHeight(AValue: TFresnelLength);
|
|
|
|
+ procedure SetMaxPreferredWidth(const AValue: TFresnelLength);
|
|
|
|
+ procedure SetScrollbarWidth(IsHorizontal: boolean;
|
|
|
|
+ const AValue: TFresnelLength);
|
|
|
|
+ procedure SetStylesheet(AValue: TStrings);
|
|
|
|
+ procedure SetVPLength(l: TFresnelViewportLength;
|
|
|
|
+ const AValue: TFresnelLength);
|
|
|
|
+ procedure SetWidth(AValue: TFresnelLength);
|
|
|
|
+ protected
|
|
|
|
+ function GetDPI(IsHorizontal: boolean): TFresnelLength; override;
|
|
|
|
+ procedure SetDPI(IsHorizontal: boolean; const AValue: TFresnelLength);
|
|
|
|
+ procedure SetCSSElAttribute(Attr: TFresnelCSSAttribute; const AValue: string
|
|
|
|
+ ); override;
|
|
|
|
+ procedure StylesheetChanged; virtual;
|
|
|
|
+ procedure UpdateStylesheetElements; virtual;
|
|
|
|
+ procedure FPOObservedChanged(ASender: TObject; {%H-}Operation: TFPObservedOperation; {%H-}Data: Pointer); virtual;
|
|
|
|
+ procedure InitCSSResolver(aResolver: TCSSResolver); override;
|
|
|
|
+ procedure Notification(AComponent: TComponent; Operation: TOperation);
|
|
|
|
+ override;
|
|
|
|
+ public
|
|
|
|
+ constructor Create(AOwner: TComponent); override;
|
|
|
|
+ destructor Destroy; override;
|
|
|
|
+ procedure ApplyCSS; virtual;
|
|
|
|
+ procedure ClearCSSValues; override;
|
|
|
|
+ function AllocateFont(const Desc: TFresnelFontDesc): IFresnelFont; virtual;
|
|
|
|
+ property DPI[IsHorizontal: boolean]: TFresnelLength read GetDPI write SetDPI;
|
|
|
|
+ property FontMinSize: TFresnelLength read FFontMinSize write SetFontMinSize;
|
|
|
|
+ property ScrollbarWidth[IsHorizontal: boolean]: TFresnelLength read GetScrollbarWidth write SetScrollbarWidth;
|
|
|
|
+ property VPLength[l: TFresnelViewportLength]: TFresnelLength read GetVPLength write SetVPLength;
|
|
|
|
+ property CSSResolver: TCSSResolver read FCSSResolver;
|
|
|
|
+ property Stylesheet: TStrings read FStylesheet write SetStylesheet;
|
|
|
|
+ property StylesheetElements: TCSSElement read FStylesheetElements;
|
|
|
|
+ property Width: TFresnelLength read GetWidth write SetWidth;
|
|
|
|
+ property Height: TFresnelLength read GetHeight write SetHeight;
|
|
|
|
+ property MaxPreferredWidth: TFresnelLength read GetMaxPreferredWidth write SetMaxPreferredWidth;
|
|
|
|
+ property Layouter: TFresnelLayouter read FLayouter write FLayouter;
|
|
|
|
+ property FontEngine: TFresnelFontEngine read FFontEngine write FFontEngine;
|
|
|
|
+ end;
|
|
|
|
+
|
|
|
|
+const
|
|
|
|
+ FresnelCSSFormatSettings: TFormatSettings = (
|
|
|
|
+ CurrencyFormat: 1;
|
|
|
|
+ NegCurrFormat: 5;
|
|
|
|
+ ThousandSeparator: ',';
|
|
|
|
+ DecimalSeparator: '.';
|
|
|
|
+ CurrencyDecimals: 2;
|
|
|
|
+ DateSeparator: '-';
|
|
|
|
+ TimeSeparator: ':';
|
|
|
|
+ ListSeparator: ',';
|
|
|
|
+ CurrencyString: '$';
|
|
|
|
+ ShortDateFormat: 'd/m/y';
|
|
|
|
+ LongDateFormat: 'dd" "mmmm" "yyyy';
|
|
|
|
+ TimeAMString: 'AM';
|
|
|
|
+ TimePMString: 'PM';
|
|
|
|
+ ShortTimeFormat: 'hh:nn';
|
|
|
|
+ LongTimeFormat: 'hh:nn:ss';
|
|
|
|
+ ShortMonthNames: ('Jan','Feb','Mar','Apr','May','Jun',
|
|
|
|
+ 'Jul','Aug','Sep','Oct','Nov','Dec');
|
|
|
|
+ LongMonthNames: ('January','February','March','April','May','June',
|
|
|
|
+ 'July','August','September','October','November','December');
|
|
|
|
+ ShortDayNames: ('Sun','Mon','Tue','Wed','Thu','Fri','Sat');
|
|
|
|
+ LongDayNames: ('Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday');
|
|
|
|
+ TwoDigitYearCenturyWindow: 50;
|
|
|
|
+ );
|
|
|
|
+
|
|
|
|
+function FloatToCSSStr(const f: TFresnelLength): string;
|
|
|
|
+function CSSStrToFloat(const s: string; out l: TFresnelLength): boolean;
|
|
|
|
+
|
|
|
|
+implementation
|
|
|
|
+
|
|
|
|
+function FloatToCSSStr(const f: TFresnelLength): string;
|
|
|
|
+begin
|
|
|
|
+ Result:=FloatToStr(f,FresnelCSSFormatSettings);
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function CSSStrToFloat(const s: string; out l: TFresnelLength): boolean;
|
|
|
|
+var
|
|
|
|
+ Code: Integer;
|
|
|
|
+begin
|
|
|
|
+ Code:=0;
|
|
|
|
+ l:=0;
|
|
|
|
+ val(s,l,Code);
|
|
|
|
+ if Code<>0 then exit(false);
|
|
|
|
+ if IsNan(l) or (l>MaxFresnelLength) or (l<-MaxFresnelLength) then
|
|
|
|
+ Result:=false
|
|
|
|
+ else
|
|
|
|
+ Result:=true;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+{ TFresnelLayoutNode }
|
|
|
|
+
|
|
|
|
+procedure TFresnelLayoutNode.SetElement(const AValue: TFresnelElement);
|
|
|
|
+begin
|
|
|
|
+ if FElement=AValue then Exit;
|
|
|
|
+ if FElement<>nil then
|
|
|
|
+ FElement.FLayoutNode:=nil;
|
|
|
|
+ FElement:=AValue;
|
|
|
|
+ if FElement<>nil then
|
|
|
|
+ FElement.FLayoutNode:=Self;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TFresnelLayoutNode.GetNodeCount: integer;
|
|
|
|
+begin
|
|
|
|
+ if FNodes<>nil then
|
|
|
|
+ Result:=FNodes.Count
|
|
|
|
+ else
|
|
|
|
+ Result:=0;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TFresnelLayoutNode.GetNodes(Index: integer): TFresnelLayoutNode;
|
|
|
|
+begin
|
|
|
|
+ Result:=TFresnelLayoutNode(FNodes[Index]);
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+procedure TFresnelLayoutNode.SetParent(const AValue: TFresnelLayoutNode);
|
|
|
|
+begin
|
|
|
|
+ if FParent=AValue then Exit;
|
|
|
|
+ if FParent<>nil then
|
|
|
|
+ begin
|
|
|
|
+ if FParent.FNodes<>nil then
|
|
|
|
+ FParent.FNodes.Remove(Self);
|
|
|
|
+ end;
|
|
|
|
+ FParent:=AValue;
|
|
|
|
+ if FParent<>nil then
|
|
|
|
+ begin
|
|
|
|
+ if FParent.FNodes=nil then
|
|
|
|
+ FParent.FNodes:=TFPList.Create;
|
|
|
|
+ FParent.FNodes.Add(Self);
|
|
|
|
+ end;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+constructor TFresnelLayoutNode.Create(AOwner: TComponent);
|
|
|
|
+begin
|
|
|
|
+ inherited Create(AOwner);
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+destructor TFresnelLayoutNode.Destroy;
|
|
|
|
+var
|
|
|
|
+ i: Integer;
|
|
|
|
+begin
|
|
|
|
+ for i:=NodeCount-1 downto 0 do
|
|
|
|
+ Nodes[i].FParent:=nil;
|
|
|
|
+ FreeAndNil(FNodes);
|
|
|
|
+ Parent:=nil;
|
|
|
|
+ inherited Destroy;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TFresnelLayoutNode.GetRoot: TFresnelLayoutNode;
|
|
|
|
+begin
|
|
|
|
+ Result:=Self;
|
|
|
|
+ while Result.Parent<>nil do
|
|
|
|
+ Result:=Result.Parent;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+procedure TFresnelLayoutNode.SortNodes(
|
|
|
|
+ const Compare: TListSortComparer_Context; Context: Pointer);
|
|
|
|
+begin
|
|
|
|
+ FNodes.Sort(Compare,Context,SortBase.DefaultSortingAlgorithm);
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+{ TFresnelViewport }
|
|
|
|
+
|
|
|
|
+function TFresnelViewport.GetDPI(IsHorizontal: boolean): TFresnelLength;
|
|
|
|
+begin
|
|
|
|
+ Result:=FDPI[IsHorizontal];
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TFresnelViewport.GetScrollbarWidth(IsHorizontal: boolean
|
|
|
|
+ ): TFresnelLength;
|
|
|
|
+begin
|
|
|
|
+ Result:=FScrollbarWidth[IsHorizontal];
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TFresnelViewport.GetHeight: TFresnelLength;
|
|
|
|
+begin
|
|
|
|
+ Result:=FHeight;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TFresnelViewport.GetMaxPreferredWidth: TFresnelLength;
|
|
|
|
+begin
|
|
|
|
+ Result:=FMaxPreferredWidth;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TFresnelViewport.GetVPLength(l: TFresnelViewportLength
|
|
|
|
+ ): TFresnelLength;
|
|
|
|
+begin
|
|
|
|
+ Result:=0;
|
|
|
|
+ case l of
|
|
|
|
+ vlFontMinSize: Result:=FFontMinSize;
|
|
|
|
+ vlDPIHorizontal: Result:=FDPI[true];
|
|
|
|
+ vlDPIVertical: Result:=FDPI[false];
|
|
|
|
+ vlHorizontalScrollbarWidth: Result:=FScrollbarWidth[true];
|
|
|
|
+ vlVerticalScrollbarWidth: Result:=FScrollbarWidth[false];
|
|
|
|
+ end;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TFresnelViewport.GetWidth: TFresnelLength;
|
|
|
|
+begin
|
|
|
|
+ Result:=FWidth;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+procedure TFresnelViewport.SetDPI(IsHorizontal: boolean;
|
|
|
|
+ const AValue: TFresnelLength);
|
|
|
|
+begin
|
|
|
|
+ if FDPI[IsHorizontal]=AValue then exit;
|
|
|
|
+ FDPI[IsHorizontal]:=AValue;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+procedure TFresnelViewport.SetCSSElAttribute(Attr: TFresnelCSSAttribute;
|
|
|
|
+ const AValue: string);
|
|
|
|
+begin
|
|
|
|
+ // css cannot alter any viewport attributes
|
|
|
|
+ if Attr=fcaDisplay then ;
|
|
|
|
+ if AValue='' then ;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+procedure TFresnelViewport.StylesheetChanged;
|
|
|
|
+begin
|
|
|
|
+ // ToDo: call async
|
|
|
|
+ UpdateStylesheetElements;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+procedure TFresnelViewport.UpdateStylesheetElements;
|
|
|
|
+var
|
|
|
|
+ ss: TStringStream;
|
|
|
|
+ aParser: TCSSParser;
|
|
|
|
+begin
|
|
|
|
+ if FStylesheetElements<>nil then exit;
|
|
|
|
+ aParser:=nil;
|
|
|
|
+ ss:=TStringStream.Create(Stylesheet.Text);
|
|
|
|
+ try
|
|
|
|
+ aParser:=TCSSParser.Create(ss);
|
|
|
|
+ FStylesheetElements:=aParser.Parse;
|
|
|
|
+ finally
|
|
|
|
+ aParser.Free;
|
|
|
|
+ end;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+procedure TFresnelViewport.FPOObservedChanged(ASender: TObject;
|
|
|
|
+ Operation: TFPObservedOperation; Data: Pointer);
|
|
|
|
+begin
|
|
|
|
+ if ASender=FStylesheet then
|
|
|
|
+ StylesheetChanged;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+procedure TFresnelViewport.InitCSSResolver(aResolver: TCSSResolver);
|
|
|
|
+begin
|
|
|
|
+ inherited InitCSSResolver(aResolver);
|
|
|
|
+ if CSSResolver.StyleCount=0 then
|
|
|
|
+ CSSResolver.AddStyle(StylesheetElements)
|
|
|
|
+ else
|
|
|
|
+ CSSResolver.Styles[0]:=StylesheetElements;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+procedure TFresnelViewport.Notification(AComponent: TComponent;
|
|
|
|
+ Operation: TOperation);
|
|
|
|
+begin
|
|
|
|
+ inherited Notification(AComponent, Operation);
|
|
|
|
+ if Operation=opRemove then
|
|
|
|
+ begin
|
|
|
|
+ if AComponent=FLayouter then
|
|
|
|
+ FLayouter:=nil
|
|
|
|
+ else if AComponent=FCSSResolver then
|
|
|
|
+ FCSSResolver:=nil;
|
|
|
|
+ end;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+procedure TFresnelViewport.SetFontMinSize(const AValue: TFresnelLength);
|
|
|
|
+begin
|
|
|
|
+ if FFontMinSize=AValue then Exit;
|
|
|
|
+ FFontMinSize:=AValue;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+procedure TFresnelViewport.SetHeight(AValue: TFresnelLength);
|
|
|
|
+begin
|
|
|
|
+ if FHeight=AValue then exit;
|
|
|
|
+ FHeight:=AValue;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+procedure TFresnelViewport.SetMaxPreferredWidth(const AValue: TFresnelLength);
|
|
|
|
+begin
|
|
|
|
+ if AValue=FMaxPreferredWidth then exit;
|
|
|
|
+ FMaxPreferredWidth:=AValue;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+procedure TFresnelViewport.SetScrollbarWidth(IsHorizontal: boolean;
|
|
|
|
+ const AValue: TFresnelLength);
|
|
|
|
+begin
|
|
|
|
+ if FScrollbarWidth[IsHorizontal]=AValue then exit;
|
|
|
|
+ FScrollbarWidth[IsHorizontal]:=AValue;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+procedure TFresnelViewport.SetStylesheet(AValue: TStrings);
|
|
|
|
+begin
|
|
|
|
+ if AValue=nil then exit;
|
|
|
|
+ if FStylesheet=AValue then Exit;
|
|
|
|
+ if FStylesheet.Equals(AValue) then Exit;
|
|
|
|
+ FStylesheet.Assign(AValue);
|
|
|
|
+ FreeAndNil(FStylesheetElements);
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+procedure TFresnelViewport.SetVPLength(l: TFresnelViewportLength;
|
|
|
|
+ const AValue: TFresnelLength);
|
|
|
|
+begin
|
|
|
|
+ case l of
|
|
|
|
+ vlFontMinSize: FontMinSize:=AValue;
|
|
|
|
+ vlDPIHorizontal: DPI[true]:=AValue;
|
|
|
|
+ vlDPIVertical: DPI[false]:=AValue;
|
|
|
|
+ vlHorizontalScrollbarWidth: ScrollbarWidth[true]:=AValue;
|
|
|
|
+ vlVerticalScrollbarWidth: ScrollbarWidth[false]:=AValue;
|
|
|
|
+ end;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+procedure TFresnelViewport.SetWidth(AValue: TFresnelLength);
|
|
|
|
+begin
|
|
|
|
+ if FWidth=AValue then exit;
|
|
|
|
+ FWidth:=AValue;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+destructor TFresnelViewport.Destroy;
|
|
|
|
+begin
|
|
|
|
+ FreeAndNil(FStylesheetElements);
|
|
|
|
+ FreeAndNil(FStylesheet);
|
|
|
|
+ FreeAndNil(FCSSResolver);
|
|
|
|
+ inherited Destroy;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+procedure TFresnelViewport.ApplyCSS;
|
|
|
|
+var
|
|
|
|
+ CurDomIndex: integer;
|
|
|
|
+
|
|
|
|
+ procedure Traverse(El: TFresnelElement);
|
|
|
|
+ var
|
|
|
|
+ i: Integer;
|
|
|
|
+ begin
|
|
|
|
+ //writeln('Traverse ',El.ClassName,' CSSTypeName=',El.CSSTypeName);
|
|
|
|
+ El.DOMIndex:=CurDomIndex;
|
|
|
|
+ inc(CurDomIndex);
|
|
|
|
+ if El<>Self then
|
|
|
|
+ begin
|
|
|
|
+ CSSResolver.Compute(El,El.StyleElements);
|
|
|
|
+ El.ComputeCSS;
|
|
|
|
+ end;
|
|
|
|
+ Layouter.ComputeCSS(El);
|
|
|
|
+ for i:=0 to El.NodeCount-1 do
|
|
|
|
+ Traverse(El.Nodes[i]);
|
|
|
|
+ Layouter.ComputedChildrenCSS(El);
|
|
|
|
+ end;
|
|
|
|
+
|
|
|
|
+begin
|
|
|
|
+ if NodeCount>1 then
|
|
|
|
+ CSSWarning(20221018152912,'TFresnelViewport.ApplyCSS NodeCount='+IntToStr(NodeCount));
|
|
|
|
+ ClearCSSValues;
|
|
|
|
+ UpdateStylesheetElements;
|
|
|
|
+ InitCSSResolver(CSSResolver);
|
|
|
|
+ //writeln('TFresnelViewport.ApplyCSS ',StylesheetElements.ClassName);
|
|
|
|
+ try
|
|
|
|
+ CurDomIndex:=0;
|
|
|
|
+ Traverse(Self);
|
|
|
|
+ finally
|
|
|
|
+ CSSResolver.ClearStyleCustomData;
|
|
|
|
+ end;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+procedure TFresnelViewport.ClearCSSValues;
|
|
|
|
+begin
|
|
|
|
+ inherited ClearCSSValues;
|
|
|
|
+ FCSSComputed[fcaDisplayBox]:='';
|
|
|
|
+ FCSSComputed[fcaDisplayOutside]:='block';
|
|
|
|
+ FCSSComputed[fcaDisplayInside]:='flow-root';
|
|
|
|
+ FCSSComputed[fcaPosition]:='absolute';
|
|
|
|
+ FCSSComputed[fcaWidth]:=FloatToCSSStr(Width);
|
|
|
|
+ FCSSComputed[fcaHeight]:=FloatToCSSStr(Height);
|
|
|
|
+ FCSSComputed[fcaFontFamily]:='arial';
|
|
|
|
+ FCSSComputed[fcaFontSize]:='12';
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TFresnelViewport.AllocateFont(const Desc: TFresnelFontDesc
|
|
|
|
+ ): IFresnelFont;
|
|
|
|
+begin
|
|
|
|
+ if FFontEngine<>nil then
|
|
|
|
+ Result:=FFontEngine.Allocate(Desc)
|
|
|
|
+ else
|
|
|
|
+ raise EFresnelFont.Create('TFresnelViewport.AllocateFont no FontEngine');
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+constructor TFresnelViewport.Create(AOwner: TComponent);
|
|
|
|
+begin
|
|
|
|
+ inherited Create(AOwner);
|
|
|
|
+ FWidth:=800;
|
|
|
|
+ FMaxPreferredWidth:=100000;
|
|
|
|
+ FHeight:=600;
|
|
|
|
+ FDPI[false]:=FresnelDefaultDPI;
|
|
|
|
+ FDPI[true]:=FresnelDefaultDPI;
|
|
|
|
+ FFontMinSize:=6;
|
|
|
|
+ FScrollbarWidth[False]:=12;
|
|
|
|
+ FScrollbarWidth[true]:=12;
|
|
|
|
+
|
|
|
|
+ FCSSResolver:=TCSSResolver.Create(nil);
|
|
|
|
+ FCSSResolver.OwnsStyle:=false;
|
|
|
|
+ FStylesheet:=TStringList.Create(false);
|
|
|
|
+ FStylesheet.FPOAttachObserver(Self);
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+{ TFresnelElement }
|
|
|
|
+
|
|
|
|
+function TFresnelElement.GetNodeCount: integer;
|
|
|
|
+begin
|
|
|
|
+ Result:=FChildren.Count;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TFresnelElement.GetCSSElComputedAttribute(Attr: TFresnelCSSAttribute
|
|
|
|
+ ): string;
|
|
|
|
+begin
|
|
|
|
+ Result:=FCSSComputed[Attr];
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+procedure TFresnelElement.SetCSSElComputedAttribute(Attr: TFresnelCSSAttribute;
|
|
|
|
+ AValue: string);
|
|
|
|
+begin
|
|
|
|
+ FCSSComputed[Attr]:=AValue;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+procedure TFresnelElement.SetCSSClasses(const AValue: TStrings);
|
|
|
|
+begin
|
|
|
|
+ if FCSSClasses=AValue then Exit;
|
|
|
|
+ if AValue=nil then
|
|
|
|
+ begin
|
|
|
|
+ if FCSSClasses.Count=0 then exit;
|
|
|
|
+ FCSSClasses.Clear;
|
|
|
|
+ end else begin
|
|
|
|
+ if FCSSClasses.Equals(AValue) then exit;
|
|
|
|
+ FCSSClasses.Assign(AValue);
|
|
|
|
+ FCSSClasses.Delimiter:=' ';
|
|
|
|
+ end;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TFresnelElement.GetCSSPseudo(
|
|
|
|
+ Pseudo: TFresnelCSSPseudo): string;
|
|
|
|
+begin
|
|
|
|
+ Result:='';
|
|
|
|
+ case Pseudo of
|
|
|
|
+ fcpaLang: ;
|
|
|
|
+ end;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TFresnelElement.GetNodes(Index: integer): TFresnelElement;
|
|
|
|
+begin
|
|
|
|
+ Result:=TFresnelElement(FChildren[Index]);
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TFresnelElement.GetCSSElAttribute(Attr: TFresnelCSSAttribute): string;
|
|
|
|
+begin
|
|
|
|
+ Result:=FCSSAttributes[Attr];
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+procedure TFresnelElement.SetCSSElAttribute(Attr: TFresnelCSSAttribute;
|
|
|
|
+ const AValue: string);
|
|
|
|
+begin
|
|
|
|
+ writeln('TFresnelElement.SetCSSAttribute ',Name,' ',Attr,' ',AValue);
|
|
|
|
+ if FCSSAttributes[Attr]=AValue then exit;
|
|
|
|
+ FCSSAttributes[Attr]:=AValue;
|
|
|
|
+ case AValue of
|
|
|
|
+ 'inherit','initial','unset': exit;
|
|
|
|
+ end;
|
|
|
|
+
|
|
|
|
+ // set shorthand attributes
|
|
|
|
+ case Attr of
|
|
|
|
+ fcaDisplay: CheckOrSetCSSDisplay(AValue,false);
|
|
|
|
+ fcaOverflow: CheckOrSetCSSOverflow(AValue,false);
|
|
|
|
+ fcaBorder: CheckOrSetCSSBorder(AValue,false);
|
|
|
|
+ fcaBorderLeft: CheckOrSetCSSBorderLeft(AValue,false);
|
|
|
|
+ fcaBorderTop: CheckOrSetCSSBorderTop(AValue,false);
|
|
|
|
+ fcaBorderRight: CheckOrSetCSSBorderRight(AValue,false);
|
|
|
|
+ fcaBorderBottom: CheckOrSetCSSBorderBottom(AValue,false);
|
|
|
|
+ fcaBorderWidth: CheckOrSetCSSBorderWidth(AValue,false);
|
|
|
|
+ fcaFont: CheckOrSetCSSFont(AValue,false);
|
|
|
|
+ fcaMargin: CheckOrSetCSSMargin(AValue,false);
|
|
|
|
+ fcaMarginBlock: CheckOrSetCSSMarginBlock(AValue,false);
|
|
|
|
+ fcaMarginInline: CheckOrSetCSSMarginInline(AValue,false);
|
|
|
|
+ fcaPadding: CheckOrSetCSSPadding(AValue,false);
|
|
|
|
+ end;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TFresnelElement.CheckCSSClear(const AValue: string): boolean;
|
|
|
|
+begin
|
|
|
|
+ case AValue of
|
|
|
|
+ 'none',
|
|
|
|
+ 'left',
|
|
|
|
+ 'right',
|
|
|
|
+ 'both',
|
|
|
|
+ 'inline-start', // ltr left
|
|
|
|
+ 'inline-end': // ltr right
|
|
|
|
+ exit(true);
|
|
|
|
+ else
|
|
|
|
+ CSSInvalidValueWarning(20221031133557,fcaClear,AValue);
|
|
|
|
+ Result:=false;
|
|
|
|
+ end;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TFresnelElement.CheckOrSetCSSDisplay(const AValue: string; Check: boolean
|
|
|
|
+ ): boolean;
|
|
|
|
+var
|
|
|
|
+ p: integer;
|
|
|
|
+ DispOutside, DispInside: String;
|
|
|
|
+begin
|
|
|
|
+ p:=Pos(' ',AValue);
|
|
|
|
+ if p>0 then
|
|
|
|
+ begin
|
|
|
|
+ p:=1;
|
|
|
|
+ DispOutside:=CSSReadNextValue(AValue,p);
|
|
|
|
+ DispInside:=CSSReadNextValue(AValue,p);
|
|
|
|
+ if Check then
|
|
|
|
+ begin
|
|
|
|
+ if not CheckCSSDisplayOutside(DispOutside) then
|
|
|
|
+ exit(false);
|
|
|
|
+ if not CheckCSSDisplayInside(DispInside) then
|
|
|
|
+ exit(false);
|
|
|
|
+ end else begin
|
|
|
|
+ SetCSSElAttribute(fcaDisplayOutside,DispOutside);
|
|
|
|
+ SetCSSElAttribute(fcaDisplayInside,DispInside);
|
|
|
|
+ end;
|
|
|
|
+ end else begin
|
|
|
|
+ case AValue of
|
|
|
|
+ 'none',
|
|
|
|
+ 'contents':
|
|
|
|
+ if not Check then
|
|
|
|
+ begin
|
|
|
|
+ SetCSSElAttribute(fcaDisplayBox,AValue);
|
|
|
|
+ SetCSSElAttribute(fcaDisplayInside,'');
|
|
|
|
+ SetCSSElAttribute(fcaDisplayOutside,'');
|
|
|
|
+ end;
|
|
|
|
+ 'block',
|
|
|
|
+ 'inline':
|
|
|
|
+ if not Check then
|
|
|
|
+ begin
|
|
|
|
+ SetCSSElAttribute(fcaDisplayBox,'');
|
|
|
|
+ SetCSSElAttribute(fcaDisplayOutside,AValue);
|
|
|
|
+ SetCSSElAttribute(fcaDisplayInside,'flow');
|
|
|
|
+ end;
|
|
|
|
+ 'flow',
|
|
|
|
+ 'flow-root',
|
|
|
|
+ 'flex',
|
|
|
|
+ 'grid':
|
|
|
|
+ if not Check then
|
|
|
|
+ begin
|
|
|
|
+ SetCSSElAttribute(fcaDisplayBox,'');
|
|
|
|
+ SetCSSElAttribute(fcaDisplayOutside,'');
|
|
|
|
+ SetCSSElAttribute(fcaDisplayInside,AValue);
|
|
|
|
+ end;
|
|
|
|
+ 'inline-block':
|
|
|
|
+ if not Check then
|
|
|
|
+ begin
|
|
|
|
+ SetCSSElAttribute(fcaDisplayBox,'');
|
|
|
|
+ SetCSSElAttribute(fcaDisplayOutside,'inline');
|
|
|
|
+ SetCSSElAttribute(fcaDisplayInside,'flow-root');
|
|
|
|
+ end;
|
|
|
|
+ else
|
|
|
|
+ p:=Pos('-',AValue);
|
|
|
|
+ if p>0 then
|
|
|
|
+ begin
|
|
|
|
+ DispOutside:=LeftStr(AValue,p-1);
|
|
|
|
+ DispInside:=copy(AValue,p+1,length(AValue));
|
|
|
|
+ if Check then
|
|
|
|
+ begin
|
|
|
|
+ if not CheckCSSDisplayOutside(DispOutside) then
|
|
|
|
+ exit(false);
|
|
|
|
+ if not CheckCSSDisplayInside(DispInside) then
|
|
|
|
+ exit(false);
|
|
|
|
+ end else begin
|
|
|
|
+ SetCSSElAttribute(fcaDisplayBox,'');
|
|
|
|
+ SetCSSElAttribute(fcaDisplayOutside,DispOutside);
|
|
|
|
+ SetCSSElAttribute(fcaDisplayInside,DispInside);
|
|
|
|
+ end;
|
|
|
|
+ end else begin
|
|
|
|
+ CSSInvalidValueWarning(20221016214635,fcaDisplay,AValue);
|
|
|
|
+ exit(false);
|
|
|
|
+ end;
|
|
|
|
+ end;
|
|
|
|
+ end;
|
|
|
|
+ Result:=true;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TFresnelElement.CheckCSSDisplayBox(const AValue: string): boolean;
|
|
|
|
+begin
|
|
|
|
+ case AValue of
|
|
|
|
+ 'none',
|
|
|
|
+ 'contents':
|
|
|
|
+ exit(true);
|
|
|
|
+ else
|
|
|
|
+ CSSInvalidValueWarning(20221031085548,fcaDisplayBox,AValue);
|
|
|
|
+ Result:=false;
|
|
|
|
+ end;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TFresnelElement.CheckCSSDisplayInside(const AValue: string): boolean;
|
|
|
|
+begin
|
|
|
|
+ case AValue of
|
|
|
|
+ 'flow',
|
|
|
|
+ 'flow-root',
|
|
|
|
+ 'flex',
|
|
|
|
+ 'grid':
|
|
|
|
+ exit(true);
|
|
|
|
+ else
|
|
|
|
+ CSSInvalidValueWarning(20221031085111,fcaDisplayInside,AValue);
|
|
|
|
+ Result:=false;
|
|
|
|
+ end;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TFresnelElement.CheckCSSDisplayOutside(const AValue: string): boolean;
|
|
|
|
+begin
|
|
|
|
+ case AValue of
|
|
|
|
+ 'block',
|
|
|
|
+ 'inline':
|
|
|
|
+ //'run-in'
|
|
|
|
+ exit(true);
|
|
|
|
+ else
|
|
|
|
+ CSSInvalidValueWarning(20221031085119,fcaDisplayOutside,AValue);
|
|
|
|
+ Result:=false;
|
|
|
|
+ end;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TFresnelElement.CheckCSSPosition(const AValue: string
|
|
|
|
+ ): boolean;
|
|
|
|
+begin
|
|
|
|
+ case AValue of
|
|
|
|
+ 'static',
|
|
|
|
+ 'relative',
|
|
|
|
+ 'absolute',
|
|
|
|
+ 'fixed',
|
|
|
|
+ 'sticky': Result:=true;
|
|
|
|
+ else
|
|
|
|
+ CSSInvalidValueWarning(20221016214813,fcaPosition,AValue);
|
|
|
|
+ Result:=false;
|
|
|
|
+ end;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TFresnelElement.CheckOrSetCSSOverflow(const AValue: string; Check: boolean
|
|
|
|
+ ): boolean;
|
|
|
|
+var
|
|
|
|
+ p: Integer;
|
|
|
|
+ X, Y: String;
|
|
|
|
+begin
|
|
|
|
+ // x, y
|
|
|
|
+ p:=1;
|
|
|
|
+ X:=CSSReadNextValue(AValue,p);
|
|
|
|
+ Y:=CSSReadNextValue(AValue,p);
|
|
|
|
+ if Check then
|
|
|
|
+ begin
|
|
|
|
+ if not CheckCSSOverflowX(X) then
|
|
|
|
+ exit(false);
|
|
|
|
+ if (Y<>'') and not CheckCSSOverflowY(Y) then
|
|
|
|
+ exit(false);
|
|
|
|
+ end else begin
|
|
|
|
+ if Y='' then Y:=X;
|
|
|
|
+ SetCSSElAttribute(fcaOverflowX,X);
|
|
|
|
+ SetCSSElAttribute(fcaOverflowY,Y);
|
|
|
|
+ end;
|
|
|
|
+ Result:=true;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TFresnelElement.CheckCSSOverflowX(const AValue: string
|
|
|
|
+ ): boolean;
|
|
|
|
+begin
|
|
|
|
+ case AValue of
|
|
|
|
+ 'visible',
|
|
|
|
+ 'hidden',
|
|
|
|
+ 'clip',
|
|
|
|
+ 'scroll',
|
|
|
|
+ 'auto': Result:=true;
|
|
|
|
+ else
|
|
|
|
+ CSSInvalidValueWarning(20221016214951,fcaOverflowX,AValue);
|
|
|
|
+ Result:=false;
|
|
|
|
+ end;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TFresnelElement.CheckCSSOverflowY(const AValue: string
|
|
|
|
+ ): boolean;
|
|
|
|
+begin
|
|
|
|
+ case AValue of
|
|
|
|
+ 'visible',
|
|
|
|
+ 'hidden',
|
|
|
|
+ 'clip',
|
|
|
|
+ 'scroll',
|
|
|
|
+ 'auto': Result:=true;
|
|
|
|
+ else
|
|
|
|
+ CSSInvalidValueWarning(20221016215008,fcaOverflowY,AValue);
|
|
|
|
+ Result:=false;
|
|
|
|
+ end;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TFresnelElement.CheckCSSZIndex(const AValue: string): boolean;
|
|
|
|
+var
|
|
|
|
+ V, Code: Integer;
|
|
|
|
+begin
|
|
|
|
+ if AValue='auto' then
|
|
|
|
+ exit(true);
|
|
|
|
+ V:=0;
|
|
|
|
+ Code:=0;
|
|
|
|
+ val(AValue,V,Code);
|
|
|
|
+ if (Code>0) or (V<low(ShortInt)) or (V>high(ShortInt)) then
|
|
|
|
+ begin
|
|
|
|
+ CSSInvalidValueWarning(20221016215854,fcaZIndex,AValue);
|
|
|
|
+ Result:=false;
|
|
|
|
+ end else
|
|
|
|
+ Result:=true;
|
|
|
|
+ if V=0 then ;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TFresnelElement.CheckCSSDirection(const AValue: string
|
|
|
|
+ ): boolean;
|
|
|
|
+begin
|
|
|
|
+ case AValue of
|
|
|
|
+ 'lrt','rtl': Result:=true;
|
|
|
|
+ else
|
|
|
|
+ CSSInvalidValueWarning(20221019094537,fcaDirection,AValue);
|
|
|
|
+ Result:=false;
|
|
|
|
+ end;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TFresnelElement.CheckOrSetCSSBorder(const AValue: string;
|
|
|
|
+ Check: boolean): boolean;
|
|
|
|
+var
|
|
|
|
+ p: Integer;
|
|
|
|
+ aWidth: String;
|
|
|
|
+begin
|
|
|
|
+ // width, style, color
|
|
|
|
+ p:=1;
|
|
|
|
+ aWidth:=CSSReadNextValue(AValue,p);
|
|
|
|
+ //aStyle:=CSSReadNextValue(AValue,p);
|
|
|
|
+ //aColor:=CSSReadNextValue(AValue,p);
|
|
|
|
+ if Check then
|
|
|
|
+ begin
|
|
|
|
+ Result:=CheckCSSBorderXWidth(fcaBorderLeftWidth,aWidth);
|
|
|
|
+ end else begin
|
|
|
|
+ SetCSSElAttribute(fcaBorderLeftWidth,aWidth);
|
|
|
|
+ SetCSSElAttribute(fcaBorderTopWidth,aWidth);
|
|
|
|
+ SetCSSElAttribute(fcaBorderRightWidth,aWidth);
|
|
|
|
+ SetCSSElAttribute(fcaBorderBottomWidth,aWidth);
|
|
|
|
+ Result:=true;
|
|
|
|
+ end;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TFresnelElement.CheckOrSetCSSBorderLeft(const AValue: string;
|
|
|
|
+ Check: boolean): boolean;
|
|
|
|
+var
|
|
|
|
+ p: Integer;
|
|
|
|
+ aWidth: String;
|
|
|
|
+begin
|
|
|
|
+ // width, style, color
|
|
|
|
+ p:=1;
|
|
|
|
+ aWidth:=CSSReadNextValue(AValue,p);
|
|
|
|
+ //aStyle:=CSSReadNextValue(AValue,p);
|
|
|
|
+ //aColor:=CSSReadNextValue(AValue,p);
|
|
|
|
+ if Check then
|
|
|
|
+ begin
|
|
|
|
+ Result:=CheckCSSBorderXWidth(fcaBorderLeftWidth,aWidth);
|
|
|
|
+ end else
|
|
|
|
+ begin
|
|
|
|
+ SetCSSElAttribute(fcaBorderLeftWidth,aWidth);
|
|
|
|
+ end;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TFresnelElement.CheckOrSetCSSBorderTop(const AValue: string;
|
|
|
|
+ Check: boolean): boolean;
|
|
|
|
+var
|
|
|
|
+ p: Integer;
|
|
|
|
+ aWidth: String;
|
|
|
|
+begin
|
|
|
|
+ // width, style, color
|
|
|
|
+ p:=1;
|
|
|
|
+ aWidth:=CSSReadNextValue(AValue,p);
|
|
|
|
+ //aStyle:=CSSReadNextValue(AValue,p);
|
|
|
|
+ //aColor:=CSSReadNextValue(AValue,p);
|
|
|
|
+ if Check then
|
|
|
|
+ begin
|
|
|
|
+ Result:=CheckCSSBorderXWidth(fcaBorderTopWidth,aWidth);
|
|
|
|
+ end else
|
|
|
|
+ begin
|
|
|
|
+ SetCSSElAttribute(fcaBorderTopWidth,aWidth);
|
|
|
|
+ end;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TFresnelElement.CheckOrSetCSSBorderRight(const AValue: string;
|
|
|
|
+ Check: boolean): boolean;
|
|
|
|
+var
|
|
|
|
+ p: Integer;
|
|
|
|
+ aWidth: String;
|
|
|
|
+begin
|
|
|
|
+ // width, style, color
|
|
|
|
+ p:=1;
|
|
|
|
+ aWidth:=CSSReadNextValue(AValue,p);
|
|
|
|
+ //aStyle:=CSSReadNextValue(AValue,p);
|
|
|
|
+ //aColor:=CSSReadNextValue(AValue,p);
|
|
|
|
+ if Check then
|
|
|
|
+ begin
|
|
|
|
+ Result:=CheckCSSBorderXWidth(fcaBorderRightWidth,aWidth);
|
|
|
|
+ end else
|
|
|
|
+ begin
|
|
|
|
+ SetCSSElAttribute(fcaBorderRightWidth,aWidth);
|
|
|
|
+ end;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TFresnelElement.CheckOrSetCSSBorderBottom(const AValue: string;
|
|
|
|
+ Check: boolean): boolean;
|
|
|
|
+var
|
|
|
|
+ p: Integer;
|
|
|
|
+ aWidth: String;
|
|
|
|
+begin
|
|
|
|
+ // width, style, color
|
|
|
|
+ p:=1;
|
|
|
|
+ aWidth:=CSSReadNextValue(AValue,p);
|
|
|
|
+ //aStyle:=CSSReadNextValue(AValue,p);
|
|
|
|
+ //aColor:=CSSReadNextValue(AValue,p);
|
|
|
|
+ if Check then
|
|
|
|
+ begin
|
|
|
|
+ Result:=CheckCSSBorderXWidth(fcaBorderBottomWidth,aWidth);
|
|
|
|
+ end else
|
|
|
|
+ begin
|
|
|
|
+ SetCSSElAttribute(fcaBorderBottomWidth,aWidth);
|
|
|
|
+ end;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TFresnelElement.CheckOrSetCSSBorderWidth(const AValue: string;
|
|
|
|
+ Check: boolean): boolean;
|
|
|
|
+var
|
|
|
|
+ p: Integer;
|
|
|
|
+ aTop, aRight, aBottom, aLeft: String;
|
|
|
|
+begin
|
|
|
|
+ p:=1;
|
|
|
|
+ aTop:=CSSReadNextValue(AValue,p);
|
|
|
|
+ aRight:=CSSReadNextValue(AValue,p);
|
|
|
|
+ aBottom:=CSSReadNextValue(AValue,p);
|
|
|
|
+ aLeft:=CSSReadNextValue(AValue,p);
|
|
|
|
+ if Check then
|
|
|
|
+ begin
|
|
|
|
+ if not CheckCSSBorderXWidth(fcaBorderTopWidth,aTop) then
|
|
|
|
+ exit(false);
|
|
|
|
+ if (aRight<>'') and not CheckCSSBorderXWidth(fcaBorderRightWidth,aRight) then
|
|
|
|
+ exit(false);
|
|
|
|
+ if (aBottom<>'') and not CheckCSSBorderXWidth(fcaBorderBottomWidth,aBottom) then
|
|
|
|
+ exit(false);
|
|
|
|
+ if (aLeft<>'') and not CheckCSSBorderXWidth(fcaBorderLeftWidth,aLeft) then
|
|
|
|
+ exit(false);
|
|
|
|
+ end else begin
|
|
|
|
+ if aRight='' then
|
|
|
|
+ aRight:=aTop;
|
|
|
|
+ if aBottom='' then
|
|
|
|
+ aBottom:=aTop;
|
|
|
|
+ if aLeft='' then
|
|
|
|
+ aLeft:=aRight;
|
|
|
|
+ SetCSSElAttribute(fcaBorderLeftWidth,aLeft);
|
|
|
|
+ SetCSSElAttribute(fcaBorderTopWidth,aTop);
|
|
|
|
+ SetCSSElAttribute(fcaBorderRightWidth,aRight);
|
|
|
|
+ SetCSSElAttribute(fcaBorderBottomWidth,aBottom);
|
|
|
|
+ end;
|
|
|
|
+ Result:=true;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TFresnelElement.CheckCSSBorderXWidth(Attr: TFresnelCSSAttribute;
|
|
|
|
+ const AValue: string): boolean;
|
|
|
|
+begin
|
|
|
|
+ case AValue of
|
|
|
|
+ 'thin',
|
|
|
|
+ 'medium',
|
|
|
|
+ 'thick': Result:=true;
|
|
|
|
+ else
|
|
|
|
+ Result:=CheckCSSLength(Attr,AValue,[flcNoNegative]);
|
|
|
|
+ end
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TFresnelElement.CheckCSSBorderColor(const AValue: string): boolean;
|
|
|
|
+var
|
|
|
|
+ aColor: TFPColor;
|
|
|
|
+begin
|
|
|
|
+ Result:=TryHtmlToFPColor(AValue,aColor);
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TFresnelElement.CheckCSSBoxSizing(const AValue: string): boolean;
|
|
|
|
+begin
|
|
|
|
+ case AValue of
|
|
|
|
+ // ToDo 'border-box',
|
|
|
|
+ 'content-box': Result:=true;
|
|
|
|
+ else
|
|
|
|
+ CSSInvalidValueWarning(20221019123227,fcaBoxSizing,AValue);
|
|
|
|
+ Result:=false;
|
|
|
|
+ end;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TFresnelElement.CheckCSSFloat(const AValue: string): boolean;
|
|
|
|
+begin
|
|
|
|
+ case AValue of
|
|
|
|
+ 'none',
|
|
|
|
+ 'left',
|
|
|
|
+ 'right',
|
|
|
|
+ 'inline-start', // ltr depending left
|
|
|
|
+ 'inline-end': // ltr depending right
|
|
|
|
+ Result:=true;
|
|
|
|
+ else
|
|
|
|
+ CSSInvalidValueWarning(20221024134429,fcaFloat,AValue);
|
|
|
|
+ Result:=false;
|
|
|
|
+ end;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TFresnelElement.CheckCSSLineHeight(const AValue: string): boolean;
|
|
|
|
+begin
|
|
|
|
+ if AValue='normal' then
|
|
|
|
+ Result:=true
|
|
|
|
+ else
|
|
|
|
+ Result:=CheckCSSLength(fcaLineHeight,AValue,[flcNoNegative]);
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TFresnelElement.CheckOrSetCSSMargin(const AValue: string;
|
|
|
|
+ Check: boolean): boolean;
|
|
|
|
+var
|
|
|
|
+ p: Integer;
|
|
|
|
+ aTop, aRight, aBottom, aLeft: String;
|
|
|
|
+begin
|
|
|
|
+ p:=1;
|
|
|
|
+ aTop:=CSSReadNextValue(AValue,p);
|
|
|
|
+ aRight:=CSSReadNextValue(AValue,p);
|
|
|
|
+ aBottom:=CSSReadNextValue(AValue,p);
|
|
|
|
+ aLeft:=CSSReadNextValue(AValue,p);
|
|
|
|
+ if Check then
|
|
|
|
+ begin
|
|
|
|
+ if not CheckCSSLength(fcaMarginTop,aTop) then
|
|
|
|
+ exit(false);
|
|
|
|
+ if (aRight<>'') and not CheckCSSLength(fcaMarginRight,aRight) then
|
|
|
|
+ exit(false);
|
|
|
|
+ if (aBottom<>'') and not CheckCSSLength(fcaMarginRight,aBottom) then
|
|
|
|
+ exit(false);
|
|
|
|
+ if (aLeft<>'') and not CheckCSSLength(fcaMarginLeft,aLeft) then
|
|
|
|
+ exit(false);
|
|
|
|
+ end else begin
|
|
|
|
+ if aRight='' then
|
|
|
|
+ aRight:=aTop;
|
|
|
|
+ if aBottom='' then
|
|
|
|
+ aBottom:=aTop;
|
|
|
|
+ if aLeft='' then
|
|
|
|
+ aLeft:=aRight;
|
|
|
|
+ SetCSSElAttribute(fcaMarginLeft,aLeft);
|
|
|
|
+ SetCSSElAttribute(fcaMarginTop,aTop);
|
|
|
|
+ SetCSSElAttribute(fcaMarginRight,aRight);
|
|
|
|
+ SetCSSElAttribute(fcaMarginBottom,aBottom);
|
|
|
|
+ end;
|
|
|
|
+ Result:=true;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TFresnelElement.CheckOrSetCSSMarginBlock(const AValue: string;
|
|
|
|
+ Check: boolean): boolean;
|
|
|
|
+var
|
|
|
|
+ p: Integer;
|
|
|
|
+ aStart, aEnd: String;
|
|
|
|
+begin
|
|
|
|
+ p:=1;
|
|
|
|
+ aStart:=CSSReadNextValue(AValue,p);
|
|
|
|
+ aEnd:=CSSReadNextValue(AValue,p);
|
|
|
|
+ if Check then
|
|
|
|
+ begin
|
|
|
|
+ if not CheckCSSLength(fcaMarginBlockStart,aStart) then
|
|
|
|
+ exit(false);
|
|
|
|
+ if (aEnd<>'') and not CheckCSSLength(fcaMarginBlockEnd,aEnd) then
|
|
|
|
+ exit(false);
|
|
|
|
+ end else begin
|
|
|
|
+ if aEnd='' then
|
|
|
|
+ aEnd:=aStart;
|
|
|
|
+ SetCSSElAttribute(fcaMarginBlockStart,aStart);
|
|
|
|
+ SetCSSElAttribute(fcaMarginBlockEnd,aEnd);
|
|
|
|
+ end;
|
|
|
|
+ Result:=true;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TFresnelElement.CheckOrSetCSSMarginInline(const AValue: string;
|
|
|
|
+ Check: boolean): boolean;
|
|
|
|
+var
|
|
|
|
+ p: Integer;
|
|
|
|
+ aStart, aEnd: String;
|
|
|
|
+begin
|
|
|
|
+ p:=1;
|
|
|
|
+ aStart:=CSSReadNextValue(AValue,p);
|
|
|
|
+ aEnd:=CSSReadNextValue(AValue,p);
|
|
|
|
+ if Check then
|
|
|
|
+ begin
|
|
|
|
+ if not CheckCSSLength(fcaMarginInlineStart,aStart) then
|
|
|
|
+ exit(false);
|
|
|
|
+ if (aEnd<>'') and not CheckCSSLength(fcaMarginInlineEnd,aEnd) then
|
|
|
|
+ exit(false);
|
|
|
|
+ end else begin
|
|
|
|
+ if aEnd='' then aEnd:=aStart;
|
|
|
|
+ SetCSSElAttribute(fcaMarginInlineStart,aStart);
|
|
|
|
+ SetCSSElAttribute(fcaMarginInlineEnd,aEnd);
|
|
|
|
+ end;
|
|
|
|
+ Result:=true;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TFresnelElement.CheckCSSMinMaxWidthHeight(Attr: TFresnelCSSAttribute;
|
|
|
|
+ const AValue: string): boolean;
|
|
|
|
+begin
|
|
|
|
+ case AValue of
|
|
|
|
+ 'auto',
|
|
|
|
+ 'max-content',
|
|
|
|
+ 'min-content': Result:=true;
|
|
|
|
+ else
|
|
|
|
+ // ToDo fit-content()
|
|
|
|
+ Result:=CheckCSSLength(Attr,AValue,[flcNoNegative]);
|
|
|
|
+ end;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TFresnelElement.CheckCSSOpacity(const AValue: string
|
|
|
|
+ ): boolean;
|
|
|
|
+var
|
|
|
|
+ l: SizeInt;
|
|
|
|
+ Opacity: TFresnelLength;
|
|
|
|
+ Code: integer;
|
|
|
|
+begin
|
|
|
|
+ // float or float%
|
|
|
|
+ if AValue='' then
|
|
|
|
+ exit(true);
|
|
|
|
+ Result:=false;
|
|
|
|
+ l:=length(AValue);
|
|
|
|
+ if AValue[l]='%' then
|
|
|
|
+ begin
|
|
|
|
+ Code:=0;
|
|
|
|
+ val(LeftStr(AValue,l-1),Opacity,Code);
|
|
|
|
+ if Code>0 then
|
|
|
|
+ begin
|
|
|
|
+ CSSInvalidValueWarning(20221019112449,fcaOpacity,AValue);
|
|
|
|
+ exit;
|
|
|
|
+ end;
|
|
|
|
+ if (Opacity<0) or (Opacity>100.0) then
|
|
|
|
+ begin
|
|
|
|
+ CSSInvalidValueWarning(20221019112449,fcaOpacity,AValue);
|
|
|
|
+ exit;
|
|
|
|
+ end;
|
|
|
|
+ end else begin
|
|
|
|
+ Code:=0;
|
|
|
|
+ val(AValue,Opacity,Code);
|
|
|
|
+ if Code>0 then
|
|
|
|
+ begin
|
|
|
|
+ CSSInvalidValueWarning(20221019112600,fcaOpacity,AValue);
|
|
|
|
+ exit;
|
|
|
|
+ end;
|
|
|
|
+ if (Opacity<0) or (Opacity>1.0) then
|
|
|
|
+ begin
|
|
|
|
+ CSSInvalidValueWarning(20221019112607,fcaOpacity,AValue);
|
|
|
|
+ exit;
|
|
|
|
+ end;
|
|
|
|
+ end;
|
|
|
|
+ Result:=true;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TFresnelElement.CheckOrSetCSSFont(const AValue: string; Check: boolean
|
|
|
|
+ ): boolean;
|
|
|
|
+var
|
|
|
|
+ p, Code, Weight: Integer;
|
|
|
|
+ s, LineHeight: String;
|
|
|
|
+ SlashP: SizeInt;
|
|
|
|
+begin
|
|
|
|
+ p:=1;
|
|
|
|
+ s:=CSSReadNextValue(AValue,p);
|
|
|
|
+ case s of
|
|
|
|
+ 'normal','italic','oblique':
|
|
|
|
+ begin
|
|
|
|
+ // first value is font-style
|
|
|
|
+ if not Check then
|
|
|
|
+ SetCSSElAttribute(fcaFontStyle,s);
|
|
|
|
+ s:=CSSReadNextValue(AValue,p);
|
|
|
|
+ end;
|
|
|
|
+ end;
|
|
|
|
+ case s of
|
|
|
|
+ 'normal','small-caps':
|
|
|
|
+ begin
|
|
|
|
+ // second value is font-variant
|
|
|
|
+ if not Check then
|
|
|
|
+ SetCSSElAttribute(fcaFontVariant,s);
|
|
|
|
+ s:=CSSReadNextValue(AValue,p);
|
|
|
|
+ end;
|
|
|
|
+ end;
|
|
|
|
+ case s of
|
|
|
|
+ 'normal','bold','bolder','lighter':
|
|
|
|
+ begin
|
|
|
|
+ // third value is font-weight
|
|
|
|
+ if not Check then
|
|
|
|
+ SetCSSElAttribute(fcaFontWeight,s);
|
|
|
|
+ s:=CSSReadNextValue(AValue,p);
|
|
|
|
+ end;
|
|
|
|
+ '0'..'9':
|
|
|
|
+ begin
|
|
|
|
+ Weight:=0;
|
|
|
|
+ Code:=0;
|
|
|
|
+ val(s,Weight,Code);
|
|
|
|
+ if (Code>0) or (Weight<=0) then
|
|
|
|
+ begin
|
|
|
|
+ if Check then
|
|
|
|
+ CSSWarning(20221016183759,'font expected font-weight, but got "'+s+'"');
|
|
|
|
+ exit(false);
|
|
|
|
+ end;
|
|
|
|
+ if not Check then
|
|
|
|
+ SetCSSElAttribute(fcaFontWeight,s);
|
|
|
|
+ s:=CSSReadNextValue(AValue,p);
|
|
|
|
+ end;
|
|
|
|
+ end;
|
|
|
|
+
|
|
|
|
+ SlashP:=Pos('/',s);
|
|
|
|
+ if SlashP>0 then
|
|
|
|
+ begin
|
|
|
|
+ // font-size/line-height
|
|
|
|
+ LineHeight:=copy(s,SlashP+1,length(s));
|
|
|
|
+ s:=LeftStr(s,SlashP-1);
|
|
|
|
+ end else
|
|
|
|
+ LineHeight:='';
|
|
|
|
+
|
|
|
|
+ case s of
|
|
|
|
+ 'medium','xx-small','x-small','small','large','x-large','xx-large','smaller','larger':
|
|
|
|
+ begin
|
|
|
|
+ // value is font-size
|
|
|
|
+ if not Check then
|
|
|
|
+ SetCSSElAttribute(fcaFontSize,s);
|
|
|
|
+ end;
|
|
|
|
+ '0'..'9':
|
|
|
|
+ begin
|
|
|
|
+ Weight:=0;
|
|
|
|
+ Code:=0;
|
|
|
|
+ val(s,Weight,Code);
|
|
|
|
+ if Code>0 then
|
|
|
|
+ begin
|
|
|
|
+ if Check then
|
|
|
|
+ CSSWarning(20221016184818,'font expected font-size, but got "'+s+'"');
|
|
|
|
+ exit(false);
|
|
|
|
+ end;
|
|
|
|
+ if not Check then
|
|
|
|
+ SetCSSElAttribute(fcaFontSize,s);
|
|
|
|
+ end;
|
|
|
|
+ else
|
|
|
|
+ if Check then
|
|
|
|
+ CSSWarning(20221016184934,'font expected font-size, but got "'+s+'"');
|
|
|
|
+ exit(false);
|
|
|
|
+ end;
|
|
|
|
+ if (LineHeight<>'') and not Check then
|
|
|
|
+ SetCSSElAttribute(fcaLineHeight,LineHeight);
|
|
|
|
+
|
|
|
|
+ // rest is font-family
|
|
|
|
+ while (p<=length(AValue)) and (aValue[p] in [' ',#9,#10,#13]) do inc(p);
|
|
|
|
+
|
|
|
|
+ if not Check then
|
|
|
|
+ SetCSSElAttribute(fcaFontFamily,copy(AValue,p,length(AValue)));
|
|
|
|
+ Result:=true;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TFresnelElement.CheckCSSFontKerning(const AValue: string
|
|
|
|
+ ): boolean;
|
|
|
|
+begin
|
|
|
|
+ case AValue of
|
|
|
|
+ 'auto','normal','none': Result:=true;
|
|
|
|
+ else
|
|
|
|
+ CSSInvalidValueWarning(20221016233244,fcaFontKerning,AValue);
|
|
|
|
+ Result:=false;
|
|
|
|
+ end;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TFresnelElement.CheckCSSFontSize(const AValue: string
|
|
|
|
+ ): boolean;
|
|
|
|
+begin
|
|
|
|
+ case AValue of
|
|
|
|
+ 'medium',
|
|
|
|
+ 'xx-small',
|
|
|
|
+ 'x-small',
|
|
|
|
+ 'small',
|
|
|
|
+ 'large',
|
|
|
|
+ 'x-large',
|
|
|
|
+ 'xx-large',
|
|
|
|
+ 'smaller',
|
|
|
|
+ 'larger',
|
|
|
|
+ 'math': Result:=true;
|
|
|
|
+ else
|
|
|
|
+ Result:=CheckCSSLength(fcaFontSize,AValue,[flcNoNegative]);
|
|
|
|
+ end;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TFresnelElement.CheckCSSFontStyle(const AValue: string
|
|
|
|
+ ): boolean;
|
|
|
|
+begin
|
|
|
|
+ case AValue of
|
|
|
|
+ 'normal',
|
|
|
|
+ 'italic',
|
|
|
|
+ 'oblique': Result:=true;
|
|
|
|
+ else
|
|
|
|
+ CSSInvalidValueWarning(20221016234702,fcaFontStyle,AValue);
|
|
|
|
+ Result:=false;
|
|
|
|
+ end;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TFresnelElement.CheckCSSFontWeight(const AValue: string
|
|
|
|
+ ): boolean;
|
|
|
|
+begin
|
|
|
|
+ case AValue of
|
|
|
|
+ 'normal',
|
|
|
|
+ 'bold',
|
|
|
|
+ 'lighter',
|
|
|
|
+ 'bolder',
|
|
|
|
+ '100',
|
|
|
|
+ '200',
|
|
|
|
+ '300',
|
|
|
|
+ '400',
|
|
|
|
+ '500',
|
|
|
|
+ '600',
|
|
|
|
+ '700',
|
|
|
|
+ '800',
|
|
|
|
+ '900': Result:=true;
|
|
|
|
+ else
|
|
|
|
+ CSSInvalidValueWarning(20221016235036,fcaFontWeight,AValue);
|
|
|
|
+ Result:=false;
|
|
|
|
+ end;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TFresnelElement.CheckCSSFontVariant(const AValue: string
|
|
|
|
+ ): boolean;
|
|
|
|
+begin
|
|
|
|
+ case AValue of
|
|
|
|
+ 'normal',
|
|
|
|
+ 'small-caps',
|
|
|
|
+ 'none': Result:=true;
|
|
|
|
+ else
|
|
|
|
+ CSSInvalidValueWarning(20221016235254,fcaFontVariant,AValue);
|
|
|
|
+ Result:=false;
|
|
|
|
+ end;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TFresnelElement.CheckOrSetCSSPadding(const AValue: string;
|
|
|
|
+ Check: boolean): boolean;
|
|
|
|
+var
|
|
|
|
+ p: Integer;
|
|
|
|
+ aTop, aRight, aBottom, aLeft: String;
|
|
|
|
+begin
|
|
|
|
+ p:=1;
|
|
|
|
+ aTop:=CSSReadNextValue(AValue,p);
|
|
|
|
+ aRight:=CSSReadNextValue(AValue,p);
|
|
|
|
+ aBottom:=CSSReadNextValue(AValue,p);
|
|
|
|
+ aLeft:=CSSReadNextValue(AValue,p);
|
|
|
|
+ if Check then
|
|
|
|
+ begin
|
|
|
|
+ if not CheckCSSLength(fcaPaddingTop,aTop,[flcNoNegative]) then
|
|
|
|
+ exit(false);
|
|
|
|
+ if (aRight<>'') and not CheckCSSLength(fcaPaddingRight,aRight,[flcNoNegative]) then
|
|
|
|
+ exit(false);
|
|
|
|
+ if (aBottom<>'') and not CheckCSSLength(fcaPaddingBottom,aBottom,[flcNoNegative]) then
|
|
|
|
+ exit(false);
|
|
|
|
+ if (aLeft<>'') and not CheckCSSLength(fcaPaddingLeft,aBottom,[flcNoNegative]) then
|
|
|
|
+ exit(false);
|
|
|
|
+ end else begin
|
|
|
|
+ if aRight='' then
|
|
|
|
+ aRight:=aTop;
|
|
|
|
+ if aBottom='' then
|
|
|
|
+ aBottom:=aTop;
|
|
|
|
+ if aLeft='' then
|
|
|
|
+ aLeft:=aRight;
|
|
|
|
+ SetCSSElAttribute(fcaPaddingLeft,aLeft);
|
|
|
|
+ SetCSSElAttribute(fcaPaddingTop,aTop);
|
|
|
|
+ SetCSSElAttribute(fcaPaddingRight,aRight);
|
|
|
|
+ SetCSSElAttribute(fcaPaddingBottom,aBottom);
|
|
|
|
+ end;
|
|
|
|
+ Result:=true;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TFresnelElement.CheckCSSVisibility(const AValue: string): boolean;
|
|
|
|
+begin
|
|
|
|
+ case AValue of
|
|
|
|
+ 'visible',
|
|
|
|
+ 'hidden',
|
|
|
|
+ 'collapse': Result:=true;
|
|
|
|
+ else
|
|
|
|
+ CSSInvalidValueWarning(20221031131529,fcaVisibility,AValue);
|
|
|
|
+ Result:=false;
|
|
|
|
+ end;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TFresnelElement.CheckCSSBackgroundColor(const AValue: string): boolean;
|
|
|
|
+var
|
|
|
|
+ aColor: TFPColor;
|
|
|
|
+begin
|
|
|
|
+ // ToDo: rgb(r,g,b), rgba(r,g,b,a)
|
|
|
|
+ // ToDo: hsl(), hsla()
|
|
|
|
+ // ToDo: transparent
|
|
|
|
+ // ToDo: currentcolor
|
|
|
|
+ Result:=TryHtmlToFPColor(AValue,aColor);
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TFresnelElement.GetComputedCSSValue(AttrID: TCSSNumericalID
|
|
|
|
+ ): TCSSString;
|
|
|
|
+var
|
|
|
|
+ Attr: TFresnelCSSAttribute;
|
|
|
|
+begin
|
|
|
|
+ if (AttrID<FFresnelElementBaseAttrID) or (AttrID>ord(High(TFresnelCSSAttribute))+FFresnelElementBaseAttrID) then
|
|
|
|
+ exit('');
|
|
|
|
+ Attr:=TFresnelCSSAttribute(AttrID-FFresnelElementBaseAttrID);
|
|
|
|
+ Result:=FCSSComputed[Attr];
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+procedure TFresnelElement.SetComputedCSSValue(AttrID: TCSSNumericalID;
|
|
|
|
+ const Value: TCSSString);
|
|
|
|
+var
|
|
|
|
+ Attr: TFresnelCSSAttribute;
|
|
|
|
+begin
|
|
|
|
+ if (AttrID<FFresnelElementBaseAttrID) or (AttrID>ord(High(TFresnelCSSAttribute))+FFresnelElementBaseAttrID) then
|
|
|
|
+ exit;
|
|
|
|
+ Attr:=TFresnelCSSAttribute(AttrID-FFresnelElementBaseAttrID);
|
|
|
|
+ FCSSComputed[Attr]:=Value;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+procedure TFresnelElement.SetParent(const AValue: TFresnelElement);
|
|
|
|
+begin
|
|
|
|
+ if FParent=AValue then Exit;
|
|
|
|
+ if AValue=Self then
|
|
|
|
+ raise Exception.Create('cycle');
|
|
|
|
+
|
|
|
|
+ if FParent<>nil then
|
|
|
|
+ begin
|
|
|
|
+ FParent.FChildren.Remove(Self);
|
|
|
|
+ end;
|
|
|
|
+ FParent:=AValue;
|
|
|
|
+ if FParent<>nil then
|
|
|
|
+ begin
|
|
|
|
+ FParent.FChildren.Add(Self);
|
|
|
|
+ FreeNotification(FParent);
|
|
|
|
+ end;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+procedure TFresnelElement.SetStyle(const AValue: string);
|
|
|
|
+var
|
|
|
|
+ ss: TStringStream;
|
|
|
|
+ aParser: TCSSParser;
|
|
|
|
+begin
|
|
|
|
+ if FStyle=AValue then Exit;
|
|
|
|
+ FStyle:=AValue;
|
|
|
|
+ FreeAndNil(FStyleElements);
|
|
|
|
+ aParser:=nil;
|
|
|
|
+ ss:=TStringStream.Create(Style);
|
|
|
|
+ try
|
|
|
|
+ aParser:=TCSSParser.Create(ss);
|
|
|
|
+ FStyleElements:=aParser.ParseInline;
|
|
|
|
+ finally
|
|
|
|
+ aParser.Free;
|
|
|
|
+ end;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+procedure TFresnelElement.SetStyleElements(const AValue: TCSSElement);
|
|
|
|
+begin
|
|
|
|
+ if FStyleElements=AValue then Exit;
|
|
|
|
+ FreeAndNil(FStyleElements);
|
|
|
|
+ FStyleElements:=AValue;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+class function TFresnelElement.RegisterCSSType(const aName: string
|
|
|
|
+ ): TCSSNumericalID;
|
|
|
|
+var
|
|
|
|
+ Old: LongInt;
|
|
|
|
+ Map: TCSSNumericalIDs;
|
|
|
|
+begin
|
|
|
|
+ Map:=FCSSNumericalIDs[nikType];
|
|
|
|
+ Old:=Map[aName];
|
|
|
|
+ if Old>0 then
|
|
|
|
+ raise Exception.Create('TFresnelElement.RegisterCSSIDType type duplicate "'+aName+'"');
|
|
|
|
+ Result:=CSSLastTypeID+100+Map.Count;
|
|
|
|
+ //writeln('TFresnelElement.RegisterCSSType ',ClassName,' aName=',aName,' Result=',Result);
|
|
|
|
+ Map[aName]:=Result;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+class function TFresnelElement.RegisterCSSAttr(const aName: string
|
|
|
|
+ ): TCSSNumericalID;
|
|
|
|
+var
|
|
|
|
+ Old: LongInt;
|
|
|
|
+ Map: TCSSNumericalIDs;
|
|
|
|
+begin
|
|
|
|
+ Map:=FCSSNumericalIDs[nikAttribute];
|
|
|
|
+ Old:=Map[aName];
|
|
|
|
+ if Old>0 then
|
|
|
|
+ raise Exception.Create('TFresnelElement.RegisterCSSAttr type duplicate "'+aName+'"');
|
|
|
|
+ Result:=CSSLastAttributeID+100+Map.Count;
|
|
|
|
+ Map[aName]:=Result;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+class function TFresnelElement.RegisterCSSPseudo(const aName: string
|
|
|
|
+ ): TCSSNumericalID;
|
|
|
|
+var
|
|
|
|
+ Old: LongInt;
|
|
|
|
+ Map: TCSSNumericalIDs;
|
|
|
|
+begin
|
|
|
|
+ Map:=FCSSNumericalIDs[nikPseudoAttribute];
|
|
|
|
+ Old:=Map[aName];
|
|
|
|
+ if Old>0 then
|
|
|
|
+ raise Exception.Create('TFresnelElement.RegisterCSSPseudo type duplicate "'+aName+'"');
|
|
|
|
+ Result:=CSSLastPseudoID+100+Map.Count;
|
|
|
|
+ Map[aName]:=Result;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+procedure TFresnelElement.InitCSSResolver(aResolver: TCSSResolver);
|
|
|
|
+var
|
|
|
|
+ Kind: TCSSNumericalIDKind;
|
|
|
|
+begin
|
|
|
|
+ for Kind in TCSSNumericalIDKind do
|
|
|
|
+ aResolver.NumericalIDs[Kind]:=FCSSNumericalIDs[Kind];
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+procedure TFresnelElement.Notification(AComponent: TComponent;
|
|
|
|
+ Operation: TOperation);
|
|
|
|
+begin
|
|
|
|
+ inherited Notification(AComponent, Operation);
|
|
|
|
+ if AComponent=Self then exit;
|
|
|
|
+ if Operation=opRemove then
|
|
|
|
+ begin
|
|
|
|
+ if FChildren<>nil then
|
|
|
|
+ FChildren.Remove(AComponent);
|
|
|
|
+ end;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TFresnelElement.CSSReadNextValue(const aValue: string; var p: integer
|
|
|
|
+ ): string;
|
|
|
|
+var
|
|
|
|
+ l: SizeInt;
|
|
|
|
+ StartP: Integer;
|
|
|
|
+begin
|
|
|
|
+ Result:='';
|
|
|
|
+ l:=length(aValue);
|
|
|
|
+ if p>l then exit;
|
|
|
|
+ while (p<=l) and (aValue[p] in [' ',#9,#10,#13]) do inc(p);
|
|
|
|
+ StartP:=p;
|
|
|
|
+ while (p<=l) and not (aValue[p] in [' ',#9,#10,#13]) do inc(p);
|
|
|
|
+ Result:=copy(aValue,StartP,p-StartP);
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+procedure TFresnelElement.CSSWarning(const ID: int64; Msg: string);
|
|
|
|
+begin
|
|
|
|
+ if FCSSPosElement<>nil then
|
|
|
|
+ Msg:=FCSSPosElement.SourceFileName+'('+IntToStr(FCSSPosElement.SourceRow)+','+IntToStr(FCSSPosElement.SourceCol)+') '+Msg;
|
|
|
|
+ Msg:=Msg+'['+IntToStr(ID)+'] '+Msg;
|
|
|
|
+ DebugLn(['TFresnelElement.CSSError ',Msg]);
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+procedure TFresnelElement.CSSInvalidValueWarning(const ID: int64;
|
|
|
|
+ Attr: TFresnelCSSAttribute; const aValue: string);
|
|
|
|
+begin
|
|
|
|
+ CSSWarning(ID,'invalid '+FresnelCSSAttributeNames[Attr]+' value "'+AValue+'"');
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TFresnelElement.CheckCSSLength(Attr: TFresnelCSSAttribute;
|
|
|
|
+ const AValue: string; const Checks: TFresnelLengthChecks): boolean;
|
|
|
|
+var
|
|
|
|
+ p, StartP: PChar;
|
|
|
|
+begin
|
|
|
|
+ Result:=false;
|
|
|
|
+ if AValue='auto' then
|
|
|
|
+ Result:=true
|
|
|
|
+ else if AValue='' then
|
|
|
|
+ CSSWarning(20221016220554,'missing '+FresnelCSSAttributeNames[Attr]+' value')
|
|
|
|
+ else begin
|
|
|
|
+ // <float><unit>
|
|
|
|
+ StartP:=PChar(AValue);
|
|
|
|
+ p:=StartP;
|
|
|
|
+ if p^='-' then
|
|
|
|
+ begin
|
|
|
|
+ if flcNoNegative in Checks then
|
|
|
|
+ begin
|
|
|
|
+ CSSInvalidValueWarning(20221103222222,Attr,AValue);
|
|
|
|
+ exit;
|
|
|
|
+ end;
|
|
|
|
+ inc(p);
|
|
|
|
+ end;
|
|
|
|
+ if not (p^ in ['0'..'9']) then
|
|
|
|
+ begin
|
|
|
|
+ CSSInvalidValueWarning(20221016220901,Attr,AValue);
|
|
|
|
+ exit;
|
|
|
|
+ end;
|
|
|
|
+ inc(p);
|
|
|
|
+ while p^ in ['0'..'9'] do inc(p);
|
|
|
|
+ if p^='.' then
|
|
|
|
+ begin
|
|
|
|
+ // float
|
|
|
|
+ if flcInteger in Checks then
|
|
|
|
+ begin
|
|
|
|
+ CSSInvalidValueWarning(20221103222126,Attr,AValue);
|
|
|
|
+ exit;
|
|
|
|
+ end;
|
|
|
|
+ inc(p);
|
|
|
|
+ if not (p^ in ['0'..'9']) then
|
|
|
|
+ begin
|
|
|
|
+ CSSInvalidValueWarning(20221016221010,Attr,AValue);
|
|
|
|
+ exit;
|
|
|
|
+ end;
|
|
|
|
+ inc(p);
|
|
|
|
+ while p^ in ['0'..'9'] do inc(p);
|
|
|
|
+ end;
|
|
|
|
+ if (p^ in ['e','E']) and (p[1] in ['-','0'..'9']) then
|
|
|
|
+ begin
|
|
|
|
+ // exponent
|
|
|
|
+ if flcInteger in Checks then
|
|
|
|
+ begin
|
|
|
|
+ CSSInvalidValueWarning(20221103222139,Attr,AValue);
|
|
|
|
+ exit;
|
|
|
|
+ end;
|
|
|
|
+ inc(p);
|
|
|
|
+ if p^='-' then
|
|
|
|
+ inc(p);
|
|
|
|
+ if not (p^ in ['0'..'9']) then
|
|
|
|
+ begin
|
|
|
|
+ CSSInvalidValueWarning(20221016220901,Attr,AValue);
|
|
|
|
+ exit;
|
|
|
|
+ end;
|
|
|
|
+ inc(p);
|
|
|
|
+ while p^ in ['0'..'9'] do inc(p);
|
|
|
|
+ end;
|
|
|
|
+
|
|
|
|
+ case p^ of
|
|
|
|
+ '%':
|
|
|
|
+ begin
|
|
|
|
+ if flcNoPercentage in Checks then
|
|
|
|
+ begin
|
|
|
|
+ CSSInvalidValueWarning(20221103222155,Attr,AValue);
|
|
|
|
+ exit;
|
|
|
|
+ end;
|
|
|
|
+ inc(p);
|
|
|
|
+ end;
|
|
|
|
+ 'c':
|
|
|
|
+ case p[1] of
|
|
|
|
+ 'm','h': inc(p,2); // cm, ch
|
|
|
|
+ end;
|
|
|
|
+ 'e':
|
|
|
|
+ case p[1] of
|
|
|
|
+ 'm','x': inc(p,2); // em, ex
|
|
|
|
+ end;
|
|
|
|
+ 'i':
|
|
|
|
+ if p[1]='n' then
|
|
|
|
+ inc(p,2); // in
|
|
|
|
+ 'm':
|
|
|
|
+ if p[1]='m' then
|
|
|
|
+ inc(p,2); // mm
|
|
|
|
+ 'p':
|
|
|
|
+ case p[1] of
|
|
|
|
+ 'x','t','c': inc(p,2); // px, pt, pc
|
|
|
|
+ end;
|
|
|
|
+ 'r':
|
|
|
|
+ if (p[1]='e') and (p[2]='m') then inc(p,3);
|
|
|
|
+ 'v':
|
|
|
|
+ case p[1] of
|
|
|
|
+ 'w','h': inc(p,2); // vw, vh
|
|
|
|
+ 'm':
|
|
|
|
+ case p[2] of
|
|
|
|
+ 'a': if p[3]='x' then inc(p,4);
|
|
|
|
+ 'i': if p[3]='n' then inc(p,4);
|
|
|
|
+ end;
|
|
|
|
+ end;
|
|
|
|
+ end;
|
|
|
|
+ // note: no unit is ok
|
|
|
|
+ if p-StartP<>length(AValue) then
|
|
|
|
+ CSSInvalidValueWarning(20221016221747,Attr,AValue)
|
|
|
|
+ else
|
|
|
|
+ Result:=true;
|
|
|
|
+ end;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+procedure TFresnelElement.ComputeCSSAttribute(Attr: TFresnelCSSAttribute);
|
|
|
|
+var
|
|
|
|
+ aValue: String;
|
|
|
|
+begin
|
|
|
|
+ aValue:=FCSSAttributes[Attr];
|
|
|
|
+ if aValue='initial' then
|
|
|
|
+ aValue:=GetCSSInitialAttribute(ElementAttrToAttrId(Attr));
|
|
|
|
+ if aValue='inherit' then
|
|
|
|
+ aValue:=GetCSSInheritAttribute(ElementAttrToAttrId(Attr));
|
|
|
|
+ if aValue='unset' then
|
|
|
|
+ aValue:='';
|
|
|
|
+ FCSSComputed[Attr]:=aValue;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TFresnelElement.GetDPI(IsHorizontal: boolean): TFresnelLength;
|
|
|
|
+begin
|
|
|
|
+ if Parent<>nil then
|
|
|
|
+ Result:=Parent.GetDPI(IsHorizontal)
|
|
|
|
+ else
|
|
|
|
+ Result:=FresnelDefaultDPI;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TFresnelElement.GetViewport: TFresnelViewport;
|
|
|
|
+var
|
|
|
|
+ El: TFresnelElement;
|
|
|
|
+begin
|
|
|
|
+ El:=GetRoot;
|
|
|
|
+ if El is TFresnelViewport then
|
|
|
|
+ Result:=TFresnelViewport(El)
|
|
|
|
+ else
|
|
|
|
+ Result:=nil;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TFresnelElement.GetComputedCSSLength(Attr: TFresnelCSSAttribute;
|
|
|
|
+ UseInherited: boolean; UseNaNOnFail: boolean): TFresnelLength;
|
|
|
|
+var
|
|
|
|
+ El: TFresnelElement;
|
|
|
|
+ s: String;
|
|
|
|
+begin
|
|
|
|
+ if CSSStrToFloat(FCSSComputed[Attr],Result) then
|
|
|
|
+ exit;
|
|
|
|
+ if UseInherited then
|
|
|
|
+ begin
|
|
|
|
+ El:=Parent;
|
|
|
|
+ while El<>nil do
|
|
|
|
+ begin
|
|
|
|
+ if CSSStrToFloat(El.FCSSComputed[Attr],Result) then
|
|
|
|
+ exit;
|
|
|
|
+ El:=El.Parent;
|
|
|
|
+ end;
|
|
|
|
+ end;
|
|
|
|
+ s:=GetCSSInitialAttribute(ElementAttrToAttrId(Attr));
|
|
|
|
+ if CSSStrToFloat(s,Result) then
|
|
|
|
+ exit;
|
|
|
|
+ if UseNaNOnFail then
|
|
|
|
+ Result:=NaN
|
|
|
|
+ else
|
|
|
|
+ Result:=0;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TFresnelElement.GetComputedCSString(Attr: TFresnelCSSAttribute;
|
|
|
|
+ UseInherited: boolean): string;
|
|
|
|
+var
|
|
|
|
+ El: TFresnelElement;
|
|
|
|
+begin
|
|
|
|
+ Result:=FCSSComputed[Attr];
|
|
|
|
+ if Result<>'' then exit;
|
|
|
|
+ if UseInherited then
|
|
|
|
+ begin
|
|
|
|
+ El:=Parent;
|
|
|
|
+ while El<>nil do
|
|
|
|
+ begin
|
|
|
|
+ Result:=El.CSSComputedAttribute[Attr];
|
|
|
|
+ if Result<>'' then
|
|
|
|
+ exit;
|
|
|
|
+ El:=El.Parent;
|
|
|
|
+ end;
|
|
|
|
+ end;
|
|
|
|
+ Result:=GetCSSInitialAttribute(ElementAttrToAttrId(Attr));
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+procedure TFresnelElement.WriteComputedAttributes(Title: string);
|
|
|
|
+var
|
|
|
|
+ Attr: TFresnelCSSAttribute;
|
|
|
|
+begin
|
|
|
|
+ writeln('TFresnelElement.WriteComputedAttributes ',Title,' ',GetPath,'================');
|
|
|
|
+ for Attr in TFresnelCSSAttribute do
|
|
|
|
+ if FCSSComputed[Attr]<>'' then
|
|
|
|
+ writeln(' ',Attr,'="',FCSSComputed[Attr],'"');
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TFresnelElement.GetMaxWidthIntrinsicContentBox: TFresnelLength;
|
|
|
|
+begin
|
|
|
|
+ Result:=GetViewport.MaxPreferredWidth;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TFresnelElement.GetMaxWidthContentBox: TFresnelLength;
|
|
|
|
+var
|
|
|
|
+ aValue: String;
|
|
|
|
+begin
|
|
|
|
+ aValue:=CSSComputedAttribute[fcaMinWidth];
|
|
|
|
+ case aValue of
|
|
|
|
+ '',
|
|
|
|
+ 'auto': Result:=GetMaxWidthIntrinsicContentBox;
|
|
|
|
+ 'max-content': Result:=GetPreferredContentBox_MaxWidth(GetViewport.MaxPreferredWidth).X;
|
|
|
|
+ 'min-content': Result:=GetMinWidthIntrinsicContentBox;
|
|
|
|
+ else
|
|
|
|
+ Result:=GetComputedCSSLength(fcaMaxWidth,false);
|
|
|
|
+ end;
|
|
|
|
+ if Result<0 then
|
|
|
|
+ Result:=0;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TFresnelElement.GetMaxWidthBorderBox: TFresnelLength;
|
|
|
|
+begin
|
|
|
|
+ // border and padding cannot be negative
|
|
|
|
+ Result:=GetComputedCSSLength(fcaBorderLeft,false)
|
|
|
|
+ +GetComputedCSSLength(fcaBorderRight,false)
|
|
|
|
+ +GetComputedCSSLength(fcaPaddingLeft,false)
|
|
|
|
+ +GetComputedCSSLength(fcaPaddingRight,false)
|
|
|
|
+ +GetMinWidthContentBox;
|
|
|
|
+ if IsNan(Result) or (Result<0) then
|
|
|
|
+ Result:=0;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TFresnelElement.GetMinWidthIntrinsicContentBox: TFresnelLength;
|
|
|
|
+begin
|
|
|
|
+ Result:=0;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TFresnelElement.GetMinWidthContentBox: TFresnelLength;
|
|
|
|
+var
|
|
|
|
+ aValue: String;
|
|
|
|
+begin
|
|
|
|
+ aValue:=CSSComputedAttribute[fcaMinWidth];
|
|
|
|
+ case aValue of
|
|
|
|
+ '',
|
|
|
|
+ 'auto': Result:=GetMinWidthIntrinsicContentBox;
|
|
|
|
+ 'max-content': Result:=GetPreferredContentBox_MaxWidth(GetViewport.MaxPreferredWidth).X;
|
|
|
|
+ 'min-content': Result:=GetMinWidthIntrinsicContentBox;
|
|
|
|
+ else
|
|
|
|
+ Result:=GetComputedCSSLength(fcaMinWidth,false);
|
|
|
|
+ end;
|
|
|
|
+ if Result<0 then
|
|
|
|
+ Result:=0;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TFresnelElement.GetMinWidthBorderBox: TFresnelLength;
|
|
|
|
+begin
|
|
|
|
+ // border and padding cannot be negative
|
|
|
|
+ Result:=GetComputedCSSLength(fcaBorderLeft,false)
|
|
|
|
+ +GetComputedCSSLength(fcaBorderRight,false)
|
|
|
|
+ +GetComputedCSSLength(fcaPaddingLeft,false)
|
|
|
|
+ +GetComputedCSSLength(fcaPaddingRight,false)
|
|
|
|
+ +GetMinWidthContentBox;
|
|
|
|
+ if Result<0 then
|
|
|
|
+ Result:=0;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TFresnelElement.GetPreferredContentBox_MaxWidth(
|
|
|
|
+ MaxWidth: TFresnelLength): TFresnelPoint;
|
|
|
|
+begin
|
|
|
|
+ Result:=default(TFresnelPoint);
|
|
|
|
+ if MaxWidth=0 then ;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TFresnelElement.GetPreferredBorderBox_MaxWidth(MaxWidth: TFresnelLength
|
|
|
|
+ ): TFresnelPoint;
|
|
|
|
+var
|
|
|
|
+ ExtraWidth, ExtraHeight: TFresnelLength;
|
|
|
|
+begin
|
|
|
|
+ // border and padding cannot be negative
|
|
|
|
+ ExtraWidth:=GetComputedCSSLength(fcaBorderLeft,false)
|
|
|
|
+ +GetComputedCSSLength(fcaBorderRight,false)
|
|
|
|
+ +GetComputedCSSLength(fcaPaddingLeft,false)
|
|
|
|
+ +GetComputedCSSLength(fcaPaddingRight,false);
|
|
|
|
+ ExtraHeight:=GetComputedCSSLength(fcaBorderTop,false)
|
|
|
|
+ +GetComputedCSSLength(fcaBorderBottom,false)
|
|
|
|
+ +GetComputedCSSLength(fcaPaddingTop,false)
|
|
|
|
+ +GetComputedCSSLength(fcaPaddingBottom,false);
|
|
|
|
+ Result:=GetPreferredContentBox_MaxWidth(Max(0,MaxWidth-ExtraWidth));
|
|
|
|
+ Result.X:=Result.X+ExtraWidth;
|
|
|
|
+ Result.Y:=Result.Y+ExtraHeight;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TFresnelElement.ElementAttrToAttrId(Attr: TFresnelCSSAttribute
|
|
|
|
+ ): TCSSNumericalID;
|
|
|
|
+begin
|
|
|
|
+ Result:=ord(Attr)+FFresnelElementBaseAttrID;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TFresnelElement.GetFont: IFresnelFont;
|
|
|
|
+var
|
|
|
|
+ ViewPort: TFresnelViewport;
|
|
|
|
+begin
|
|
|
|
+ if FFontDescValid then
|
|
|
|
+ exit(FFont);
|
|
|
|
+ FFontDescValid:=true;
|
|
|
|
+ FFontDesc.Family:=GetComputedCSString(fcaFontFamily,true);
|
|
|
|
+ FFontDesc.Style:=GetComputedCSString(fcaFontStyle,true);
|
|
|
|
+ FFontDesc.Variant_:=GetComputedCSString(fcaFontVariant,true);
|
|
|
|
+ FFontDesc.Weight:=GetComputedCSString(fcaFontWeight,true);
|
|
|
|
+ FFontDesc.Size:=GetComputedCSString(fcaFontSize,true);
|
|
|
|
+ FFontDesc.Kerning:=GetComputedCSString(fcaFontKerning,true);
|
|
|
|
+ if FFont<>nil then
|
|
|
|
+ begin
|
|
|
|
+ if (FFont.GetFamily=FFontDesc.Family)
|
|
|
|
+ and (FFont.GetStyle=FFontDesc.Style)
|
|
|
|
+ and (FFont.GetVariant=FFontDesc.Variant_)
|
|
|
|
+ and (FFont.GetWeight=FFontDesc.Weight)
|
|
|
|
+ and (FFont.GetSize=FFontDesc.Size)
|
|
|
|
+ and (FFont.GetKerning=FFontDesc.Kerning) then
|
|
|
|
+ exit(FFont); // still valid
|
|
|
|
+ FFont:=nil;
|
|
|
|
+ end;
|
|
|
|
+
|
|
|
|
+ ViewPort:=GetViewport;
|
|
|
|
+ FFont:=ViewPort.AllocateFont(FFontDesc);
|
|
|
|
+ Result:=FFont;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TFresnelElement.HasParent: Boolean;
|
|
|
|
+begin
|
|
|
|
+ Result:=Parent<>nil;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+procedure TFresnelElement.SetParentComponent(Value: TComponent);
|
|
|
|
+begin
|
|
|
|
+ if Value is TFresnelElement then
|
|
|
|
+ Parent:=TFresnelElement(Value);
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+procedure TFresnelElement.GetChildren(Proc: TGetChildProc; Root: TComponent);
|
|
|
|
+var
|
|
|
|
+ i: Integer;
|
|
|
|
+begin
|
|
|
|
+ for i:=0 to NodeCount-1 do
|
|
|
|
+ if Nodes[i].Owner=Root then
|
|
|
|
+ Proc(Nodes[i]);
|
|
|
|
+
|
|
|
|
+ if Root = Self then
|
|
|
|
+ for i:=0 to ComponentCount-1 do
|
|
|
|
+ if Components[i].GetParentComponent = nil then
|
|
|
|
+ Proc(Components[i]);
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TFresnelElement.GetParentComponent: TComponent;
|
|
|
|
+begin
|
|
|
|
+ Result:=Parent;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+constructor TFresnelElement.Create(AOwner: TComponent);
|
|
|
|
+begin
|
|
|
|
+ inherited Create(AOwner);
|
|
|
|
+ FChildren:=TFPList.Create;
|
|
|
|
+ FCSSClasses:=TStringList.Create;
|
|
|
|
+ FCSSClasses.Delimiter:=' ';
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+destructor TFresnelElement.Destroy;
|
|
|
|
+begin
|
|
|
|
+ Clear;
|
|
|
|
+ FreeAndNil(FLayoutNode);
|
|
|
|
+ FreeAndNil(FChildren);
|
|
|
|
+ FreeAndNil(FCSSClasses);
|
|
|
|
+ inherited Destroy;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+procedure TFresnelElement.Clear;
|
|
|
|
+var
|
|
|
|
+ i: Integer;
|
|
|
|
+begin
|
|
|
|
+ FCSSClasses.Clear;
|
|
|
|
+ for i:=NodeCount-1 downto 0 do
|
|
|
|
+ Nodes[i].Parent:=nil;
|
|
|
|
+ FChildren.Clear;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TFresnelElement.GetRoot: TFresnelElement;
|
|
|
|
+begin
|
|
|
|
+ Result:=Self;
|
|
|
|
+ while Result.Parent<>nil do
|
|
|
|
+ Result:=Result.Parent;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TFresnelElement.GetPath: string;
|
|
|
|
+begin
|
|
|
|
+ if Parent<>nil then
|
|
|
|
+ Result:=Parent.GetPath+'.'
|
|
|
|
+ else
|
|
|
|
+ Result:='';
|
|
|
|
+ if Name='' then
|
|
|
|
+ Result:=Result+ClassName
|
|
|
|
+ else
|
|
|
|
+ Result:=Result+Name;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+class constructor TFresnelElement.InitFresnelElementClass;
|
|
|
|
+var
|
|
|
|
+ Kind: TCSSNumericalIDKind;
|
|
|
|
+ Attr: TFresnelCSSAttribute;
|
|
|
|
+ id: TCSSNumericalID;
|
|
|
|
+ PseudoAttr: TFresnelCSSPseudo;
|
|
|
|
+begin
|
|
|
|
+ for Kind in TCSSNumericalIDKind do
|
|
|
|
+ begin
|
|
|
|
+ FCSSNumericalIDs[Kind]:=TCSSNumericalIDs.Create(Kind);
|
|
|
|
+ FCSSIDToName[Kind]:=nil;
|
|
|
|
+ FCSSIDToNameCount[Kind]:=0;
|
|
|
|
+ end;
|
|
|
|
+
|
|
|
|
+ // register type
|
|
|
|
+ FFresnelElementTypeID:=RegisterCSSType(CSSTypeName);
|
|
|
|
+
|
|
|
|
+ // register attributes
|
|
|
|
+ FFresnelElementBaseAttrID:=CSSIDNone;
|
|
|
|
+ for Attr in TFresnelCSSAttribute do
|
|
|
|
+ begin
|
|
|
|
+ id:=RegisterCSSAttr(FresnelCSSAttributeNames[Attr]);
|
|
|
|
+ if FFresnelElementBaseAttrID=CSSIDNone then
|
|
|
|
+ FFresnelElementBaseAttrID:=id;
|
|
|
|
+ end;
|
|
|
|
+
|
|
|
|
+ // register pseudo attributes
|
|
|
|
+ FFresnelElementBasePseudoID:=CSSIDNone;
|
|
|
|
+ for PseudoAttr in TFresnelCSSPseudo do
|
|
|
|
+ begin
|
|
|
|
+ id:=RegisterCSSPseudo(FresnelCSSPseudoNames[PseudoAttr]);
|
|
|
|
+ if FFresnelElementBasePseudoID=CSSIDNone then
|
|
|
|
+ FFresnelElementBasePseudoID:=id;
|
|
|
|
+ end;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+class destructor TFresnelElement.FinalFresnelElementClass;
|
|
|
|
+var
|
|
|
|
+ Kind: TCSSNumericalIDKind;
|
|
|
|
+begin
|
|
|
|
+ for Kind in TCSSNumericalIDKind do
|
|
|
|
+ begin
|
|
|
|
+ FreeAndNil(FCSSNumericalIDs[Kind]);
|
|
|
|
+ FCSSIDToName[Kind]:=nil;
|
|
|
|
+ FCSSIDToNameCount[Kind]:=0;
|
|
|
|
+ end;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+class function TFresnelElement.CSSTypeID: TCSSNumericalID;
|
|
|
|
+begin
|
|
|
|
+ Result:=FFresnelElementTypeID;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+class function TFresnelElement.CSSTypeName: TCSSString;
|
|
|
|
+begin
|
|
|
|
+ Result:='element';
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+procedure TFresnelElement.ClearCSSValues;
|
|
|
|
+var
|
|
|
|
+ Attr: TFresnelCSSAttribute;
|
|
|
|
+ i: Integer;
|
|
|
|
+begin
|
|
|
|
+ for Attr in TFresnelCSSAttribute do
|
|
|
|
+ begin
|
|
|
|
+ FCSSAttributes[Attr]:='';
|
|
|
|
+ FCSSComputed[Attr]:='';
|
|
|
|
+ end;
|
|
|
|
+ for i:=0 to NodeCount-1 do
|
|
|
|
+ Nodes[i].ClearCSSValues;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TFresnelElement.GetCSSAttribute(const AttrID: TCSSNumericalID
|
|
|
|
+ ): TCSSString;
|
|
|
|
+var
|
|
|
|
+ Attr: TFresnelCSSAttribute;
|
|
|
|
+begin
|
|
|
|
+ if (AttrID<FFresnelElementBaseAttrID) or (AttrID>FFresnelElementBaseAttrID+ord(High(TFresnelCSSAttribute))) then
|
|
|
|
+ exit('');
|
|
|
|
+ Attr:=TFresnelCSSAttribute(AttrID-FFresnelElementBaseAttrID);
|
|
|
|
+ Result:=CSSAttribute[Attr];
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TFresnelElement.GetCSSAttributeClass: TCSSString;
|
|
|
|
+begin
|
|
|
|
+ FCSSClasses.Delimiter:=' ';
|
|
|
|
+ Result:=FCSSClasses.DelimitedText;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TFresnelElement.GetCSSChild(const anIndex: integer): ICSSNode;
|
|
|
|
+begin
|
|
|
|
+ Result:=Nodes[anIndex];
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TFresnelElement.GetCSSChildCount: integer;
|
|
|
|
+begin
|
|
|
|
+ Result:=NodeCount;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TFresnelElement.GetCSSDepth: integer;
|
|
|
|
+var
|
|
|
|
+ aChild: TFresnelElement;
|
|
|
|
+begin
|
|
|
|
+ // ToDo: store
|
|
|
|
+ Result:=0;
|
|
|
|
+ aChild:=Parent;
|
|
|
|
+ while aChild<>nil do
|
|
|
|
+ begin
|
|
|
|
+ inc(Result);
|
|
|
|
+ aChild:=aChild.Parent;
|
|
|
|
+ end;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TFresnelElement.GetCSSEmpty: boolean;
|
|
|
|
+begin
|
|
|
|
+ Result:=NodeCount=0;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TFresnelElement.GetCSSID: TCSSString;
|
|
|
|
+begin
|
|
|
|
+ Result:=Name;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TFresnelElement.GetCSSIndex: integer;
|
|
|
|
+begin
|
|
|
|
+ // ToDo: store
|
|
|
|
+ if Parent=nil then
|
|
|
|
+ Result:=-1
|
|
|
|
+ else
|
|
|
|
+ Result:=Parent.FChildren.IndexOf(Self);
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TFresnelElement.GetCSSNextOfType: ICSSNode;
|
|
|
|
+var
|
|
|
|
+ i, Cnt: Integer;
|
|
|
|
+ MyID: TCSSNumericalID;
|
|
|
|
+ aChild: TFresnelElement;
|
|
|
|
+begin
|
|
|
|
+ Result:=nil;
|
|
|
|
+ i:=GetCSSIndex;
|
|
|
|
+ if i<0 then exit;
|
|
|
|
+ inc(i);
|
|
|
|
+ MyID:=CSSTypeID;
|
|
|
|
+ Cnt:=Parent.NodeCount;
|
|
|
|
+ while i<Cnt do
|
|
|
|
+ begin
|
|
|
|
+ aChild:=Parent[i];
|
|
|
|
+ if aChild.CSSTypeID=MyID then
|
|
|
|
+ exit(aChild);
|
|
|
|
+ inc(i);
|
|
|
|
+ end;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TFresnelElement.GetCSSNextSibling: ICSSNode;
|
|
|
|
+var
|
|
|
|
+ i: Integer;
|
|
|
|
+begin
|
|
|
|
+ i:=GetCSSIndex;
|
|
|
|
+ if (i<0) or (i+1>=Parent.NodeCount) then
|
|
|
|
+ Result:=nil
|
|
|
|
+ else
|
|
|
|
+ Result:=Parent[i+1];
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TFresnelElement.GetCSSParent: ICSSNode;
|
|
|
|
+begin
|
|
|
|
+ Result:=Parent;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TFresnelElement.GetCSSPreviousOfType: ICSSNode;
|
|
|
|
+var
|
|
|
|
+ i: Integer;
|
|
|
|
+ MyID: TCSSNumericalID;
|
|
|
|
+ aChild: TFresnelElement;
|
|
|
|
+begin
|
|
|
|
+ Result:=nil;
|
|
|
|
+ i:=GetCSSIndex;
|
|
|
|
+ if i<0 then exit;
|
|
|
|
+ dec(i);
|
|
|
|
+ MyID:=CSSTypeID;
|
|
|
|
+ while i>=0 do
|
|
|
|
+ begin
|
|
|
|
+ aChild:=Parent[i];
|
|
|
|
+ if aChild.CSSTypeID=MyID then
|
|
|
|
+ exit(aChild);
|
|
|
|
+ dec(i);
|
|
|
|
+ end;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TFresnelElement.GetCSSPreviousSibling: ICSSNode;
|
|
|
|
+var
|
|
|
|
+ i: Integer;
|
|
|
|
+begin
|
|
|
|
+ i:=GetCSSIndex;
|
|
|
|
+ if i<1 then
|
|
|
|
+ Result:=nil
|
|
|
|
+ else
|
|
|
|
+ Result:=Parent[i-1];
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TFresnelElement.GetCSSPseudo(const AttrID: TCSSNumericalID
|
|
|
|
+ ): TCSSString;
|
|
|
|
+var
|
|
|
|
+ Pseudo: TFresnelCSSPseudo;
|
|
|
|
+begin
|
|
|
|
+ if (AttrID<FFresnelElementBasePseudoID) or (AttrID>FFresnelElementBasePseudoID+ord(High(TFresnelCSSPseudo))) then
|
|
|
|
+ exit('');
|
|
|
|
+ Pseudo:=TFresnelCSSPseudo(AttrID-FFresnelElementBasePseudoID);
|
|
|
|
+ Result:=CSSPseudo[Pseudo];
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TFresnelElement.GetCSSTypeID: TCSSNumericalID;
|
|
|
|
+begin
|
|
|
|
+ Result:=CSSTypeID;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TFresnelElement.GetCSSTypeName: TCSSString;
|
|
|
|
+begin
|
|
|
|
+ Result:=CSSTypeName;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TFresnelElement.HasCSSAttribute(const AttrID: TCSSNumericalID
|
|
|
|
+ ): boolean;
|
|
|
|
+begin
|
|
|
|
+ Result:=(AttrID>=FFresnelElementBaseAttrID) and (AttrID<=FFresnelElementBaseAttrID+ord(High(TFresnelCSSAttribute)));
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TFresnelElement.HasCSSClass(const aClassName: TCSSString): boolean;
|
|
|
|
+var
|
|
|
|
+ i: Integer;
|
|
|
|
+begin
|
|
|
|
+ for i:=0 to CSSClasses.Count-1 do
|
|
|
|
+ if aClassName=CSSClasses[i] then
|
|
|
|
+ exit(true);
|
|
|
|
+ Result:=false;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TFresnelElement.HasCSSPseudo(const AttrID: TCSSNumericalID
|
|
|
|
+ ): boolean;
|
|
|
|
+begin
|
|
|
|
+ Result:=(AttrID>=FFresnelElementBasePseudoID) and (AttrID<=FFresnelElementBasePseudoID+ord(High(TFresnelCSSPseudo)));
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+procedure TFresnelElement.SetCSSValue(AttrID: TCSSNumericalID;
|
|
|
|
+ Value: TCSSElement);
|
|
|
|
+var
|
|
|
|
+ Attr: TFresnelCSSAttribute;
|
|
|
|
+ s: TCSSString;
|
|
|
|
+begin
|
|
|
|
+ if (AttrID<FFresnelElementBaseAttrID) or (AttrID>ord(High(TFresnelCSSAttribute))+FFresnelElementBaseAttrID) then
|
|
|
|
+ raise Exception.Create('TFresnelElement.SetCSSValue invalid AttrID '+IntToStr(AttrID));
|
|
|
|
+ Attr:=TFresnelCSSAttribute(AttrID-FFresnelElementBaseAttrID);
|
|
|
|
+ s:=Value.AsString;
|
|
|
|
+ {$IFDEF VerboseCSSResolver}
|
|
|
|
+ writeln('TFresnelElement.SetCSSValue ',FresnelAttributeNames[Attr],':="',s,'"');
|
|
|
|
+ {$ENDIF}
|
|
|
|
+ FCSSPosElement:=Value;
|
|
|
|
+ try
|
|
|
|
+ CSSAttribute[Attr]:=s;
|
|
|
|
+ finally
|
|
|
|
+ FCSSPosElement:=nil;
|
|
|
|
+ end;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TFresnelElement.CheckCSSValue(AttrID: TCSSNumericalID;
|
|
|
|
+ Value: TCSSElement): boolean;
|
|
|
|
+var
|
|
|
|
+ Attr: TFresnelCSSAttribute;
|
|
|
|
+ s: TCSSString;
|
|
|
|
+begin
|
|
|
|
+ if (AttrID<FFresnelElementBaseAttrID) or (AttrID>ord(High(TFresnelCSSAttribute))+FFresnelElementBaseAttrID) then
|
|
|
|
+ raise Exception.Create('TFresnelElement.SetCSSValue invalid AttrID '+IntToStr(AttrID));
|
|
|
|
+ Result:=true;
|
|
|
|
+ Attr:=TFresnelCSSAttribute(AttrID-FFresnelElementBaseAttrID);
|
|
|
|
+ s:=Value.AsString;
|
|
|
|
+ FCSSPosElement:=Value;
|
|
|
|
+ try
|
|
|
|
+ case Attr of
|
|
|
|
+ fcaDisplay: Result:=CheckOrSetCSSDisplay(s,true);
|
|
|
|
+ fcaDisplayBox: Result:=CheckCSSDisplayBox(s);
|
|
|
|
+ fcaDisplayInside: Result:=CheckCSSDisplayInside(s);
|
|
|
|
+ fcaDisplayOutside: Result:=CheckCSSDisplayOutside(s);
|
|
|
|
+ fcaPosition: Result:=CheckCSSPosition(s);
|
|
|
|
+ fcaOverflow: Result:=CheckOrSetCSSOverflow(s,true);
|
|
|
|
+ fcaOverflowX: Result:=CheckCSSOverflowX(s);
|
|
|
|
+ fcaOverflowY: Result:=CheckCSSOverflowY(s);
|
|
|
|
+ fcaZIndex: Result:=CheckCSSZIndex(s);
|
|
|
|
+ fcaClear: Result:=CheckCSSClear(s);
|
|
|
|
+ fcaDirection: Result:=CheckCSSDirection(s);
|
|
|
|
+ fcaLeft,
|
|
|
|
+ fcaTop,
|
|
|
|
+ fcaRight,
|
|
|
|
+ fcaBottom,
|
|
|
|
+ fcaWidth,
|
|
|
|
+ fcaHeight: Result:=CheckCSSLength(Attr,s,[flcNoNegative]);
|
|
|
|
+ fcaBorder: Result:=CheckOrSetCSSBorder(s,true);
|
|
|
|
+ fcaBorderLeft: Result:=CheckOrSetCSSBorderLeft(s,true);
|
|
|
|
+ fcaBorderRight: Result:=CheckOrSetCSSBorderRight(s,true);
|
|
|
|
+ fcaBorderTop: Result:=CheckOrSetCSSBorderTop(s,true);
|
|
|
|
+ fcaBorderBottom: Result:=CheckOrSetCSSBorderBottom(s,true);
|
|
|
|
+ fcaBorderWidth: Result:=CheckOrSetCSSBorderWidth(s,true);
|
|
|
|
+ fcaBorderLeftWidth,
|
|
|
|
+ fcaBorderRightWidth,
|
|
|
|
+ fcaBorderTopWidth,
|
|
|
|
+ fcaBorderBottomWidth: Result:=CheckCSSBorderXWidth(Attr,s);
|
|
|
|
+ fcaBorderColor: Result:=CheckCSSBorderColor(s);
|
|
|
|
+ fcaBoxSizing: Result:=CheckCSSBoxSizing(s);
|
|
|
|
+ fcaFloat: Result:=CheckCSSFloat(s);
|
|
|
|
+ fcaFont: Result:=CheckCSSFontKerning(s);
|
|
|
|
+ fcaFontFamily: ; //Result:=CheckCSSFontFamily(s);
|
|
|
|
+ fcaFontFeatureSettings: ; //Result:=CheckCSSFontFeatureSettings(s);
|
|
|
|
+ fcaFontKerning: Result:=CheckCSSFontKerning(s);
|
|
|
|
+ fcaFontSize: Result:=CheckCSSFontSize(s);
|
|
|
|
+ fcaFontStyle: Result:=CheckCSSFontStyle(s);
|
|
|
|
+ fcaFontWeight: Result:=CheckCSSFontWeight(s);
|
|
|
|
+ fcaFontVariant: Result:=CheckCSSFontVariant(s);
|
|
|
|
+ fcaLineHeight: Result:=CheckCSSLineHeight(s);
|
|
|
|
+ fcaMargin: Result:=CheckOrSetCSSMargin(s,true);
|
|
|
|
+ fcaMarginLeft,
|
|
|
|
+ fcaMarginTop,
|
|
|
|
+ fcaMarginRight,
|
|
|
|
+ fcaMarginBottom: Result:=CheckCSSLength(Attr,s);
|
|
|
|
+ fcaMarginBlock: Result:=CheckOrSetCSSMarginBlock(s,true);
|
|
|
|
+ fcaMarginBlockEnd,
|
|
|
|
+ fcaMarginBlockStart: Result:=CheckCSSLength(Attr,s);
|
|
|
|
+ fcaMarginInline: Result:=CheckOrSetCSSMarginInline(s,true);
|
|
|
|
+ fcaMarginInlineEnd,
|
|
|
|
+ fcaMarginInlineStart: Result:=CheckCSSLength(Attr,s);
|
|
|
|
+ fcaMinWidth,
|
|
|
|
+ fcaMaxWidth,
|
|
|
|
+ fcaMinHeight,
|
|
|
|
+ fcaMaxHeight: Result:=CheckCSSLength(Attr,s,[flcNoNegative]);
|
|
|
|
+ fcaOpacity: Result:=CheckCSSOpacity(s);
|
|
|
|
+ fcaPadding: Result:=CheckOrSetCSSPadding(s,true);
|
|
|
|
+ fcaPaddingLeft,
|
|
|
|
+ fcaPaddingTop,
|
|
|
|
+ fcaPaddingRight,
|
|
|
|
+ fcaPaddingBottom: Result:=CheckCSSLength(Attr,s,[flcNoNegative]);
|
|
|
|
+ fcaVisibility: Result:=CheckCSSVisibility(s);
|
|
|
|
+ fcaBackgroundColor: Result:=CheckCSSBackgroundColor(s);
|
|
|
|
+ end;
|
|
|
|
+ finally
|
|
|
|
+ FCSSPosElement:=nil;
|
|
|
|
+ end;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TFresnelElement.GetCSSInitialAttribute(const AttrID: TCSSNumericalID
|
|
|
|
+ ): TCSSString;
|
|
|
|
+var
|
|
|
|
+ Attr: TFresnelCSSAttribute;
|
|
|
|
+begin
|
|
|
|
+ if (AttrID<FFresnelElementBaseAttrID) or (AttrID>FFresnelElementBaseAttrID+ord(High(TFresnelCSSAttribute))) then
|
|
|
|
+ exit('');
|
|
|
|
+ Attr:=TFresnelCSSAttribute(AttrID-FFresnelElementBaseAttrID);
|
|
|
|
+ case Attr of
|
|
|
|
+ fcaBorderLeftWidth,
|
|
|
|
+ fcaBorderRightWidth,
|
|
|
|
+ fcaBorderTopWidth,
|
|
|
|
+ fcaBorderBottomWidth: Result:='0';
|
|
|
|
+ fcaMarginLeft,
|
|
|
|
+ fcaMarginTop,
|
|
|
|
+ fcaMarginRight,
|
|
|
|
+ fcaMarginBottom: Result:='0';
|
|
|
|
+ fcaPaddingLeft,
|
|
|
|
+ fcaPaddingTop,
|
|
|
|
+ fcaPaddingRight,
|
|
|
|
+ fcaPaddingBottom: Result:='0';
|
|
|
|
+ else
|
|
|
|
+ Result:='';
|
|
|
|
+ end;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TFresnelElement.GetCSSInheritAttribute(const AttrID: TCSSNumericalID
|
|
|
|
+ ): TCSSString;
|
|
|
|
+var
|
|
|
|
+ El: TFresnelElement;
|
|
|
|
+begin
|
|
|
|
+ El:=Parent;
|
|
|
|
+ while El<>nil do
|
|
|
|
+ begin
|
|
|
|
+ Result:=El.GetCSSAttribute(AttrID);
|
|
|
|
+ if Result<>'' then exit;
|
|
|
|
+ El:=El.Parent;
|
|
|
|
+ end;
|
|
|
|
+ Result:='';
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+procedure TFresnelElement.ComputeCSS;
|
|
|
|
+const
|
|
|
|
+ NormalAttr = [low(TFresnelCSSAttribute)..high(TFresnelCSSAttribute)]
|
|
|
|
+ -[fcaFontFamily,fcaFontSize,fcaFontStyle,fcaFontWeight];
|
|
|
|
+var
|
|
|
|
+ Attr: TFresnelCSSAttribute;
|
|
|
|
+begin
|
|
|
|
+ // lengths can depend on font, so compute it first
|
|
|
|
+ FFontDescValid:=false;
|
|
|
|
+ ComputeCSSAttribute(fcaFontFamily);
|
|
|
|
+ ComputeCSSAttribute(fcaFontSize);
|
|
|
|
+ ComputeCSSAttribute(fcaFontStyle);
|
|
|
|
+ ComputeCSSAttribute(fcaFontWeight);
|
|
|
|
+ for Attr in NormalAttr do
|
|
|
|
+ ComputeCSSAttribute(Attr);
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+end.
|
|
|
|
+
|