11640 lines
368 KiB
ObjectPascal
11640 lines
368 KiB
ObjectPascal
|
{
|
||
|
Version 11.9
|
||
|
Copyright (c) 1995-2008 by L. David Baldwin
|
||
|
Copyright (c) 2008-2018 by HtmlViewer Team
|
||
|
|
||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||
|
this software and associated documentation files (the "Software"), to deal in
|
||
|
the Software without restriction, including without limitation the rights to
|
||
|
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||
|
of the Software, and to permit persons to whom the Software is furnished to do
|
||
|
so, subject to the following conditions:
|
||
|
|
||
|
The above copyright notice and this permission notice shall be included in all
|
||
|
copies or substantial portions of the Software.
|
||
|
|
||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||
|
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||
|
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||
|
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||
|
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||
|
|
||
|
Note that the source modules HTMLGIF1.PAS and DITHERUNIT.PAS
|
||
|
are covered by separate copyright notices located in those modules.
|
||
|
}
|
||
|
|
||
|
{$I frxHTMLCons.inc}
|
||
|
|
||
|
{
|
||
|
This module is comprised mostly of the various Section object definitions.
|
||
|
As the HTML document is parsed, it is divided up into sections. Some sections
|
||
|
are quite simple, like TParagraphSpace. Others are more complex such as
|
||
|
TfrxHtSection which can hold a complete paragraph.
|
||
|
|
||
|
The HTML document is then stored as a list of type TfrxHtDocument, of the various sections.
|
||
|
|
||
|
Closely related to TfrxHtDocument is TfrxHtCell. TfrxHtCell holds the list of sections for
|
||
|
each cell in a Table (the TfrxHtmlTable section). In this way each table cell may
|
||
|
contain a document of it's own.
|
||
|
|
||
|
The Section objects each store relevant data for the section such as the text,
|
||
|
fonts, images, and other info needed for formating.
|
||
|
|
||
|
Each Section object is responsible for its own formated layout. The layout is
|
||
|
done in the DrawLogic method. Layout for the whole document is done in the
|
||
|
TfrxHtDocument.DoLogic method which essentially just calls all the Section
|
||
|
DrawLogic's. It's only necessary to call TfrxHtDocument.DoLogic when a new
|
||
|
layout is required (when the document is loaded or when its width changes).
|
||
|
|
||
|
Each Section is also responsible for drawing itself (its Draw method). The
|
||
|
whole document is drawn with the TfrxHtDocument.Draw method.
|
||
|
}
|
||
|
|
||
|
unit frxHTMLSubs;
|
||
|
|
||
|
{-$define DO_BLOCK_INLINE}
|
||
|
{$ifdef DO_BLOCK_INLINE}
|
||
|
{$endif}
|
||
|
|
||
|
//TODO -oBG, 15.03.2014: support display:inline
|
||
|
{-$define DO_PD_INLINE}
|
||
|
//TODO -oBG, 15.03.2014: support display:inline
|
||
|
{$ifdef DO_PD_INLINE}
|
||
|
{$endif}
|
||
|
|
||
|
interface
|
||
|
|
||
|
uses
|
||
|
{$ifdef UseInline}
|
||
|
frxHTMLCaches,
|
||
|
{$endif}
|
||
|
{$ifdef VCL}
|
||
|
Windows,
|
||
|
frxNetUtils,
|
||
|
{$endif}
|
||
|
{$IFDEF FPC}
|
||
|
frxNetUtils,
|
||
|
{$ENDIF}
|
||
|
Messages, Graphics, Classes, SysUtils, Variants, Math, Contnrs,
|
||
|
{$ifdef LCL}
|
||
|
LclIntf, LclType, Types, frxHTMLMisc,
|
||
|
{$endif}
|
||
|
frxHTMLGlobals,
|
||
|
frxHTMLFonts,
|
||
|
frxHTMLStyleTypes,
|
||
|
frxHTMLImages, // use before HTMLUn2, as both define a TGetImageEvent, but we need the one of HTMLUn2 here.
|
||
|
frxHTMLUn2,
|
||
|
frxHTMLBuffer,
|
||
|
frxHTMLSymb,
|
||
|
frxHTMLStyleUn,
|
||
|
frxHTMLURLSubs,
|
||
|
frxGif2,
|
||
|
frxMD5;
|
||
|
|
||
|
type
|
||
|
TfrxHtBlock = class;
|
||
|
TfrxHtSection = class;
|
||
|
TfrxHtCellBasic = class;
|
||
|
TfrxHtDocument = class;
|
||
|
|
||
|
//------------------------------------------------------------------------------
|
||
|
// TfrxHtFontObj, contains an atomic font info for a part of a section.
|
||
|
// TfrxHtFontList, contains and owns all font infos of a section
|
||
|
// TfrxHtLinkList, references but does not own all link infos of a document. The objects are still owned by their sections.
|
||
|
//------------------------------------------------------------------------------
|
||
|
|
||
|
TfrxHtFontList = class;
|
||
|
|
||
|
TfrxHtFontObj = class(TfrxHtFontObjBase) {font information}
|
||
|
// BG, 10.08.2013: deprecated
|
||
|
// Is used to handle the link states, but the full range of CSS
|
||
|
// properties can be applied to :link, :hover, :visited, etc.
|
||
|
//
|
||
|
private
|
||
|
Title: ThtString;
|
||
|
FYValue: Integer;
|
||
|
Active: Boolean;
|
||
|
function GetURL: ThtString;
|
||
|
procedure CreateFIArray;
|
||
|
public
|
||
|
Pos: Integer; {0..Len Index where font takes effect}
|
||
|
TheFont: TfrxHtFont;
|
||
|
FIArray: TFontInfoObj;
|
||
|
FontHeight, {tmHeight+tmExternalLeading}
|
||
|
tmHeight,
|
||
|
tmMaxCharWidth,
|
||
|
Overhang,
|
||
|
Descent: Integer;
|
||
|
SScript: ThtAlignmentStyle;
|
||
|
constructor Create(ASection: TfrxHtSection; F: TfrxHtFont; Position: Integer);
|
||
|
constructor CreateCopy(ASection: TfrxHtSection; T: TfrxHtFontObj);
|
||
|
destructor Destroy; override;
|
||
|
procedure ReplaceFont(F: TfrxHtFont);
|
||
|
procedure ConvertFont(const FI: TfrxHtFontInfo);
|
||
|
procedure FontChanged;
|
||
|
function GetOverhang: Integer;
|
||
|
function GetHeight(var Desc: Integer): Integer;
|
||
|
|
||
|
property URL: ThtString read GetURL;
|
||
|
property DrawYY: Integer read FYValue;
|
||
|
end;
|
||
|
|
||
|
// BG, 10.02.2013: owns its objects.
|
||
|
TfrxHtFontList = class(TfrxHtFontObjBaseList) {a list of TfrxHtFontObj's}
|
||
|
private
|
||
|
function GetFont(Index: Integer): TfrxHtFontObj; {$ifdef UseInline} inline; {$endif}
|
||
|
public
|
||
|
constructor CreateCopy(ASection: TfrxHtSection; T: TfrxHtFontList);
|
||
|
function GetFontAt(Posn: Integer; out OHang: Integer): TfrxHtFont;
|
||
|
// function GetFontCountAt(Posn, Leng: Integer): Integer;
|
||
|
function GetFontObjAt(Posn: Integer): TfrxHtFontObj; overload;
|
||
|
function GetFontObjAt(Posn, Leng: Integer; out Obj: TfrxHtFontObj): Integer; overload;
|
||
|
procedure Decrement(N: Integer; Document: TfrxHtDocument);
|
||
|
property Items[Index: Integer]: TfrxHtFontObj read GetFont; default;
|
||
|
end;
|
||
|
|
||
|
// BG, 10.02.2013: does not own its font objects.
|
||
|
TfrxHtLinkList = class(TfrxHtFontList)
|
||
|
public
|
||
|
constructor Create;
|
||
|
end;
|
||
|
|
||
|
//------------------------------------------------------------------------------
|
||
|
// TfrxHtmlNode is base class for all objects in the HTML document tree.
|
||
|
//------------------------------------------------------------------------------
|
||
|
|
||
|
TfrxHtmlNode = class(TfrxHtIDObject)
|
||
|
private
|
||
|
FDocument: TfrxHtDocument; // the document it belongs to
|
||
|
FOwnerBlock: TfrxHtBlock; // the parental block it is placed in
|
||
|
FOwnerCell: TfrxHtCellBasic; // the parent's child list it is placed in
|
||
|
FAttributes: TfrxHtAttributeList;
|
||
|
FProperties: TfrxHTProperties;
|
||
|
FDisplay: ThtDisplayStyle; // how it is displayed
|
||
|
FEmSize, FExSize: Integer;
|
||
|
|
||
|
function GetSymbol(): TElemSymb;
|
||
|
function GetAttribute(const Name: ThtString): ThtString;
|
||
|
function GetContainingBlock: TfrxHtBlock; virtual;
|
||
|
function GetProperty(PropIndex: ThtPropIndices): Variant;
|
||
|
function GetContainingBox: TRect;
|
||
|
|
||
|
function GetClearSpace(IMgr: TfrxHtIndentManager; Y: Integer): Integer;
|
||
|
|
||
|
protected
|
||
|
FPositioning: ThtBoxPositionStyle;
|
||
|
FPositions: ThtRectIntegers; // in Pixels
|
||
|
FFloating: ThtAlignmentStyle;
|
||
|
FClearing: ThtClearStyle;
|
||
|
FIndent: Integer; {Indentation of floating object relative to Draw-X}
|
||
|
|
||
|
procedure GetVMarginArray(var MArray: ThtVMarginArray);
|
||
|
|
||
|
function TryGetClear(var Clear: ThtClearStyle): Boolean; virtual;
|
||
|
function CalcDisplayExtern: ThtDisplayStyle; virtual;
|
||
|
function CalcDisplayIntern: ThtDisplayStyle; virtual;
|
||
|
function FindAttribute(const Name: ThtString; out Attribute: TfrxHtAttribute): Boolean; overload;
|
||
|
function IsCopy: Boolean; virtual;
|
||
|
property ContainingBox: TRect read GetContainingBox;
|
||
|
public
|
||
|
constructor Create(Parent: TfrxHtCellBasic; Attributes: TfrxHtAttributeList; Properties: TfrxHTProperties; const ID: ThtString);
|
||
|
constructor CreateCopy(Parent: TfrxHtCellBasic; Source: TfrxHtmlNode); virtual;
|
||
|
destructor Destroy; override;
|
||
|
|
||
|
function IsInFlow: Boolean; {$ifdef UseInline} inline; {$endif}
|
||
|
function IndexOf(Child: TfrxHtmlNode): Integer; virtual;
|
||
|
procedure AfterConstruction; override;
|
||
|
property Symbol: TElemSymb read GetSymbol;
|
||
|
property OwnerBlock: TfrxHtBlock read FOwnerBlock; //BG, 07.02.2011: public for reading document structure (see issue 24). Renamed from MyBlock to Owner to clarify the relation.
|
||
|
property OwnerCell: TfrxHtCellBasic read FOwnerCell write FOwnerCell;
|
||
|
property Document: TfrxHtDocument read FDocument;
|
||
|
property Display: ThtDisplayStyle read FDisplay write FDisplay;
|
||
|
property EmSize: Integer read FEmSize write FEmSize;
|
||
|
property ExSize: Integer read FExSize write FExSize;
|
||
|
property AttributeValue[const AttrName: ThtString]: ThtString read GetAttribute;
|
||
|
property PropertyValue[PropIndex: ThtPropIndices]: Variant read GetProperty;
|
||
|
end;
|
||
|
|
||
|
//------------------------------------------------------------------------------
|
||
|
// TfrxHtSectionBase, the abstract base class for all document sections
|
||
|
//------------------------------------------------------------------------------
|
||
|
// Each block is a section (see TfrxHtBlock and its derivates) and a series of text
|
||
|
// and non block building "inline" tags is held in a section (see TfrxHtSection)
|
||
|
//
|
||
|
// Base class for TfrxHtSection, TfrxHtBlock, TfrxHtmlTable, TfrxHtPage and TfrxHtHorzLine
|
||
|
//------------------------------------------------------------------------------
|
||
|
|
||
|
TfrxHtSectionBase = class(TfrxHtmlNode)
|
||
|
protected
|
||
|
OwnerIndent: Integer;
|
||
|
|
||
|
function GetYPosition: Integer; override;
|
||
|
procedure SetDocument(List: TfrxHtDocument);
|
||
|
public
|
||
|
// source buffer reference
|
||
|
StartCurs: Integer; // where the section starts in the source buffer.
|
||
|
Len: Integer; // number of bytes in source buffer the section represents.
|
||
|
// Z coordinates are calculated in Create()
|
||
|
ZIndex: Integer;
|
||
|
// Y coordinates calculated in DrawLogic1() are still valid in Draw1()
|
||
|
YDraw: Integer; // where the section starts.
|
||
|
DrawTop: Integer; // where the border starts. In case of a block this is YDraw + MarginTop
|
||
|
ContentTop: Integer; // where the content starts. In case of a block this is YDraw + MarginTop + BorderTopWidth + PaddingTop
|
||
|
ContentBot: Integer; // where the section ends. In case of a block this is Block.ClientContentBot + PaddingBottom + BorderBottomWidth + MarginBottom
|
||
|
DrawBot: Integer; // where the border ends. In case of a block this is Max(Block.ClientContentBot, MyCell.tcDrawBot) + PaddingBottom + BorderBottomWidth
|
||
|
SectionHeight: Integer; // pixel height of section. = ContentBot - YDraw
|
||
|
DrawHeight: Integer; // floating image may overhang. = Max(ContentBot, DrawBot) - YDraw
|
||
|
// X coordinates calculated in DrawLogic1() may be shifted in Draw1(), if section is centered or right aligned
|
||
|
TagClass: ThtString; {debugging aid}
|
||
|
|
||
|
constructor Create(Parent: TfrxHtCellBasic; Attributes: TfrxHtAttributeList; Properties: TfrxHTProperties; const TheId, TheClass: ThtString); overload;
|
||
|
constructor Create(Parent: TfrxHtCellBasic; Attributes: TfrxHtAttributeList; Properties: TfrxHTProperties); overload;
|
||
|
constructor CreateCopy(Parent: TfrxHtCellBasic; Source: TfrxHtmlNode); override;
|
||
|
function DrawLogic1(Canvas: TCanvas; X, Y, XRef, YRef, AWidth, AHeight, BlHt: Integer; IMgr: TfrxHtIndentManager; var MaxWidth, Curs: Integer; ARemainHeight: Integer): Integer; virtual;
|
||
|
function Draw1(Canvas: TCanvas; const ARect: TRect; IMgr: TfrxHtIndentManager; X, XRef, YRef: Integer): Integer; virtual;
|
||
|
function FindDocPos(SourcePos: Integer; Prev: Boolean): Integer; virtual;
|
||
|
function FindSourcePos(DocPos: Integer): Integer; virtual;
|
||
|
function FindString(From: Integer; const ToFind: UnicodeString; MatchCase: Boolean): Integer; virtual;
|
||
|
function FindStringR(From: Integer; const ToFind: UnicodeString; MatchCase: Boolean): Integer; virtual;
|
||
|
function GetChAtPos(Pos: Integer; out Ch: WideChar; out Obj: TfrxHtSectionBase): Boolean; virtual;
|
||
|
procedure AddSectionsToList; virtual;
|
||
|
procedure MinMaxWidth(Canvas: TCanvas; out Min, Max: Integer; AvailableWidth, AvailableHeight: Integer); virtual;
|
||
|
end;
|
||
|
|
||
|
TfrxHtSectionBaseList = class(TObjectList)
|
||
|
private
|
||
|
function GetItem(Index: Integer): TfrxHtSectionBase; {$ifdef UseInline} inline; {$endif}
|
||
|
public
|
||
|
function FindDocPos(SourcePos: Integer; Prev: Boolean): Integer; virtual;
|
||
|
property Items[Index: Integer]: TfrxHtSectionBase read GetItem; default;
|
||
|
end;
|
||
|
|
||
|
//------------------------------------------------------------------------------
|
||
|
// TfrxHtFloatingObj, an inline block for floating blocks.
|
||
|
//------------------------------------------------------------------------------
|
||
|
|
||
|
TfrxHtBlockBase = class(TfrxHtSectionBase)
|
||
|
public
|
||
|
constructor Create(Parent: TfrxHtCellBasic; Position: Integer; Attributes: TfrxHtAttributeList; Prop: TfrxHTProperties);
|
||
|
constructor CreateCopy(Parent: TfrxHtCellBasic; Source: TfrxHtmlNode); override;
|
||
|
function GetPosition(const Index: ThtRectEdge): Integer;
|
||
|
property Positioning: ThtBoxPositionStyle read FPositioning;
|
||
|
property Floating: ThtAlignmentStyle read FFloating;
|
||
|
property Indent: Integer read FIndent; {Indentation of floated object}
|
||
|
end;
|
||
|
|
||
|
TfrxHtFloatingObj = class(TfrxHtBlockBase)
|
||
|
protected
|
||
|
// begin copy by move()
|
||
|
// source buffer reference
|
||
|
VertAlign: ThtAlignmentStyle;
|
||
|
HSpaceL, HSpaceR: Integer; {horizontal extra space}
|
||
|
VSpaceT, VSpaceB: Integer; {vertical extra space}
|
||
|
PercentWidth: Boolean; {if width is percent}
|
||
|
PercentHeight: Boolean; {if height is percent}
|
||
|
// end copy by move()
|
||
|
|
||
|
function Clone(Parent: TfrxHtCellBasic): TfrxHtFloatingObj;
|
||
|
function GetClientHeight: Integer; virtual; abstract;
|
||
|
function GetClientWidth: Integer; virtual; abstract;
|
||
|
procedure SetClientHeight(Value: Integer); virtual; abstract;
|
||
|
procedure SetClientWidth(Value: Integer); virtual; abstract;
|
||
|
public
|
||
|
DrawYY: Integer; // where the object starts.
|
||
|
DrawXX: Integer; // where the object starts.
|
||
|
constructor Create(Parent: TfrxHtCellBasic; Position: Integer; L: TfrxHtAttributeList; Prop: TfrxHTProperties);
|
||
|
constructor CreateCopy(Parent: TfrxHtCellBasic; Source: TfrxHtmlNode); override;
|
||
|
function DrawLogic1(Canvas: TCanvas; X, Y, XRef, YRef, AWidth, AHeight, BlHt: Integer; IMgr: TfrxHtIndentManager; var MaxWidth, Curs: Integer; ARemainHeight: Integer = 0): Integer; override;
|
||
|
function Draw1(Canvas: TCanvas; const ARect: TRect; IMgr: TfrxHtIndentManager; X, XRef, YRef: Integer): Integer; override;
|
||
|
function GetYPosition: Integer; override;
|
||
|
procedure DrawLogicInline(Canvas: TCanvas; FO: TfrxHtFontObj; AvailableWidth, AvailableHeight: Integer); virtual; abstract;
|
||
|
procedure DrawInline(Canvas: TCanvas; X, Y, YBaseline: Integer; FO: TfrxHtFontObj); virtual; abstract;
|
||
|
property ClientHeight: Integer read GetClientHeight write SetClientHeight;
|
||
|
property ClientWidth: Integer read GetClientWidth write SetClientWidth;
|
||
|
function TotalHeight: Integer; {$ifdef UseInline} inline; {$endif}
|
||
|
function TotalWidth: Integer; {$ifdef UseInline} inline; {$endif}
|
||
|
end;
|
||
|
TFloatingObjClass = class of TfrxHtFloatingObj;
|
||
|
|
||
|
TfrxFrHtImageObj = class;
|
||
|
|
||
|
TFloatingObjList = class(TObjectList) {a list of TfrxHtFloatingObj's}
|
||
|
private
|
||
|
function GetItem(Index: Integer): TfrxHtFloatingObj; {$ifdef UseInline} inline; {$endif}
|
||
|
procedure SetItem(Index: Integer; const Item: TfrxHtFloatingObj); {$ifdef UseInline} inline; {$endif}
|
||
|
public
|
||
|
constructor CreateCopy(Parent: TfrxHtCellBasic; T: TFloatingObjList);
|
||
|
procedure Decrement(N: Integer); {$ifdef UseInline} inline; {$endif}
|
||
|
function FindObject(Posn: Integer): TfrxHtFloatingObj; {$ifdef UseInline} inline; {$endif}
|
||
|
// GetObjectAt() returns number of positions from Posn to next object. If it returns 0, Obj is at Posn.
|
||
|
function GetObjectAt(Posn: Integer; out Obj): Integer;
|
||
|
property Items[Index: Integer]: TfrxHtFloatingObj read GetItem write SetItem; default;
|
||
|
end;
|
||
|
|
||
|
//------------------------------------------------------------------------------
|
||
|
// TfrxHtCellBasic, the base class for content
|
||
|
//------------------------------------------------------------------------------
|
||
|
// Base class for table cells, block content and the entire document
|
||
|
//------------------------------------------------------------------------------
|
||
|
|
||
|
//BG, 02.12.2013: handling display:inline is too complex in this class structure, where TfrxHtSection is both home of a couple
|
||
|
// of HTML elements, the renderer and the rendering results (in the ThtLineRecs).
|
||
|
//
|
||
|
// A straight forward rendering would require overall Lines collecting the text of all consecutive inline level elements
|
||
|
// no matter where it is defined in the document tree.
|
||
|
//
|
||
|
// //BG, 01.12.2013: handle display:inline
|
||
|
// //This list mixes up block elements and autogenerated anonymous blocks for consecutive inline level elements based on
|
||
|
// // TInlineSection. All objects based on TInlineSection are owned (and therefore freed) by this list all other kind of
|
||
|
// // objects are assumed to be referenced and thus are not freed.
|
||
|
// TRenderSectionBaseList = class(TfrxHtSectionBaseList)
|
||
|
// protected
|
||
|
// procedure Notify(Ptr: Pointer; Action: TListNotification); override;
|
||
|
// end;
|
||
|
|
||
|
TfrxHtCellBasic = class(TfrxHtSectionBaseList) {a list of sections and blocks}
|
||
|
private
|
||
|
FDocument: TfrxHtDocument; // the document it belongs to
|
||
|
FOwnerBlock: TfrxHtBlock; // the parental block it is placed in
|
||
|
// FRenderList: TRenderSectionBaseList; //BG, 01.12.2013: The list of block level elements to render. Filled in DoLogic()
|
||
|
protected
|
||
|
function CalcDisplayExtern: ThtDisplayStyle; // returns either pdInline or pdBlock
|
||
|
public
|
||
|
// source buffer reference
|
||
|
StartCurs: Integer; // where the section starts in the source buffer.
|
||
|
Len: Integer; // number of bytes in source buffer the section represents.
|
||
|
//
|
||
|
IMgr: TfrxHtIndentManager; // Each element displayed as a block needs an indent manager.
|
||
|
BkGnd: Boolean;
|
||
|
BkColor: TColor;
|
||
|
tcDrawTop: Integer;
|
||
|
tcContentBot: Integer;
|
||
|
tcDrawBot: Integer;
|
||
|
|
||
|
constructor Create(Parent: TfrxHtBlock);
|
||
|
constructor CreateCopy(Parent: TfrxHtBlock; T: TfrxHtCellBasic);
|
||
|
destructor Destroy; override;
|
||
|
|
||
|
function CheckLastBottomMargin: Boolean;
|
||
|
function DoLogic(Canvas: TCanvas; Y, Width, AHeight, BlHt: Integer; var ScrollWidth, Curs: Integer; ARemainHeight: Integer = 0): Integer; virtual;
|
||
|
function Draw(Canvas: TCanvas; ARect: TRect; ClipWidth, X, Y, XRef, YRef: Integer): Integer; virtual;
|
||
|
function FindSourcePos(DocPos: Integer): Integer;
|
||
|
function FindString(From: Integer; const ToFind: UnicodeString; MatchCase: Boolean): Integer;
|
||
|
function FindStringR(From: Integer; const ToFind: UnicodeString; MatchCase: Boolean): Integer;
|
||
|
function GetChAtPos(Pos: Integer; out Ch: WideChar; out Obj: TfrxHtSectionBase): Boolean;
|
||
|
function IsCopy: Boolean;
|
||
|
procedure Add(Item: TfrxHtSectionBase; TagIndex: Integer); overload;
|
||
|
procedure Add(var Section: TfrxHtSection; TagIndex: Integer); overload;
|
||
|
procedure AddSectionsToList;
|
||
|
{$ifdef UseFormTree}
|
||
|
procedure FormTree(const Indent: ThtString; var Tree: ThtString);
|
||
|
{$endif UseFormTree}
|
||
|
procedure MinMaxWidth(Canvas: TCanvas; out Min, Max: Integer; AvailableWidth, AvailableHeight: Integer); virtual;
|
||
|
property Document: TfrxHtDocument read FDocument; {the TfrxHtDocument that holds the whole document}
|
||
|
property OwnerBlock: TfrxHtBlock read FOwnerBlock;
|
||
|
end;
|
||
|
|
||
|
TfrxHtCell = class(TfrxHtCellBasic)
|
||
|
private
|
||
|
DrawYY: Integer;
|
||
|
public
|
||
|
constructor Create(Parent: TfrxHtBlock);
|
||
|
constructor CreateCopy(Parent: TfrxHtBlock; T: TfrxHtCellBasic);
|
||
|
destructor Destroy; override;
|
||
|
function DoLogic(Canvas: TCanvas; Y, Width, AHeight, BlHt: Integer; var ScrollWidth, Curs: Integer; ARemainHeight: Integer = 0): Integer; override;
|
||
|
function Draw(Canvas: TCanvas; ARect: TRect; ClipWidth, X, Y, XRef, YRef: Integer): Integer; override;
|
||
|
end;
|
||
|
|
||
|
//------------------------------------------------------------------------------
|
||
|
// TfrxHtSizeableObj is base class for floating objects TfrxFrHtImageObj, TFrameOBj and TPanelObj.
|
||
|
//
|
||
|
// These objects may appear in text flow or attribute ALIGN or style FLOAT or
|
||
|
// style POSITION may push them out of the flow floating to the left or right
|
||
|
// side or anywhere else in the containing block or even fixed in the viewport
|
||
|
// resp. on printed pages.
|
||
|
//------------------------------------------------------------------------------
|
||
|
|
||
|
TfrxHtSizeableObj = class(TfrxHtFloatingObj)
|
||
|
private
|
||
|
FAlt: ThtString; {the alt= attribute}
|
||
|
FClientHeight: Integer; {does not include VSpace}
|
||
|
FClientWidth: Integer; {does not include HSpace}
|
||
|
public
|
||
|
ClientSizeKnown: Boolean; {know size of image}
|
||
|
SpecWidth: Integer; {as specified by <img, applet, panel, object, or iframe> tag}
|
||
|
SpecHeight: Integer; {as specified by <img, applet, panel, object, or iframe> tag}
|
||
|
Title: ThtString;
|
||
|
protected
|
||
|
procedure CalcSize(AvailableWidth, AvailableHeight, SetWidth, SetHeight: Integer; IsClientSizeSpecified: Boolean);
|
||
|
function GetClientHeight: Integer; override;
|
||
|
function GetClientWidth: Integer; override;
|
||
|
procedure SetClientHeight(Value: Integer); override;
|
||
|
procedure SetClientWidth(Value: Integer); override;
|
||
|
public
|
||
|
NoBorder: Boolean; {set if don't want blue border}
|
||
|
BorderWidth: Integer;
|
||
|
MargArray: ThtMarginArray;
|
||
|
constructor Create(Parent: TfrxHtCellBasic; Position: Integer; L: TfrxHtAttributeList; Prop: TfrxHTProperties);
|
||
|
constructor CreateCopy(Parent: TfrxHtCellBasic; Source: TfrxHtmlNode); override;
|
||
|
constructor SimpleCreate(Parent: TfrxHtCellBasic);
|
||
|
procedure DrawLogicInline(Canvas: TCanvas; FO: TfrxHtFontObj; AvailableWidth, AvailableHeight: Integer); override;
|
||
|
procedure DrawInline(Canvas: TCanvas; X, Y, YBaseline: Integer; FO: TfrxHtFontObj); override;
|
||
|
procedure ProcessProperties(Prop: TfrxHTProperties);
|
||
|
procedure SetAlt(CodePage: Integer; const Value: ThtString);
|
||
|
property Alt: ThtString read FAlt;
|
||
|
end;
|
||
|
|
||
|
TfrxHtSizeableObjList = class(TFloatingObjList) {a list of TfrxFrHtImageObj's, TPanelObj's , and TFrameObj's}
|
||
|
end;
|
||
|
|
||
|
// inline image node
|
||
|
TfrxFrHtImageObj = class(TfrxHtSizeableObj)
|
||
|
private
|
||
|
FSource: ThtString;
|
||
|
FImage: TfrxHtImage;
|
||
|
OrigImage: TfrxHtImage; {same as above unless swapped}
|
||
|
Transparent: ThtImageTransparency; {None, Lower Left Corner, or Transp GIF}
|
||
|
AltHeight, AltWidth: Integer;
|
||
|
function GetGraphic: TGraphic;
|
||
|
procedure DoDraw(Canvas: TCanvas; XX, Y: Integer; ddImage: TfrxHtImage);
|
||
|
public
|
||
|
ObjHeight, ObjWidth: Integer; {width as drawn}
|
||
|
IsMap, UseMap: Boolean;
|
||
|
MapName: ThtString;
|
||
|
Swapped: Boolean; {image has been replaced}
|
||
|
Missing: Boolean; {waiting for image to be downloaded}
|
||
|
|
||
|
constructor Create(Parent: TfrxHtCellBasic; Position: Integer; L: TfrxHtAttributeList; Prop: TfrxHTProperties);
|
||
|
constructor SimpleCreate(Parent: TfrxHtCellBasic; const AnURL: ThtString);
|
||
|
constructor CreateCopy(Parent: TfrxHtCellBasic; Source: TfrxHtmlNode); override;
|
||
|
procedure DrawLogicInline(Canvas: TCanvas; FO: TfrxHtFontObj; AvailableWidth, AvailableHeight: Integer); override;
|
||
|
procedure DrawInline(Canvas: TCanvas; X: Integer; Y, YBaseline: Integer; FO: TfrxHtFontObj); override;
|
||
|
|
||
|
property Graphic: TGraphic read GetGraphic;
|
||
|
property Image: TfrxHtImage read FImage ; //write SetImage;
|
||
|
property Source: ThtString read FSource; {the src= attribute}
|
||
|
end;
|
||
|
|
||
|
TfrxHtDrawList = class(TObjectList)
|
||
|
procedure AddImage(Obj: TfrxFrHtImageObj; Canvas: TCanvas; X, Y, YBaseline: Integer; FO: TfrxHtFontObj);
|
||
|
procedure DrawImages;
|
||
|
end;
|
||
|
|
||
|
//------------------------------------------------------------------------------
|
||
|
// TfrxHtSection holds a series of text and inline tags like images and panels.
|
||
|
//------------------------------------------------------------------------------
|
||
|
// Holds tags like A, B, I, FONT, SPAN, IMG, ...
|
||
|
//------------------------------------------------------------------------------
|
||
|
|
||
|
TfrxHtBorderRec = class {record for inline borders}
|
||
|
private
|
||
|
BStart, BEnd: Integer;
|
||
|
OpenStart, OpenEnd: Boolean;
|
||
|
BRect: TRect;
|
||
|
MargArray: ThtMarginArray;
|
||
|
procedure DrawTheBorder(Canvas: TCanvas; XOffset, YOffSet: Integer; Printing: Boolean);
|
||
|
end;
|
||
|
|
||
|
TfrxHtBorderRecList = class(TObjectList)
|
||
|
private
|
||
|
function Get(Index: Integer): TfrxHtBorderRec; {$ifdef UseInline} inline; {$endif}
|
||
|
public
|
||
|
property Items[Index: Integer]: TfrxHtBorderRec read Get; default;
|
||
|
end;
|
||
|
|
||
|
TfrxHtLineRec = class {holds info on a line of text}
|
||
|
private
|
||
|
Start: PWideChar;
|
||
|
SpaceBefore, SpaceAfter,
|
||
|
LineHt, {total height of line}
|
||
|
LineImgHt, {top to bottom including any floating image}
|
||
|
Ln, {# chars in line}
|
||
|
Descent,
|
||
|
LineIndent: Integer; // relative to section's left edge
|
||
|
DrawXX, DrawWidth: Integer;
|
||
|
DrawY: Integer;
|
||
|
Spaces, Extra: Integer;
|
||
|
BorderList: TfrxHtBorderRecList; {List of inline borders (TfrxHtBorderRec's) in this Line}
|
||
|
FirstDraw: Boolean; {set if border processing needs to be done when first drawn}
|
||
|
Drawn: Boolean; // set if drawn by section and thus actual position has been calculated
|
||
|
FirstX: Integer; {x value at FirstDraw}
|
||
|
Shy: Boolean;
|
||
|
public
|
||
|
constructor Create(SL: TfrxHtDocument);
|
||
|
procedure Clear;
|
||
|
destructor Destroy; override;
|
||
|
end;
|
||
|
|
||
|
TfrxHtLineRecList = class(TObjectList)
|
||
|
private
|
||
|
function Get(Index: Integer): TfrxHtLineRec; {$ifdef UseInline} inline; {$endif}
|
||
|
public
|
||
|
property Items[Index: Integer]: TfrxHtLineRec read Get; default;
|
||
|
end;
|
||
|
|
||
|
PXArray = array of Integer;
|
||
|
|
||
|
TfrxHtIndexObj = class
|
||
|
public
|
||
|
Pos: Integer;
|
||
|
Index: Integer;
|
||
|
end;
|
||
|
|
||
|
TfrxHtIndexObjList = class(TObjectList)
|
||
|
private
|
||
|
function Get(Index: Integer): TfrxHtIndexObj; {$ifdef UseInline} inline; {$endif}
|
||
|
public
|
||
|
property Items[Index: Integer]: TfrxHtIndexObj read Get; default;
|
||
|
end;
|
||
|
|
||
|
ThtTextWrap = (
|
||
|
twNo, // 'n'
|
||
|
twYes, // 'y'
|
||
|
twSoft, // 's'
|
||
|
twOptional // 'a'
|
||
|
);
|
||
|
|
||
|
ThtTextWrapArray = array of ThtTextWrap;
|
||
|
|
||
|
// TODO: stop creating TfrxHtSection, which mix up several inline elements into one instance.
|
||
|
// Therefore we cannot control individual properties/attributes of single elements in it.
|
||
|
// TfrxHtSection has to be reduced to a simple inline block for text of a single inline element
|
||
|
// resp. to an anonymous block for text of a block element.
|
||
|
// Also remove rendering code as soon as rendering is done by TInlineSection.
|
||
|
// As a document is a TSectionList, TInlineSection will do it.
|
||
|
TfrxHtSection = class(TfrxHtSectionBase)
|
||
|
{TfrxHtSection holds and renders inline content. Mainly text and floating images, panel, frames, and form controls.}
|
||
|
private
|
||
|
BreakWord: Boolean;
|
||
|
DrawWidth: Integer;
|
||
|
FLPercent: Integer;
|
||
|
LineHeight: Integer;
|
||
|
StoredMin, StoredMax: TSize;
|
||
|
|
||
|
SectionNumber: Integer;
|
||
|
ThisCycle: Integer;
|
||
|
|
||
|
BuffS: ThtString; {holds the text or one of #2 (Form), #4 (Image/Panel), #8 (break char) for the section} //TODO -oBG, 30.11.2013: #1 (Table for display:inline-table)
|
||
|
FBuff: PWideChar; {same as above}
|
||
|
Brk: ThtTextWrapArray; //string; // Brk[n]: Can I wrap to new line after BuffS[n]? One entry per character in BuffS
|
||
|
SIndexList: TfrxHtIndexObjList; {list of Source index changes}
|
||
|
Lines: TfrxHtLineRecList; {List of ThtLineRecs, info on all the lines in section}
|
||
|
|
||
|
function GetIndexObj(I: Integer): TfrxHtIndexObj;
|
||
|
property PosIndex[I: Integer]: TfrxHtIndexObj read GetIndexObj;
|
||
|
procedure CheckForInlines(LR: TfrxHtLineRec);
|
||
|
public
|
||
|
Images: TfrxHtSizeableObjList; {list of TfrxHtSizeableObj's, the images, panels and iframes in section}
|
||
|
AnchorName: Boolean;
|
||
|
|
||
|
Fonts: TfrxHtFontList; {List of FontObj's in this section}
|
||
|
Justify: ThtJustify; {Left, Centered, Right}
|
||
|
JustifyByDirection: Boolean;
|
||
|
Direction: ThtDirection;
|
||
|
TextWidth: Integer;
|
||
|
WhiteSpaceStyle: ThtWhiteSpaceStyle;
|
||
|
FirstLineIndent: Integer; // Issue 365: public for TRichView
|
||
|
property Buff: PWideChar read FBuff; // Issue 365: public for TRichView
|
||
|
protected
|
||
|
XP: PXArray;
|
||
|
constructor Create(Parent: TfrxHtCellBasic); overload;
|
||
|
function TryGetClear(var Clear: ThtClearStyle): Boolean; override;
|
||
|
procedure SureDirection(WC: PWideChar; Len: Integer);
|
||
|
procedure SetJustifyByDirection;
|
||
|
public
|
||
|
constructor Create(Parent: TfrxHtCellBasic; Attr: TfrxHtAttributeList; Prop: TfrxHTProperties; AnURL: TfrxHtUrlTarget; FirstItem: Boolean); overload;
|
||
|
constructor CreateCopy(Parent: TfrxHtCellBasic; Source: TfrxHtmlNode); override;
|
||
|
destructor Destroy; override;
|
||
|
function AddImage(L: TfrxHtAttributeList; ACell: TfrxHtCellBasic; Index: Integer; Prop: TfrxHTProperties): TfrxFrHtImageObj;
|
||
|
function Draw1(Canvas: TCanvas; const ARect: TRect; IMgr: TfrxHtIndentManager; X, XRef, YRef: Integer): Integer; override;
|
||
|
function DrawLogic1(Canvas: TCanvas; X, Y, XRef, YRef, AWidth, AHeight, BlHt: Integer; IMgr: TfrxHtIndentManager; var MaxWidth, Curs: Integer; ARemainHeight: Integer = 0): Integer; override;
|
||
|
function FindCountThatFits(Canvas: TCanvas; Width: Integer; Start: PWideChar; Max: Integer): Integer;
|
||
|
function FindDocPos(SourcePos: Integer; Prev: Boolean): Integer; override;
|
||
|
function FindSourcePos(DocPos: Integer): Integer; override;
|
||
|
function FindString(From: Integer; const ToFind: UnicodeString; MatchCase: Boolean): Integer; override;
|
||
|
function FindStringR(From: Integer; const ToFind: UnicodeString; MatchCase: Boolean): Integer; override;
|
||
|
function FindTextSize(Canvas: TCanvas; Start: PWideChar; N: Integer; RemoveSpaces: Boolean): TSize;
|
||
|
function FindTextWidthA(Canvas: TCanvas; Start: PWideChar; N: Integer): Integer;
|
||
|
function GetChAtPos(Pos: Integer; out Ch: WideChar; out Obj: TfrxHtSectionBase): Boolean; override;
|
||
|
function GetXPLen: Integer;
|
||
|
procedure AddChar(C: WideChar; Index: Integer); virtual;
|
||
|
procedure AddOpBrk;
|
||
|
procedure AddTokenObj(T: TfrxHtTokenObj); virtual;
|
||
|
procedure Allocate(N: Integer);
|
||
|
procedure ChangeFont(Prop: TfrxHTProperties);
|
||
|
procedure CheckFree;
|
||
|
procedure Finish;
|
||
|
procedure HRef(IsHRef: Boolean; List: TfrxHtDocument; AnURL: TfrxHtUrlTarget; Attributes: TfrxHtAttributeList; Prop: TfrxHTProperties);
|
||
|
procedure MinMaxWidth(Canvas: TCanvas; out Min, Max: Integer; AvailableWidth, AvailableHeight: Integer); override;
|
||
|
procedure ProcessText(TagIndex: Integer); virtual;
|
||
|
end;
|
||
|
|
||
|
// //BG, 01.12.2013: handle display:inline
|
||
|
// // anonymous block for consecutive inline level elements.
|
||
|
// TInlineSection = class(TfrxHtSection)
|
||
|
// public
|
||
|
// constructor Create(Parent: TfrxHtCellBasic);
|
||
|
// procedure AddElement(Section: TfrxHtSection);
|
||
|
// end;
|
||
|
|
||
|
//------------------------------------------------------------------------------
|
||
|
// TfrxHtBlock represents block tags.
|
||
|
//------------------------------------------------------------------------------
|
||
|
// A block is a rectangular area which may have a border
|
||
|
// with margins outside and padding inside the border. It contains a
|
||
|
// cell, which itself contains any kind of the html document content.
|
||
|
//
|
||
|
// Holds tags like DIV, FORM, PRE, P, H1..H6, UL, OL, DL, DIR, MENU, ...
|
||
|
//------------------------------------------------------------------------------
|
||
|
|
||
|
TfrxHtBlockCell = class(TfrxHtCellBasic)
|
||
|
private
|
||
|
CellHeight: Integer;
|
||
|
TextWidth: Integer;
|
||
|
|
||
|
function DoLogicX(Canvas: TCanvas; X, Y, XRef, YRef, Width, AHeight, BlHt: Integer;
|
||
|
out ScrollWidth: Integer; var Curs: Integer; ARemainHeight: Integer = 0): Integer;
|
||
|
end;
|
||
|
|
||
|
TfrxHtBlock = class(TfrxHtBlockBase)
|
||
|
protected
|
||
|
function GetBorderWidth: Integer; virtual;
|
||
|
function CalcDisplayExtern: ThtDisplayStyle; override;
|
||
|
function CalcDisplayIntern: ThtDisplayStyle; override;
|
||
|
procedure ContentMinMaxWidth(Canvas: TCanvas; out Min, Max: Integer; AvailableWidth, AvailableHeight: Integer); virtual;
|
||
|
procedure ConvMargArray(BaseWidth, BaseHeight: Integer; out AutoCount: Integer); virtual;
|
||
|
procedure DrawBlockBorder(Canvas: TCanvas; const ORect, IRect: TRect); virtual;
|
||
|
property BorderWidth: Integer read GetBorderWidth;
|
||
|
public
|
||
|
MyCell: TfrxHtBlockCell; // the block content
|
||
|
MargArrayO: ThtVMarginArray;
|
||
|
BGImage: TfrxFrHtImageObj; //TODO -oBG, 10.03.2011: see also bkGnd and bkColor in TfrxHtCellBasic one background should be enough.
|
||
|
BlockTitle: ThtString;
|
||
|
|
||
|
// Notice: styling tag attributes are deprecated by W3C and must be translated
|
||
|
// to the corresponding style properties with a very low priority.
|
||
|
|
||
|
// BEGIN: this area is copied by move() in CreateCopy() - NO string types allowed!
|
||
|
MargArray: ThtMarginArray;
|
||
|
FGColor: Integer;
|
||
|
HasBorderStyle: Boolean;
|
||
|
|
||
|
PRec: PtPositionRec; // background image position
|
||
|
Visibility: ThtVisibilityStyle;
|
||
|
TopAuto: Boolean;
|
||
|
BottomAuto: Boolean;
|
||
|
BreakBefore, BreakAfter, KeepIntact: Boolean;
|
||
|
HideOverflow: Boolean;
|
||
|
Justify: ThtJustify;
|
||
|
RTL: Boolean;
|
||
|
Converted: Boolean;
|
||
|
// END: this area is copied by move() in CreateCopy()
|
||
|
|
||
|
ContentWidth: Integer;
|
||
|
ClearAddon: Integer;
|
||
|
NeedDoImageStuff: Boolean;
|
||
|
TiledImage: TfrxHtImage;
|
||
|
TopP, LeftP: Integer;
|
||
|
DrawList: TfrxHtSectionBaseList;
|
||
|
NoMask: Boolean;
|
||
|
ClientContentBot: Integer;
|
||
|
MyRect: TRect; // calculated by DrawBlock(): the outmost rectangle of this block incl. border and padding but without margins in screen coordinates.
|
||
|
MyIMgr: TfrxHtIndentManager;
|
||
|
RefIMgr: TfrxHtIndentManager;
|
||
|
|
||
|
constructor Create(Parent: TfrxHtCellBasic; Attributes: TfrxHtAttributeList; Prop: TfrxHTProperties);
|
||
|
constructor CreateCopy(Parent: TfrxHtCellBasic; Source: TfrxHtmlNode); override;
|
||
|
destructor Destroy; override;
|
||
|
function Draw1(Canvas: TCanvas; const ARect: TRect; IMgr: TfrxHtIndentManager; X, XRef, YRef: Integer): Integer; override;
|
||
|
function DrawLogic1(Canvas: TCanvas; X, Y, XRef, YRef, AWidth, AHeight, BlHt: Integer; IMgr: TfrxHtIndentManager; var MaxWidth, Curs: Integer; ARemainHeight: Integer = 0): Integer; override;
|
||
|
function FindDocPos(SourcePos: Integer; Prev: Boolean): Integer; override;
|
||
|
function FindSourcePos(DocPos: Integer): Integer; override;
|
||
|
function FindString(From: Integer; const ToFind: UnicodeString; MatchCase: Boolean): Integer; override;
|
||
|
function FindStringR(From: Integer; const ToFind: UnicodeString; MatchCase: Boolean): Integer; override;
|
||
|
function FindWidth(Canvas: TCanvas; AWidth, AHeight, AutoCount: Integer): Integer; virtual;
|
||
|
function GetChAtPos(Pos: Integer; out Ch: WideChar; out Obj: TfrxHtSectionBase): Boolean; override;
|
||
|
procedure AddSectionsToList; override;
|
||
|
procedure CollapseAdjoiningMargins;
|
||
|
procedure CollapseNestedMargins;
|
||
|
procedure DrawBlock(Canvas: TCanvas; const ARect: TRect; IMgr: TfrxHtIndentManager; X, Y, XRef, YRef: Integer);
|
||
|
procedure DrawSort;
|
||
|
procedure DrawTheList(Canvas: TCanvas; const ARect: TRect; ClipWidth, X, XRef, YRef: Integer);
|
||
|
{$ifdef UseFormTree}
|
||
|
procedure FormTree(const Indent: ThtString; var Tree: ThtString);
|
||
|
{$endif UseFormTree}
|
||
|
procedure MinMaxWidth(Canvas: TCanvas; out Min, Max: Integer; AvailableWidth, AvailableHeight: Integer); override;
|
||
|
end;
|
||
|
|
||
|
ThtListType = (None, Ordered, Unordered, Definition, liAlone);
|
||
|
|
||
|
//------------------------------------------------------------------------------
|
||
|
// some blocks
|
||
|
//------------------------------------------------------------------------------
|
||
|
|
||
|
{ TfrxHtHRBlock }
|
||
|
|
||
|
TfrxHtHRBlock = class(TfrxHtBlock)
|
||
|
public
|
||
|
Align: ThtJustify;
|
||
|
MyHRule: TfrxHtSectionBase;
|
||
|
constructor CreateCopy(OwnerCell: TfrxHtCellBasic; Source: TfrxHtmlNode); override;
|
||
|
function FindWidth(Canvas: TCanvas; AWidth, AHeight, AutoCount: Integer): Integer; override;
|
||
|
end;
|
||
|
|
||
|
TfrxHtListBlock = class(TfrxHtBlock)
|
||
|
end;
|
||
|
|
||
|
TfrxHtBlockLI = class(TfrxHtBlock)
|
||
|
private
|
||
|
FListType: ThtListType;
|
||
|
FListNumb: Integer;
|
||
|
FListStyleType: ThtBulletStyle;
|
||
|
FListFont: TFont;
|
||
|
Image: TfrxFrHtImageObj;
|
||
|
FirstLineHt: Integer;
|
||
|
procedure SetListFont(const Value: TFont);
|
||
|
public
|
||
|
constructor Create(Parent: TfrxHtCellBasic; Attributes: TfrxHtAttributeList; Prop: TfrxHTProperties;
|
||
|
Sy: TElemSymb; APlain: Boolean; AIndexType: ThtChar;
|
||
|
AListNumb, ListLevel: Integer);
|
||
|
constructor CreateCopy(OwnerCell: TfrxHtCellBasic; Source: TfrxHtmlNode); override;
|
||
|
destructor Destroy; override;
|
||
|
function DrawLogic1(Canvas: TCanvas; X, Y, XRef, YRef, AWidth, AHeight, BlHt: Integer; IMgr: TfrxHtIndentManager; var MaxWidth, Curs: Integer; ARemainHeight: Integer = 0): Integer; override;
|
||
|
function Draw1(Canvas: TCanvas; const ARect: TRect; IMgr: TfrxHtIndentManager; X, XRef, YRef: Integer): Integer; override;
|
||
|
property ListNumb: Integer read FListNumb write FListNumb;
|
||
|
property ListStyleType: ThtBulletStyle read FListStyleType write FListStyleType;
|
||
|
property ListType: ThtListType read FListType write FListType;
|
||
|
property ListFont: TFont read FListFont write SetListFont;
|
||
|
end;
|
||
|
|
||
|
TfrxHtFieldsetBlock = class(TfrxHtBlock)
|
||
|
private
|
||
|
FLegend: TfrxHtBlockCell;
|
||
|
protected
|
||
|
procedure ConvMargArray(BaseWidth, BaseHeight: Integer; out AutoCount: Integer); override;
|
||
|
procedure ContentMinMaxWidth(Canvas: TCanvas; out Min, Max: Integer; AvailableWidth, AvailableHeight: Integer); override;
|
||
|
public
|
||
|
constructor Create(Parent: TfrxHtCellBasic; Attributes: TfrxHtAttributeList; Prop: TfrxHTProperties);
|
||
|
constructor CreateCopy(Parent: TfrxHtCellBasic; Source: TfrxHtmlNode); override;
|
||
|
destructor Destroy; override;
|
||
|
function DrawLogic1(Canvas: TCanvas; X, Y, XRef, YRef, AWidth, AHeight, BlHt: Integer; IMgr: TfrxHtIndentManager; var MaxWidth, Curs: Integer; ARemainHeight: Integer = 0): Integer; override;
|
||
|
function Draw1(Canvas: TCanvas; const ARect: TRect; IMgr: TfrxHtIndentManager; X, XRef, YRef: Integer): Integer; override;
|
||
|
property Legend: TfrxHtBlockCell read FLegend;
|
||
|
end;
|
||
|
|
||
|
TfrxHtBodyBlock = class(TfrxHtBlock)
|
||
|
public
|
||
|
constructor Create(Parent: TfrxHtCellBasic; Attributes: TfrxHtAttributeList; Prop: TfrxHTProperties);
|
||
|
function DrawLogic1(Canvas: TCanvas; X, Y, XRef, YRef, AWidth, AHeight, BlHt: Integer; IMgr: TfrxHtIndentManager; var MaxWidth, Curs: Integer; ARemainHeight: Integer = 0): Integer; override;
|
||
|
function Draw1(Canvas: TCanvas; const ARect: TRect; IMgr: TfrxHtIndentManager; X, XRef, YRef: Integer): Integer; override;
|
||
|
end;
|
||
|
|
||
|
//------------------------------------------------------------------------------
|
||
|
// TfrxHtmlTable, a block that represents a html table
|
||
|
//------------------------------------------------------------------------------
|
||
|
|
||
|
TTableFrame = (tfVoid, tfAbove, tfBelow, tfHSides, tfLhs, tfRhs, tfVSides, tfBox, tfBorder);
|
||
|
TTableRules = (trNone, trGroups, trRows, trCols, trAll);
|
||
|
TIntArray = array of Integer;
|
||
|
TWidthTypeArray = array of TWidthType;
|
||
|
TIntegerPerWidthType = array [TWidthType] of Integer;
|
||
|
|
||
|
TfrxHtTableBlock = class;
|
||
|
|
||
|
TfrxHtCellObjCell = class(TfrxHtCell)
|
||
|
private
|
||
|
MyRect: TRect;
|
||
|
Title: ThtString;
|
||
|
Url, Target: ThtString;
|
||
|
public
|
||
|
constructor CreateCopy(Parent: TfrxHtBlock; T: TfrxHtCellObjCell);
|
||
|
end;
|
||
|
|
||
|
TfrxHtfrcHtCellObjBase = class(TObject)
|
||
|
protected
|
||
|
// BEGIN: this area is copied by move() in AssignTo() - NO string types or any other references like objects allowed!
|
||
|
FColSpan: Integer; {column spans for this cell}
|
||
|
FRowSpan: Integer; {row spans for this cell}
|
||
|
FHzSpace: Integer;
|
||
|
FVrSpace: Integer;
|
||
|
FSpecWd: TSpecWidth; {Width attribute (percentage or absolute)}
|
||
|
FSpecHt: TSpecWidth; {Height as specified}
|
||
|
// END: this area is copied by move() in AssignTo()
|
||
|
function GetCell: TfrxHtCellObjCell; virtual; abstract;
|
||
|
procedure Draw(Canvas: TCanvas; const ARect: TRect; X, Y, CellSpacingHorz, CellSpacingVert: Integer; Border: Boolean; Light, Dark: TColor); virtual; abstract;
|
||
|
procedure DrawLogic2(Canvas: TCanvas; Y, CellSpacingHorz, CellSpacingVert : Integer; var Curs: Integer); virtual; abstract;
|
||
|
public
|
||
|
function Clone(Parent: TfrxHtBlock): TfrxHtfrcHtCellObjBase; virtual; abstract;
|
||
|
procedure AssignTo(Destin: TfrxHtfrcHtCellObjBase); virtual;
|
||
|
property Cell: TfrxHtCellObjCell read GetCell;
|
||
|
property ColSpan: Integer read FColSpan write FColSpan; {column and row spans for this cell}
|
||
|
property RowSpan: Integer read FRowSpan write FRowSpan; {column and row spans for this cell}
|
||
|
property HzSpace: Integer read FHzSpace write FHzSpace;
|
||
|
property VrSpace: Integer read FVrSpace write FVrSpace;
|
||
|
property SpecHt: TSpecWidth read FSpecHt write FSpecHt; {Height as specified}
|
||
|
// BG, 12.01.2012: not C++-Builder compatible
|
||
|
// property SpecHtType: TWidthType read FSpecHt.VType write FSpecHt.VType; {Height as specified}
|
||
|
// property SpecHtValue: Double read FSpecHt.Value write FSpecHt.Value; {Height as specified}
|
||
|
property SpecWd: TSpecWidth read FSpecWd write FSpecWd; {Width as specified}
|
||
|
// BG, 12.01.2012: not C++-Builder compatible
|
||
|
// property SpecWdType: TWidthType read FSpecWd.VType write FSpecWd.VType; {Height as specified}
|
||
|
// property SpecWdValue: Double read FSpecWd.Value write FSpecWd.Value; {Height as specified}
|
||
|
end;
|
||
|
|
||
|
TfrxHtDummyCellObj = class(TfrxHtfrcHtCellObjBase)
|
||
|
{holds one dummy cell of the table}
|
||
|
protected
|
||
|
function GetCell: TfrxHtCellObjCell; override;
|
||
|
procedure Draw(Canvas: TCanvas; const ARect: TRect; X, Y, CellSpacingHorz, CellSpacingVert: Integer; Border: Boolean; Light, Dark: TColor); override;
|
||
|
procedure DrawLogic2(Canvas: TCanvas; Y, CellSpacingHorz, CellSpacingVert : Integer; var Curs: Integer); override;
|
||
|
public
|
||
|
constructor Create(RSpan: Integer);
|
||
|
function Clone(Parent: TfrxHtBlock): TfrxHtfrcHtCellObjBase; override;
|
||
|
end;
|
||
|
|
||
|
TfrxHtCellObj = class(TfrxHtfrcHtCellObjBase)
|
||
|
{holds one cell of the table and some other information}
|
||
|
private
|
||
|
// BEGIN: this area is copied by move() in CreateCopy() - NO string types allowed!
|
||
|
FWd: Integer; {total width (may cover more than one column)}
|
||
|
FHt: Integer; {total height (may cover more than one row)}
|
||
|
FVSize: Integer; {Actual vertical size of contents}
|
||
|
FYIndent: Integer; {Vertical indent}
|
||
|
FVAlign: ThtAlignmentStyle; {Top, Middle, or Bottom}
|
||
|
FEmSize, FExSize: Integer;
|
||
|
FPRec: PtPositionRec; // background image position info
|
||
|
FPad: TRect;
|
||
|
FBrd: TRect;
|
||
|
FHideOverflow: Boolean;
|
||
|
FHasBorderStyle: Boolean;
|
||
|
FShowEmptyCells: Boolean;
|
||
|
// END: this area is copied by move() in CreateCopy()
|
||
|
FCell: TfrxHtCellObjCell;
|
||
|
procedure Initialize(TablePadding: Integer; const BkImageName: ThtString; const APRec: PtPositionRec; Border: Boolean);
|
||
|
protected
|
||
|
function GetCell: TfrxHtCellObjCell; override;
|
||
|
procedure Draw(Canvas: TCanvas; const ARect: TRect; X, Y, CellSpacingHorz, CellSpacingVert : Integer; Border: Boolean; Light, Dark: TColor); override;
|
||
|
procedure DrawLogic2(Canvas: TCanvas; Y, CellSpacingHorz, CellSpacingVert: Integer; var Curs: Integer); override;
|
||
|
private
|
||
|
|
||
|
// BG, 08.01.2012: Issue 109: C++Builder cannot handle properties that reference record members.
|
||
|
// - added for legacy support only, will be removed in a near future release.
|
||
|
// Please use properties Border and Padding instead.
|
||
|
function GetBorderBottom: Integer;
|
||
|
function GetBorderLeft: Integer;
|
||
|
function GetBorderRight: Integer;
|
||
|
function GetBorderTop: Integer;
|
||
|
function GetPaddingBottom: Integer;
|
||
|
function GetPaddingLeft: Integer;
|
||
|
function GetPaddingRight: Integer;
|
||
|
function GetPaddingTop: Integer;
|
||
|
procedure SetBorderBottom(const Value: Integer);
|
||
|
procedure SetBorderLeft(const Value: Integer);
|
||
|
procedure SetBorderRight(const Value: Integer);
|
||
|
procedure SetBorderTop(const Value: Integer);
|
||
|
procedure SetPaddingBottom(const Value: Integer);
|
||
|
procedure SetPaddingLeft(const Value: Integer);
|
||
|
procedure SetPaddingRight(const Value: Integer);
|
||
|
procedure SetPaddingTop(const Value: Integer);
|
||
|
public
|
||
|
|
||
|
NeedDoImageStuff: Boolean;
|
||
|
BGImage: TfrxFrHtImageObj;
|
||
|
TiledImage: TfrxHtImage;
|
||
|
MargArray: ThtMarginArray;
|
||
|
MargArrayO: ThtVMarginArray;
|
||
|
NoMask: Boolean;
|
||
|
BreakBefore, BreakAfter, KeepIntact: Boolean;
|
||
|
|
||
|
constructor Create(Parent: TfrxHtTableBlock; AVAlign: ThtAlignmentStyle; Attr: TfrxHtAttributeList; Prop: TfrxHTProperties);
|
||
|
constructor CreateCopy(Parent: TfrxHtBlock; T: TfrxHtCellObj);
|
||
|
destructor Destroy; override;
|
||
|
function Clone(Parent: TfrxHtBlock): TfrxHtfrcHtCellObjBase; override;
|
||
|
procedure AssignTo(Destin: TfrxHtfrcHtCellObjBase); override;
|
||
|
|
||
|
property Border: TRect read FBrd write FBrd; //was: BrdTop, BrdRight, BrdBottom, BrdLeft: Integer;
|
||
|
property BrdBottom: Integer read getBorderBottom write setBorderBottom;
|
||
|
property BrdLeft: Integer read getBorderLeft write setBorderLeft;
|
||
|
property BrdRight: Integer read getBorderRight write setBorderRight;
|
||
|
property BrdTop: Integer read getBorderTop write setBorderTop;
|
||
|
property Cell: TfrxHtCellObjCell read FCell;
|
||
|
property EmSize: Integer read FEmSize write FEmSize;
|
||
|
property ExSize: Integer read FExSize write FExSize;
|
||
|
property HasBorderStyle: Boolean read FHasBorderStyle write FHasBorderStyle;
|
||
|
property Ht: Integer read FHt {write FHt}; {total height (may cover more than one row)}
|
||
|
property Padding: TRect read FPad write FPad; //was: PadTop, PadRight, PadBottom, PadLeft: Integer;
|
||
|
property PadBottom: Integer read getPaddingBottom write setPaddingBottom;
|
||
|
property PadLeft: Integer read getPaddingLeft write setPaddingLeft;
|
||
|
property PadRight: Integer read getPaddingRight write setPaddingRight;
|
||
|
property PadTop: Integer read getPaddingTop write setPaddingTop;
|
||
|
property PRec: PtPositionRec read FPRec write FPRec;
|
||
|
property ShowEmptyCells: Boolean read FShowEmptyCells write FShowEmptyCells;
|
||
|
property HideOverflow: Boolean read FHideOverflow write FHideOverflow;
|
||
|
property VAlign: ThtAlignmentStyle read FVAlign write FVAlign; {Top, Middle, or Bottom}
|
||
|
property VSize: Integer read FVSize write FVSize; {Actual vertical size of contents}
|
||
|
property Wd: Integer read FWd write FWd; {total width (may cover more than one column)}
|
||
|
property YIndent: Integer read FYIndent write FYIndent; {Vertical indent}
|
||
|
end;
|
||
|
|
||
|
TfrxHtCellList = class(TObjectList)
|
||
|
{holds one row of the html table, a list of TfrxHtCellObj}
|
||
|
private
|
||
|
function GetCellObj(Index: Integer): TfrxHtfrcHtCellObjBase; {$ifdef UseInline} inline; {$endif}
|
||
|
public
|
||
|
RowHeight: Integer;
|
||
|
SpecRowHeight: TSpecWidth;
|
||
|
RowSpanHeight: Integer; {height of largest rowspan}
|
||
|
BkGnd: Boolean;
|
||
|
BkColor: TColor;
|
||
|
BkImage: ThtString;
|
||
|
APRec: PtPositionRec;
|
||
|
BreakBefore, BreakAfter, KeepIntact: Boolean;
|
||
|
RowType: TRowType;
|
||
|
|
||
|
constructor Create(Attr: TfrxHtAttributeList; Prop: TfrxHTProperties);
|
||
|
constructor CreateCopy(Parent: TfrxHtBlock; T: TfrxHtCellList);
|
||
|
procedure Initialize;
|
||
|
function DrawLogicA(Canvas: TCanvas; const Widths: TIntArray; Span, CellSpacingHorz,CellSpacingVert, AHeight, Rows: Integer;
|
||
|
out Desired: Integer; out Spec, More: Boolean): Integer;
|
||
|
procedure DrawLogicB(Canvas: TCanvas; Y, CellSpacingHorz, CellSpacingVert: Integer; var Curs: Integer);
|
||
|
function Draw(Canvas: TCanvas; Document: TfrxHtDocument; const ARect: TRect; const Widths: TIntArray;
|
||
|
X, Y, YOffset, CellSpacingHorz,CellSpacingVert: Integer; Border: Boolean; Light, Dark: TColor; MyRow: Integer): Integer;
|
||
|
procedure Add(CellObjBase: TfrxHtfrcHtCellObjBase);
|
||
|
procedure RTLSwap;
|
||
|
|
||
|
property Items[Index: Integer]: TfrxHtfrcHtCellObjBase read GetCellObj; default;
|
||
|
end;
|
||
|
|
||
|
// BG, 26.12.2011:
|
||
|
TfrxHtRowList = class(TObjectList)
|
||
|
private
|
||
|
function GetItem(Index: Integer): TfrxHtCellList; {$ifdef UseInline} inline; {$endif}
|
||
|
public
|
||
|
procedure RTLSwap;
|
||
|
property Items[Index: Integer]: TfrxHtCellList read GetItem; default;
|
||
|
end;
|
||
|
|
||
|
TfrxHtColSpec = class
|
||
|
private
|
||
|
FWidth: TSpecWidth;
|
||
|
FAlign: ThtString;
|
||
|
FVAlign: ThtAlignmentStyle;
|
||
|
public
|
||
|
constructor Create(const Width: TSpecWidth; Align: ThtString; VAlign: ThtAlignmentStyle);
|
||
|
constructor CreateCopy(const ColSpec: TfrxHtColSpec);
|
||
|
property ColWidth: TSpecWidth read FWidth;
|
||
|
property ColAlign: ThtString read FAlign;
|
||
|
property ColVAlign: ThtAlignmentStyle read FVAlign;
|
||
|
end;
|
||
|
|
||
|
// BG, 26.12.2011:
|
||
|
TfrxHtColSpecList = class(TObjectList)
|
||
|
private
|
||
|
function GetItem(Index: Integer): TfrxHtColSpec; {$ifdef UseInline} inline; {$endif}
|
||
|
public
|
||
|
property Items[Index: Integer]: TfrxHtColSpec read GetItem; default;
|
||
|
end;
|
||
|
|
||
|
TfrxHtmlTable = class;
|
||
|
|
||
|
TfrxHtTableBlock = class(TfrxHtBlock)
|
||
|
protected
|
||
|
function GetBorderWidth: Integer; override;
|
||
|
public
|
||
|
Table: TfrxHtmlTable;
|
||
|
|
||
|
WidthAttr: Integer;
|
||
|
AsPercent: Boolean;
|
||
|
BkColor: TColor;
|
||
|
BkGnd: Boolean;
|
||
|
HSpace, VSpace: Integer;
|
||
|
HasCaption: Boolean;
|
||
|
TableBorder: Boolean;
|
||
|
|
||
|
TableIndent: Integer;
|
||
|
|
||
|
constructor Create(Parent: TfrxHtCellBasic; Attr: TfrxHtAttributeList; Prop: TfrxHTProperties; TableLevel: Integer);
|
||
|
constructor CreateCopy(OwnerCell: TfrxHtCellBasic; Source: TfrxHtmlNode); override;
|
||
|
function DrawLogic1(Canvas: TCanvas; X, Y, XRef, YRef, AWidth, AHeight, BlHt: Integer; IMgr: TfrxHtIndentManager; var MaxWidth, Curs: Integer; ARemainHeight: Integer = 0): Integer; override;
|
||
|
function Draw1(Canvas: TCanvas; const ARect: TRect; IMgr: TfrxHtIndentManager; X, XRef, YRef: Integer): Integer; override;
|
||
|
procedure MinMaxWidth(Canvas: TCanvas; out Min, Max: Integer; AvailableWidth, AvailableHeight: Integer); override;
|
||
|
function FindWidth(Canvas: TCanvas; AWidth, AHeight, AutoCount: Integer): Integer; override;
|
||
|
function FindWidth1(Canvas: TCanvas; AWidth, AHeight, ExtMarg: Integer): Integer;
|
||
|
procedure AddSectionsToList; override;
|
||
|
end;
|
||
|
|
||
|
TfrxHtTableAndCaptionBlock = class(TfrxHtBlock)
|
||
|
private
|
||
|
procedure SetCaptionBlock(Value: TfrxHtBlock);
|
||
|
public
|
||
|
TopCaption: Boolean;
|
||
|
TableBlock: TfrxHtTableBlock;
|
||
|
FCaptionBlock: TfrxHtBlock;
|
||
|
TableID: ThtString;
|
||
|
constructor Create(Parent: TfrxHtCellBasic; Attributes: TfrxHtAttributeList; Prop: TfrxHTProperties; ATableBlock: TfrxHtTableBlock);
|
||
|
constructor CreateCopy(OwnerCell: TfrxHtCellBasic; Source: TfrxHtmlNode); override;
|
||
|
procedure CancelUsage;
|
||
|
function FindWidth(Canvas: TCanvas; AWidth, AHeight, AutoCount: Integer): Integer; override;
|
||
|
procedure MinMaxWidth(Canvas: TCanvas; out Min, Max: Integer; AvailableWidth, AvailableHeight: Integer); override;
|
||
|
function FindDocPos(SourcePos: Integer; Prev: Boolean): Integer; override;
|
||
|
property CaptionBlock: TfrxHtBlock read FCaptionBlock write SetCaptionBlock;
|
||
|
end;
|
||
|
|
||
|
TfrxHtmlTable = class(TfrxHtSectionBase)
|
||
|
private
|
||
|
FOwnerTableBlock: TfrxHtTableBlock;
|
||
|
TablePartRec: TTablePartRec;
|
||
|
HeaderHeight, HeaderRowCount, FootHeight, FootStartRow, FootOffset: Integer;
|
||
|
BodyBreak: Integer;
|
||
|
HeadOrFoot: Boolean;
|
||
|
FColSpecs: TfrxHtColSpecList; // Column width specifications
|
||
|
// calculated in GetMinMaxWidths
|
||
|
Percents: TIntArray; {percent widths of columns}
|
||
|
Multis: TIntArray; {multi widths of columns}
|
||
|
MaxWidths: TIntArray;
|
||
|
MinWidths: TIntArray;
|
||
|
ColumnCounts: TIntegerPerWidthType;
|
||
|
ColumnSpecs: TWidthTypeArray;
|
||
|
CycleNumber: Integer;
|
||
|
// these fields are copied via Move() in CreateCopy. Don't add reference counted data like strings and arrays.
|
||
|
Initialized: Boolean;
|
||
|
brdWidthAttr: Integer; {Width attribute as entered}
|
||
|
HasBorderWidthAttr: Boolean; {width of border has been set by attr}
|
||
|
Frame: TTableFrame;
|
||
|
Float: Boolean; {if floating}
|
||
|
NumCols: Integer; {Number columns in table}
|
||
|
TableWidth: Integer; {width of table}
|
||
|
tblWidthAttr: Integer; {Width attribute as entered}
|
||
|
FCellPadding: Integer;
|
||
|
FCellSpacingHorz, FCellSpacingVert: Integer;
|
||
|
BorderColorLight: TColor;
|
||
|
BorderColorDark: TColor;
|
||
|
EndList: Boolean; {marker for copy}
|
||
|
// end of Move()d fields
|
||
|
DrawX: Integer;
|
||
|
//DrawY: Integer;
|
||
|
FBkGnd: Boolean;
|
||
|
FBkColor: TColor;
|
||
|
Widths: TIntArray; {holds calculated column widths}
|
||
|
Heights: TIntArray; {holds calculated row heights}
|
||
|
//
|
||
|
procedure IncreaseWidthsByWidth(WidthType: TWidthType; var Widths: TIntArray; StartIndex, EndIndex, Required, Spanned, Count: Integer);
|
||
|
procedure IncreaseWidthsByPercentage(var Widths: TIntArray; StartIndex, EndIndex, Required, Spanned, Percent, Count: Integer);
|
||
|
procedure IncreaseWidthsByMinMaxDelta(WidthType: TWidthType; var Widths: TIntArray; StartIndex, EndIndex, Excess, DeltaWidth, Count: Integer; const Deltas: TIntArray);
|
||
|
procedure IncreaseWidthsRelatively(var Widths: TIntArray; StartIndex, EndIndex, Required, SpannedMultis: Integer; ExactRelation: Boolean);
|
||
|
procedure IncreaseWidthsEvenly(WidthType: TWidthType; var Widths: TIntArray; StartIndex, EndIndex, Required, Spanned, Count: Integer);
|
||
|
procedure Initialize; // add dummy cells, initialize cells, prepare arrays
|
||
|
procedure GetMinMaxWidths(Canvas: TCanvas; AvailableWidth, AvailableHeight: Integer);
|
||
|
protected
|
||
|
procedure Reverse(A: TIntArray); overload;
|
||
|
procedure Reverse(A: TWidthTypeArray); overload;
|
||
|
public
|
||
|
Rows: TfrxHtRowList; {a list of TCellLists}
|
||
|
Rules: TTableRules;
|
||
|
BorderWidth: Integer; {width of border}
|
||
|
BorderColor: TColor; //BG, 13.06.2010: added for Issue 5: Table border versus stylesheets
|
||
|
|
||
|
constructor Create(OwnerTableBlock: TfrxHtTableBlock; Parent: TfrxHtCellBasic; Attr: TfrxHtAttributeList; Prop: TfrxHTProperties);
|
||
|
constructor CreateCopy(OwnerCell: TfrxHtCellBasic; Source: TfrxHtmlNode); override;
|
||
|
destructor Destroy; override;
|
||
|
procedure DoColumns(Count: Integer; const SpecWidth: TSpecWidth; VAlign: ThtAlignmentStyle; const Align: ThtString);
|
||
|
procedure MinMaxWidth(Canvas: TCanvas; out Min, Max: Integer; AvailableWidth, AvailableHeight: Integer); override;
|
||
|
function DrawLogic1(Canvas: TCanvas; X, Y, XRef, YRef, AWidth, AHeight, BlHt: Integer; IMgr: TfrxHtIndentManager; var MaxWidth, Curs: Integer; ARemainHeight: Integer = 0): Integer; override;
|
||
|
function Draw1(Canvas: TCanvas; const ARect: TRect; IMgr: TfrxHtIndentManager; X, XRef, YRef: Integer): Integer; override;
|
||
|
function GetChAtPos(Pos: Integer; out Ch: WideChar; out Obj: TfrxHtSectionBase): Boolean; override;
|
||
|
function FindString(From: Integer; const ToFind: UnicodeString; MatchCase: Boolean): Integer; override;
|
||
|
function FindStringR(From: Integer; const ToFind: UnicodeString; MatchCase: Boolean): Integer; override;
|
||
|
function FindSourcePos(DocPos: Integer): Integer; override;
|
||
|
function FindDocPos(SourcePos: Integer; Prev: Boolean): Integer; override;
|
||
|
property ColSpecs: TfrxHtColSpecList read FColSpecs;
|
||
|
property TableHeight: Integer read SectionHeight write SectionHeight; {height of table itself, not incl caption}
|
||
|
property CellPadding: Integer read FCellPadding;
|
||
|
property CellSpacingHorz: Integer read FCellSpacingHorz;
|
||
|
property CellSpacingVert: Integer read FCellSpacingVert;
|
||
|
property BkGnd: Boolean read FBkGnd;
|
||
|
property BkColor: TColor read FBkColor;
|
||
|
end;
|
||
|
|
||
|
//------------------------------------------------------------------------------
|
||
|
// TfrxHtChPosObj, a pseudo object for ID attributes.
|
||
|
//------------------------------------------------------------------------------
|
||
|
// It is a general purpose ID marker, that finds its position by byte
|
||
|
// position in the document buffer. This object is deprecated.
|
||
|
// The corresponding tag object has to be added to the IDNameList instead.
|
||
|
//------------------------------------------------------------------------------
|
||
|
|
||
|
// deprecated
|
||
|
TfrxHtChPosObj = class(TfrxHtIDObject)
|
||
|
private
|
||
|
FDocument: TfrxHtDocument;
|
||
|
FChPos: Integer;
|
||
|
protected
|
||
|
function GetYPosition: Integer; override;
|
||
|
function FreeMe: Boolean; override;
|
||
|
public
|
||
|
constructor Create(Document: TfrxHtDocument; Pos: Integer);
|
||
|
property ChPos: Integer read FChPos write FChPos;
|
||
|
property Document: TfrxHtDocument read FDocument;
|
||
|
end;
|
||
|
|
||
|
//------------------------------------------------------------------------------
|
||
|
// TfrxHtDocument, a complete html document, that can draw itself on a canvas.
|
||
|
//------------------------------------------------------------------------------
|
||
|
|
||
|
TExpandNameEvent = procedure(Sender: TObject; const SRC: ThtString; var Result: ThtString) of object;
|
||
|
|
||
|
TfrxHtmlStyleList = class(TfrxHtStyleList) {a list of all the styles -- the stylesheet}
|
||
|
private
|
||
|
Document: TfrxHtDocument;
|
||
|
protected
|
||
|
procedure SetLinksActive(Value: Boolean); override;
|
||
|
public
|
||
|
constructor Create(AMasterList: TfrxHtDocument);
|
||
|
end;
|
||
|
|
||
|
TfrxHtmlPropStack = class(TfrxHtPropStack)
|
||
|
public
|
||
|
Document: TfrxHtDocument;
|
||
|
SIndex: Integer; //BG, 26.12.2010: seems, this is the current position in the original html-file.
|
||
|
procedure PopAProp(Sym: TElemSymb);
|
||
|
procedure PopProp;
|
||
|
procedure PushNewProp(Sym: TElemSymb; Properties: TfrxHTProperties; Attributes: TfrxHtAttributeList; const APseudo: ThtString = '');
|
||
|
end;
|
||
|
|
||
|
TfrxHtDocument = class(TfrxHtCell) {a list of all the sections -- the html document}
|
||
|
private
|
||
|
FPropStack: TfrxHtmlPropStack;
|
||
|
FPageArea: TRect;
|
||
|
FPrinted: Boolean; {set if actually printed anything else but background}
|
||
|
procedure AddSectionsToPositionList(Sections: TfrxHtSectionBase);
|
||
|
procedure SetPageArea(const Value: TRect);
|
||
|
function GetViewPort: TRect;
|
||
|
procedure SetPrinted(const Value: Boolean);
|
||
|
public
|
||
|
|
||
|
// copied by move() in CreateCopy()
|
||
|
ShowImages: Boolean; {set if showing images}
|
||
|
YOff: Integer; {marks top of window that's displayed}
|
||
|
YOffChange: Boolean; {when above changes}
|
||
|
XOffChange: Boolean; {when x offset changes}
|
||
|
NoPartialLine: Boolean; {set when printing if no partial line allowed at page bottom}
|
||
|
LinkVisitedColor, LinkActiveColor, HotSpotColor: TColor;
|
||
|
PrintTableBackground: Boolean;
|
||
|
PrintBackground: Boolean;
|
||
|
PrintMonoBlack: Boolean;
|
||
|
TheOwner: TfrxHtmlViewerBase; {the viewer that owns this document}
|
||
|
GetImage: TGetImageEvent; {for OnImageRequest Event}
|
||
|
GottenImage: TGottenImageEvent; {for OnImageRequest Event}
|
||
|
OnExpandName: TExpandNameEvent;
|
||
|
FileBrowse: TFileBrowseEvent;
|
||
|
BackGround: TColor;
|
||
|
// end of copied by move() in CreateCopy()
|
||
|
// don't copy strings via move()
|
||
|
PreFontName: TFontName; {<pre>, <code> font for document}
|
||
|
|
||
|
OnBackgroundChange: TNotifyEvent;
|
||
|
BackgroundImage: TfrxHtImage;
|
||
|
BackgroundImagePosition: PtPositionRec;
|
||
|
BackgroundImageName: ThtString; {name of background bitmap}
|
||
|
BackgroundImageLoaded: Boolean; {if background bitmap is loaded}
|
||
|
ScriptEvent: TScriptEvent;
|
||
|
PageBottom: Integer;
|
||
|
PageShortened: Boolean;
|
||
|
MissingImages: ThtStringList; {images to be supplied later}
|
||
|
ControlEnterEvent: TNotifyEvent;
|
||
|
LinkList: TfrxHtLinkList; {List of links (TfrxHtFontObj's)}
|
||
|
LinksActive: Boolean;
|
||
|
ShowDummyCaret: Boolean;
|
||
|
Styles: TfrxHtmlStyleList; {the stylesheet}
|
||
|
DrawList: TfrxHtDrawList;
|
||
|
FirstLineHtPtr: PInteger;
|
||
|
IDNameList: TfrxHtIDObjectList;
|
||
|
PositionList: TfrxHtSectionBaseList;
|
||
|
ImageCache: TfrxHtImageCache;
|
||
|
SectionCount: Integer;
|
||
|
CycleNumber: Integer;
|
||
|
IsCopy: Boolean; {set when printing or making bitmap/metafile}
|
||
|
NoOutput: Boolean;
|
||
|
FirstPageItem: Boolean;
|
||
|
StopTab: Boolean;
|
||
|
InlineList: TObjectList; {actually TInlineList, a list of ThtInlineRec's}
|
||
|
TableNestLevel: Integer;
|
||
|
InLogic2: Boolean;
|
||
|
LinkDrawnEvent: TLinkDrawnEvent;
|
||
|
LinkPage: Integer;
|
||
|
PrintingTable: TfrxHtmlTable;
|
||
|
ScaleX, ScaleY: single;
|
||
|
SkipDraw: Boolean;
|
||
|
FNoBreak : Boolean;
|
||
|
FCurrentStyle: TFontStyles;
|
||
|
|
||
|
constructor Create(Owner: TfrxHtmlViewerBase);
|
||
|
constructor CreateCopy(T: TfrxHtDocument);
|
||
|
destructor Destroy; override;
|
||
|
function AddChPosObjectToIDNameList(const S: ThtString; Pos: Integer): Integer; {$ifdef UseInline} inline; {$endif}
|
||
|
function DoLogic(Canvas: TCanvas; Y: Integer; Width, AHeight, BlHt: Integer; var ScrollWidth, Curs: Integer; ARemainHeight: Integer = 0): Integer; override;
|
||
|
function Draw(Canvas: TCanvas; ARect: TRect; ClipWidth, X: Integer; Y, XRef, YRef: Integer): Integer; override;
|
||
|
function FindDocPos(SourcePos: Integer; Prev: Boolean): Integer; override;
|
||
|
function FindSectionAtPosition(Pos: Integer; out TopPos, Index: Integer): TfrxHtSectionBase;
|
||
|
function GetTheImage(const BMName: ThtString; var Transparent: ThtImageTransparency; out FromCache, Delay: Boolean): TfrxHtImage;
|
||
|
procedure Clear; override;
|
||
|
procedure GetBackgroundImage;
|
||
|
procedure ProcessInlines(SIndex: Integer; Prop: TfrxHTProperties; Start: Boolean);
|
||
|
procedure SetBackground(ABackground: TColor);
|
||
|
procedure SetBackgroundImage(const Name: ThtString; const APrec: PtPositionRec);
|
||
|
procedure SetYOffset(Y: Integer);
|
||
|
procedure SetFonts(const Name, PreName: ThtString; ASize: Double;
|
||
|
AColor, AHotSpot, AVisitedColor, AActiveColor, ABackground: TColor; LnksActive, LinkUnderLine: Boolean;
|
||
|
ACodePage: TBuffCodePage; ACharSet: TFontCharSet; MarginHeight, MarginWidth: Integer);
|
||
|
property PropStack : TfrxHtmlPropStack read FPropStack write FPropStack;
|
||
|
property Printed: Boolean read FPrinted write SetPrinted;
|
||
|
|
||
|
property NoBreak : Boolean read FNoBreak write FNoBreak; {set when in <NoBr>}
|
||
|
property ViewPort: TRect read GetViewPort; {ViewPort is the APaintPanel's client rect, except while printing}
|
||
|
property PageArea: TRect write SetPageArea; {is the ViewPort while printing, set by THtmlViewer.Print}
|
||
|
|
||
|
property CurrentStyle: TFontStyles read FCurrentStyle write FCurrentStyle; {as set by <b>, <i>, etc.}
|
||
|
end;
|
||
|
|
||
|
//------------------------------------------------------------------------------
|
||
|
// some more base sections
|
||
|
//------------------------------------------------------------------------------
|
||
|
|
||
|
TfrxHtLineBreak = class(TfrxHtSectionBase)
|
||
|
protected
|
||
|
function TryGetClear(var Clear: ThtClearStyle): Boolean; override;
|
||
|
end;
|
||
|
|
||
|
TfrxHtPage = class(TfrxHtSectionBase)
|
||
|
public
|
||
|
constructor Create(Parent: TfrxHtCellBasic; Attributes: TfrxHtAttributeList; Properties: TfrxHTProperties);
|
||
|
function Draw1(Canvas: TCanvas; const ARect: TRect; IMgr: TfrxHtIndentManager; X, XRef, YRef: Integer): Integer; override;
|
||
|
end;
|
||
|
|
||
|
TfrxHtHorzLine = class(TfrxHtSectionBase) {a horizontal line, <hr>}
|
||
|
public
|
||
|
VSize: Integer;
|
||
|
Color: TColor;
|
||
|
Align: ThtJustify;
|
||
|
UseDefBorder: Boolean;
|
||
|
NoShade: Boolean;
|
||
|
BkGnd: Boolean;
|
||
|
Width, Indent: Integer;
|
||
|
|
||
|
constructor Create(Parent: TfrxHtCellBasic; L: TfrxHtAttributeList; Prop: TfrxHTProperties);
|
||
|
constructor CreateCopy(Parent: TfrxHtCellBasic; Source: TfrxHtmlNode); override;
|
||
|
function DrawLogic1(Canvas: TCanvas; X, Y, XRef, YRef, AWidth, AHeight, BlHt: Integer; IMgr: TfrxHtIndentManager; var MaxWidth, Curs: Integer; ARemainHeight: Integer = 0): Integer; override;
|
||
|
function Draw1(Canvas: TCanvas; const ARect: TRect; IMgr: TfrxHtIndentManager; X, XRef, YRef: Integer): Integer; override;
|
||
|
end;
|
||
|
|
||
|
TfrxHtPreFormated = class(TfrxHtSection)
|
||
|
// {section for preformated, <pre>}
|
||
|
// public
|
||
|
// procedure ProcessText(TagIndex: Integer); override;
|
||
|
// function DrawLogic(Canvas: TCanvas; X, Y, XRef, YRef, AWidth, AHeight, BlHt: Integer; IMgr: TfrxHtIndentManager;
|
||
|
// var MaxWidth, Curs: Integer): Integer; override;
|
||
|
// procedure MinMaxWidth(Canvas: TCanvas; out Min, Max: Integer); override;
|
||
|
end;
|
||
|
|
||
|
var
|
||
|
WaitStream: TMemoryStream;
|
||
|
ErrorStream: TMemoryStream;
|
||
|
WaitBitmap: TBitmap;
|
||
|
ErrorBitmap: TBitmap;
|
||
|
{$ifdef UNICODE}
|
||
|
{$else}
|
||
|
UnicodeControls: Boolean;
|
||
|
{$endif}
|
||
|
|
||
|
implementation
|
||
|
|
||
|
uses
|
||
|
{$ifdef UseVCLStyles}
|
||
|
System.Types,
|
||
|
System.UITypes,
|
||
|
Vcl.Themes,
|
||
|
VCL.Controls,
|
||
|
{$endif}
|
||
|
{$ifdef Compiler28_Plus}
|
||
|
System.NetEncoding,
|
||
|
{$endif}
|
||
|
frxHTMLViewer, frxUtils,
|
||
|
frxProtocolFactory;
|
||
|
|
||
|
type
|
||
|
TSameWidthFix = class
|
||
|
private
|
||
|
FAtLeastOneFix: Boolean;
|
||
|
FNeedFix: array of Boolean;
|
||
|
FFirstIndex: TIntArray;
|
||
|
public
|
||
|
constructor Create(Widths, MinWidths, MaxWidths: TIntArray; ColumnSpecs: TWidthTypeArray);
|
||
|
procedure Fix(Widths: TIntArray);
|
||
|
end;
|
||
|
|
||
|
//-- BG ---------------------------------------------------------- 14.01.2012 --
|
||
|
function Sum(const Arr: TIntArray; StartIndex, EndIndex: Integer): Integer; overload;
|
||
|
{$ifdef UseInline} inline; {$endif}
|
||
|
// Return sum of array elements from StartIndex to EndIndex.
|
||
|
var
|
||
|
I: Integer;
|
||
|
begin
|
||
|
Result := 0;
|
||
|
for I := StartIndex to EndIndex do
|
||
|
Inc(Result, Arr[I]);
|
||
|
end;
|
||
|
|
||
|
//-- BG ---------------------------------------------------------- 14.01.2012 --
|
||
|
function Sum(const Arr: TIntArray): Integer; overload;
|
||
|
{$ifdef UseInline} inline; {$endif}
|
||
|
// Return sum of all array elements.
|
||
|
begin
|
||
|
Result := Sum(Arr, Low(Arr), High(Arr));
|
||
|
end;
|
||
|
|
||
|
//-- BG ---------------------------------------------------------- 14.01.2012 --
|
||
|
function Sum(const Arr: TIntegerPerWidthType; StartIndex, EndIndex: TWidthType): Integer; overload;
|
||
|
{$ifdef UseInline} inline; {$endif}
|
||
|
// Return sum of array elements from StartIndex to EndIndex.
|
||
|
var
|
||
|
I: TWidthType;
|
||
|
begin
|
||
|
Result := 0;
|
||
|
for I := StartIndex to EndIndex do
|
||
|
Inc(Result, Arr[I]);
|
||
|
end;
|
||
|
|
||
|
//-- BG ---------------------------------------------------------- 14.01.2012 --
|
||
|
function Sum(const Arr: TIntegerPerWidthType): Integer; overload;
|
||
|
{$ifdef UseInline} inline; {$endif}
|
||
|
// Return sum of all array elements.
|
||
|
begin
|
||
|
Result := Sum(Arr, Low(Arr), High(Arr));
|
||
|
end;
|
||
|
|
||
|
//-- BG ---------------------------------------------------------- 17.01.2012 --
|
||
|
function SubArray(const Arr, Minus: TIntArray): TIntArray;
|
||
|
{$ifdef UseInline} inline; {$endif}
|
||
|
// Return array with differences per index.
|
||
|
var
|
||
|
I: Integer;
|
||
|
begin
|
||
|
Result := Copy(Arr);
|
||
|
for I := 0 to Min(High(Result), High(Minus)) do
|
||
|
Dec(Result[I], Minus[I]);
|
||
|
end;
|
||
|
|
||
|
//-- BG ---------------------------------------------------------- 16.01.2012 --
|
||
|
procedure SetArray(var Arr: TIntArray; Value, StartIndex, EndIndex: Integer); overload;
|
||
|
{$ifdef UseInline} inline; {$endif}
|
||
|
var
|
||
|
I: Integer;
|
||
|
begin
|
||
|
for I := StartIndex to EndIndex do
|
||
|
Arr[I] := Value;
|
||
|
end;
|
||
|
|
||
|
//-- BG ---------------------------------------------------------- 16.01.2012 --
|
||
|
procedure SetArray(var Arr: TIntArray; Value: Integer); overload;
|
||
|
{$ifdef UseInline} inline; {$endif}
|
||
|
begin
|
||
|
SetArray(Arr, Value, Low(Arr), High(Arr));
|
||
|
end;
|
||
|
|
||
|
//-- BG ---------------------------------------------------------- 16.01.2012 --
|
||
|
procedure SetArray(var Arr: TIntegerPerWidthType; Value: Integer); overload;
|
||
|
{$ifdef UseInline} inline; {$endif}
|
||
|
var
|
||
|
I: TWidthType;
|
||
|
begin
|
||
|
for I := Low(TWidthType) to High(TWidthType) do
|
||
|
Arr[I] := Value;
|
||
|
end;
|
||
|
|
||
|
//-- BG ---------------------------------------------------------- 18.01.2012 --
|
||
|
procedure CountsPerType(
|
||
|
out CountsPerType: TIntegerPerWidthType;
|
||
|
const ColumnSpecs: TWidthTypeArray;
|
||
|
StartIndex, EndIndex: Integer);
|
||
|
{$ifdef UseInline} inline; {$endif}
|
||
|
var
|
||
|
I: Integer;
|
||
|
begin
|
||
|
SetArray(CountsPerType, 0);
|
||
|
for I := StartIndex to EndIndex do
|
||
|
Inc(CountsPerType[ColumnSpecs[I]]);
|
||
|
end;
|
||
|
|
||
|
//-- BG ---------------------------------------------------------- 19.01.2012 --
|
||
|
function SumOfType(
|
||
|
WidthType: TWidthType;
|
||
|
const ColumnSpecs: TWidthTypeArray;
|
||
|
const Widths: TIntArray;
|
||
|
StartIndex, EndIndex: Integer): Integer;
|
||
|
{$ifdef UseInline} inline; {$endif}
|
||
|
var
|
||
|
I: Integer;
|
||
|
begin
|
||
|
Result := 0;
|
||
|
for I := StartIndex to EndIndex do
|
||
|
if ColumnSpecs[I] = WidthType then
|
||
|
Inc(Result, Widths[I]);
|
||
|
end;
|
||
|
|
||
|
//-- BG ---------------------------------------------------------- 17.06.2012 --
|
||
|
function SumOfNotType(
|
||
|
WidthType: TWidthType;
|
||
|
const ColumnSpecs: TWidthTypeArray;
|
||
|
const Widths: TIntArray;
|
||
|
StartIndex, EndIndex: Integer): Integer;
|
||
|
{$ifdef UseInline} inline; {$endif}
|
||
|
var
|
||
|
I: Integer;
|
||
|
begin
|
||
|
Result := 0;
|
||
|
for I := StartIndex to EndIndex do
|
||
|
if ColumnSpecs[I] <> WidthType then
|
||
|
Inc(Result, Widths[I]);
|
||
|
end;
|
||
|
|
||
|
procedure InitializeFontSizes(Size: Double);
|
||
|
{$ifdef UseInline} inline; {$endif}
|
||
|
var
|
||
|
I: Integer;
|
||
|
begin
|
||
|
for I := 1 to 7 do
|
||
|
begin
|
||
|
FontConv[I] := FontConvBase[I] * Size / 12.0;
|
||
|
PreFontConv[I] := PreFontConvBase[I] * Size / 12.0;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
{ TfrxHtmlNode }
|
||
|
|
||
|
//-- BG ---------------------------------------------------------- 24.03.2011 --
|
||
|
procedure TfrxHtmlNode.AfterConstruction;
|
||
|
begin
|
||
|
inherited AfterConstruction;
|
||
|
|
||
|
if (Length(Id) > 0) and (Document <> nil) and (Document.IDNameList <> nil) then
|
||
|
Document.IDNameList.AddObject(Id, Self);
|
||
|
end;
|
||
|
|
||
|
//-- BG ---------------------------------------------------------- 07.09.2013 --
|
||
|
function TfrxHtmlNode.CalcDisplayExtern: ThtDisplayStyle;
|
||
|
begin
|
||
|
case FDisplay of
|
||
|
pdInlineBlock,
|
||
|
pdInlineTable:
|
||
|
Result := pdInline;
|
||
|
else
|
||
|
Result := FDisplay;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
//-- BG ---------------------------------------------------------- 07.09.2013 --
|
||
|
function TfrxHtmlNode.CalcDisplayIntern: ThtDisplayStyle;
|
||
|
begin
|
||
|
case FDisplay of
|
||
|
pdInlineTable:
|
||
|
Result := pdTable;
|
||
|
|
||
|
pdInlineBlock:
|
||
|
Result := pdBlock;
|
||
|
else
|
||
|
Result := FDisplay;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
//-- BG ---------------------------------------------------------- 24.03.2011 --
|
||
|
constructor TfrxHtmlNode.Create(Parent: TfrxHtCellBasic; Attributes: TfrxHtAttributeList; Properties: TfrxHTProperties; const ID: ThtString);
|
||
|
var
|
||
|
MargArrayO: ThtVMarginArray;
|
||
|
MargArray: ThtMarginArray;
|
||
|
Cd: ThtConvData;
|
||
|
begin
|
||
|
inherited Create(ID);
|
||
|
FOwnerCell := Parent;
|
||
|
if FOwnerCell <> nil then
|
||
|
begin
|
||
|
FOwnerBlock := FOwnerCell.OwnerBlock;
|
||
|
FDocument := FOwnerCell.Document;
|
||
|
end;
|
||
|
if Attributes <> nil then
|
||
|
FAttributes := Attributes.Clone;
|
||
|
if Properties <> nil then
|
||
|
FProperties := Properties.Clone;
|
||
|
// defaults are set automatically as Ord() of these defaults is 0:
|
||
|
// FDisplay := pdUnassigned;
|
||
|
// FFloating := aNone;
|
||
|
// FPositioning := posStatic;
|
||
|
TryGetClear(FClearing);
|
||
|
|
||
|
if FProperties <> nil then
|
||
|
begin
|
||
|
FDisplay := FProperties.Display;
|
||
|
FPositioning := FProperties.GetPosition;
|
||
|
if not FProperties.GetFloat(FFloating) or (FPositioning in [posAbsolute, posFixed]) then
|
||
|
FFloating := ANone;
|
||
|
FProperties.GetVMarginArray(MargArrayO);
|
||
|
FEmSize := FProperties.EmSize;
|
||
|
FExSize := FProperties.ExSize;
|
||
|
CD := ConvData(100, 100, FEmSize, FExSize, 0);
|
||
|
ConvMargProp(piTop , MargArrayO, CD, MargArray);
|
||
|
ConvMargProp(piLeft , MargArrayO, CD, MargArray);
|
||
|
ConvMargProp(piRight , MargArrayO, CD, MargArray);
|
||
|
ConvMargProp(piBottom, MargArrayO, CD, MargArray);
|
||
|
FPositions[reTop ] := MargArray[piTop ];
|
||
|
FPositions[reLeft ] := MargArray[piLeft ];
|
||
|
FPositions[reRight ] := MargArray[piRight ];
|
||
|
FPositions[reBottom] := MargArray[piBottom];
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
//-- BG ---------------------------------------------------------- 24.03.2011 --
|
||
|
constructor TfrxHtmlNode.CreateCopy(Parent: TfrxHtCellBasic; Source: TfrxHtmlNode);
|
||
|
begin
|
||
|
inherited Create( Source.HtmlId );
|
||
|
FOwnerCell := Parent;
|
||
|
begin
|
||
|
FOwnerBlock := FOwnerCell.OwnerBlock;
|
||
|
FDocument := FOwnerCell.Document;
|
||
|
end;
|
||
|
FAttributes := Source.FAttributes;
|
||
|
FProperties := Source.FProperties;
|
||
|
FClearing := Source.FClearing;
|
||
|
FDisplay := Source.FDisplay;
|
||
|
FPositioning := Source.FPositioning;
|
||
|
FPositions := Source.FPositions;
|
||
|
FFloating := Source.FFloating;
|
||
|
FIndent := Source.FIndent;
|
||
|
end;
|
||
|
|
||
|
//-- BG ---------------------------------------------------------- 21.10.2016 --
|
||
|
destructor TfrxHtmlNode.Destroy;
|
||
|
var
|
||
|
Idx: Integer;
|
||
|
begin
|
||
|
if (Length(Id) > 0) and (Document <> nil) and (Document.IDNameList <> nil) then
|
||
|
with Document.IdNameList do
|
||
|
begin
|
||
|
Idx := IndexOfObject(Self);
|
||
|
if Idx >= 0 then
|
||
|
Delete(Idx);
|
||
|
end;
|
||
|
|
||
|
if not IsCopy then
|
||
|
begin
|
||
|
FAttributes.Free;
|
||
|
FProperties.Free;
|
||
|
end;
|
||
|
inherited;
|
||
|
end;
|
||
|
|
||
|
//-- BG ---------------------------------------------------------- 24.02.2016 --
|
||
|
function TfrxHtmlNode.TryGetClear(var Clear: ThtClearStyle): Boolean;
|
||
|
begin
|
||
|
Result := False;
|
||
|
if FProperties <> nil then
|
||
|
Result := FProperties.GetClear(Clear);
|
||
|
end;
|
||
|
|
||
|
//-- BG ---------------------------------------------------------- 24.02.2016 --
|
||
|
function TfrxHtSection.TryGetClear(var Clear: ThtClearStyle): Boolean;
|
||
|
var
|
||
|
T: TfrxHtAttribute;
|
||
|
begin
|
||
|
T := nil;
|
||
|
Result := inherited TryGetClear(Clear);
|
||
|
if not Result then
|
||
|
if FAttributes <> nil then
|
||
|
if FAttributes.Find(ClearSy, T) then
|
||
|
Result := TryStrToClearStyle(LowerCase(T.Name), Clear);
|
||
|
end;
|
||
|
|
||
|
//-- BG ---------------------------------------------------------- 24.03.2011 --
|
||
|
function TfrxHtmlNode.FindAttribute(const Name: ThtString; out Attribute: TfrxHtAttribute): Boolean;
|
||
|
begin
|
||
|
Attribute := nil;
|
||
|
Result := (FAttributes <> nil) and FAttributes.Find(Name, Attribute);
|
||
|
end;
|
||
|
|
||
|
//-- BG ---------------------------------------------------------- 28.10.2015 --
|
||
|
function TfrxHtmlNode.GetAttribute(const Name: ThtString): ThtString;
|
||
|
var
|
||
|
Attribute: TfrxHtAttribute;
|
||
|
begin
|
||
|
if FindAttribute(Name, Attribute) then
|
||
|
Result := Attribute.Name
|
||
|
else
|
||
|
SetLength(Result, 0);
|
||
|
end;
|
||
|
|
||
|
//-- BG ---------------------------------------------------------- 24.02.2016 --
|
||
|
function TfrxHtmlNode.GetClearSpace(IMgr: TfrxHtIndentManager; Y: Integer): Integer;
|
||
|
var
|
||
|
CL, CR: Integer;
|
||
|
begin
|
||
|
Result := 0;
|
||
|
if FClearing <> clrNone then
|
||
|
begin {may need to move down past floating image}
|
||
|
IMgr.GetClearY(CL, CR);
|
||
|
case FClearing of
|
||
|
clrLeft: Result := Max(0, CL - Y - 1);
|
||
|
clrRight: Result := Max(0, CR - Y - 1);
|
||
|
clrBoth: Result := Max(CL - Y - 1, Max(0, CR - Y - 1));
|
||
|
end;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
//-- BG ---------------------------------------------------------- 14.02.2016 --
|
||
|
function TfrxHtmlNode.GetContainingBlock: TfrxHtBlock;
|
||
|
begin
|
||
|
// if Result is nil, containing block is the viewport resp. page area
|
||
|
case FPositioning of
|
||
|
posFixed:
|
||
|
Result := nil;
|
||
|
|
||
|
posAbsolute:
|
||
|
begin
|
||
|
Result := OwnerBlock;
|
||
|
while (Result <> nil) and not (Result.Positioning in [posAbsolute, posRelative, posFixed]) do
|
||
|
Result := Result.OwnerBlock;
|
||
|
end;
|
||
|
|
||
|
else
|
||
|
Result := OwnerBlock;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
//-- BG ---------------------------------------------------------- 14.02.2016 --
|
||
|
function TfrxHtmlNode.GetContainingBox: TRect;
|
||
|
var
|
||
|
ContainingBlock: TfrxHtBlock;
|
||
|
begin
|
||
|
ContainingBlock := GetContainingBlock;
|
||
|
if ContainingBlock <> nil then
|
||
|
begin
|
||
|
Result.Left := ContainingBlock.LeftP;
|
||
|
Result.Top := ContainingBlock.TopP;
|
||
|
Result.Right := Result.Left + ContainingBlock.ContentWidth;
|
||
|
Result.Bottom := Result.Top + ContainingBlock.MyCell.tcContentBot - ContainingBlock.MyCell.tcDrawTop;
|
||
|
end
|
||
|
else
|
||
|
Result := FDocument.ViewPort;
|
||
|
end;
|
||
|
|
||
|
//-- BG ---------------------------------------------------------- 14.02.2016 --
|
||
|
function TfrxHtmlNode.GetProperty(PropIndex: ThtPropIndices): Variant;
|
||
|
begin
|
||
|
if FProperties <> nil then
|
||
|
Result := FProperties.Props[PropIndex]
|
||
|
else
|
||
|
Result := Unassigned;
|
||
|
end;
|
||
|
|
||
|
//-- BG ---------------------------------------------------------- 04.08.2013 --
|
||
|
function TfrxHtmlNode.GetSymbol: TElemSymb;
|
||
|
begin
|
||
|
Result := FProperties.PropSym;
|
||
|
end;
|
||
|
|
||
|
//-- BG ---------------------------------------------------------- 21.09.2016 --
|
||
|
procedure TfrxHtmlNode.GetVMarginArray(var MArray: ThtVMarginArray);
|
||
|
begin
|
||
|
FProperties.GetVMarginArray(MArray);
|
||
|
end;
|
||
|
|
||
|
//function TfrxHtmlNode.GetPseudos: TPseudos;
|
||
|
//begin
|
||
|
// Result := []; //TODO -oBG, 24.03.2011
|
||
|
//end;
|
||
|
|
||
|
//-- BG ---------------------------------------------------------- 24.03.2011 --
|
||
|
function TfrxHtmlNode.IndexOf(Child: TfrxHtmlNode): Integer;
|
||
|
begin
|
||
|
Result := -1; //TODO -oBG, 24.03.2011
|
||
|
end;
|
||
|
|
||
|
//-- BG ---------------------------------------------------------- 04.08.2013 --
|
||
|
function TfrxHtmlNode.IsCopy: Boolean;
|
||
|
begin
|
||
|
Result := Document.IsCopy;
|
||
|
end;
|
||
|
|
||
|
//-- BG ---------------------------------------------------------- 13.02.2016 --
|
||
|
function TfrxHtmlNode.IsInFlow: Boolean;
|
||
|
begin
|
||
|
Result := not (FFloating in [aLeft, aRight]) and not (FPositioning in [posAbsolute, posFixed]);
|
||
|
end;
|
||
|
|
||
|
|
||
|
{ TfrxHtFontObj }
|
||
|
|
||
|
type
|
||
|
TSectionClass = class of TfrxHtSectionBase;
|
||
|
EProcessError = class(Exception);
|
||
|
|
||
|
type
|
||
|
ThtInlineRec = class
|
||
|
private
|
||
|
StartB, EndB, IDB, StartBDoc, EndBDoc: Integer;
|
||
|
MargArray: ThtMarginArray;
|
||
|
end;
|
||
|
|
||
|
TInlineList = class(TObjectList) {a list of ThtInlineRec's}
|
||
|
private
|
||
|
NeedsConverting: Boolean;
|
||
|
Owner: TfrxHtDocument;
|
||
|
procedure AdjustValues;
|
||
|
function Get(Index: Integer): ThtInlineRec; {$ifdef UseInline} inline; {$endif}
|
||
|
function GetStartB(I: Integer): Integer;
|
||
|
function GetEndB(I: Integer): Integer;
|
||
|
public
|
||
|
constructor Create(AnOwner: TfrxHtDocument);
|
||
|
procedure Clear; override;
|
||
|
property Items[Index: Integer]: ThtInlineRec read Get; default;
|
||
|
property StartB[I: Integer]: Integer read GetStartB;
|
||
|
property EndB[I: Integer]: Integer read GetEndB;
|
||
|
end;
|
||
|
|
||
|
constructor TfrxHtFontObj.Create(ASection: TfrxHtSection; F: TfrxHtFont; Position: Integer);
|
||
|
begin
|
||
|
inherited Create;
|
||
|
TheFont := TfrxHtFont.Create;
|
||
|
TheFont.Assign(F);
|
||
|
Pos := Position;
|
||
|
UrlTarget := TfrxHtUrlTarget.Create;
|
||
|
FontChanged;
|
||
|
end;
|
||
|
|
||
|
procedure TfrxHtFontObj.CreateFIArray;
|
||
|
begin
|
||
|
if not Assigned(FIArray) then
|
||
|
FIArray := TFontInfoObj.Create;
|
||
|
end;
|
||
|
|
||
|
procedure TfrxHtFontObj.ReplaceFont(F: TfrxHtFont);
|
||
|
begin
|
||
|
TheFont.Assign(F);
|
||
|
FontChanged;
|
||
|
end;
|
||
|
|
||
|
procedure TfrxHtFontObj.ConvertFont(const FI: TfrxHtFontInfo);
|
||
|
begin
|
||
|
TheFont.Assign(FI);
|
||
|
FontChanged;
|
||
|
end;
|
||
|
|
||
|
constructor TfrxHtFontObj.CreateCopy(ASection: TfrxHtSection; T: TfrxHtFontObj);
|
||
|
begin
|
||
|
inherited Create;
|
||
|
Pos := T.Pos;
|
||
|
SScript := T.SScript;
|
||
|
TheFont := TfrxHtFont.Create;
|
||
|
TheFont.Assign(T.TheFont);
|
||
|
if Assigned(T.FIArray) then
|
||
|
ConvertFont(T.FIArray.Info);
|
||
|
UrlTarget := TfrxHtUrlTarget.Create;
|
||
|
UrlTarget.Assign(T.UrlTarget);
|
||
|
FontChanged;
|
||
|
end;
|
||
|
|
||
|
destructor TfrxHtFontObj.Destroy;
|
||
|
begin
|
||
|
FIArray.Free;
|
||
|
TheFont.Free;
|
||
|
UrlTarget.Free;
|
||
|
inherited Destroy;
|
||
|
end;
|
||
|
|
||
|
function TfrxHtFontObj.GetURL: ThtString;
|
||
|
begin
|
||
|
try
|
||
|
Result := UrlTarget.Url;
|
||
|
except
|
||
|
Result := '';
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
procedure TfrxHtFontObj.FontChanged;
|
||
|
begin
|
||
|
tmHeight := TheFont.tmHeight;
|
||
|
tmMaxCharWidth := TheFont.tmMaxCharWidth;
|
||
|
FontHeight := TheFont.tmHeight + TheFont.tmExternalLeading;
|
||
|
Descent := TheFont.tmDescent;
|
||
|
if fsItalic in TheFont.Style then {estimated overhang}
|
||
|
Overhang := TheFont.tmheight div 10
|
||
|
else
|
||
|
Overhang := 0;
|
||
|
TheFont.Charset := TheFont.tmCharset;
|
||
|
end;
|
||
|
|
||
|
function TfrxHtFontObj.GetOverhang: Integer;
|
||
|
begin
|
||
|
Result := Overhang;
|
||
|
end;
|
||
|
|
||
|
function TfrxHtFontObj.GetHeight(var Desc: Integer): Integer;
|
||
|
begin
|
||
|
Desc := Descent;
|
||
|
Result := FontHeight;
|
||
|
end;
|
||
|
|
||
|
constructor TfrxHtFontList.CreateCopy(ASection: TfrxHtSection; T: TfrxHtFontList);
|
||
|
var
|
||
|
I: Integer;
|
||
|
begin
|
||
|
inherited create;
|
||
|
for I := 0 to T.Count - 1 do
|
||
|
Add(TfrxHtFontObj.CreateCopy(ASection, T.Items[I]));
|
||
|
end;
|
||
|
|
||
|
//-- BG ---------------------------------------------------------- 10.02.2013 --
|
||
|
function TfrxHtFontList.GetFont(Index: Integer): TfrxHtFontObj;
|
||
|
begin
|
||
|
Result := inherited Get(Index);
|
||
|
end;
|
||
|
|
||
|
function TfrxHtFontList.GetFontAt(Posn: Integer; out OHang: Integer): TfrxHtFont;
|
||
|
{given a character index, find the font that's effective there}
|
||
|
var
|
||
|
I, PosX: Integer;
|
||
|
F: TfrxHtFontObj;
|
||
|
begin
|
||
|
I := 0;
|
||
|
PosX := 0;
|
||
|
while (I < Count) do
|
||
|
begin
|
||
|
PosX := Items[I].Pos;
|
||
|
Inc(I);
|
||
|
if PosX >= Posn then
|
||
|
Break;
|
||
|
end;
|
||
|
Dec(I);
|
||
|
if PosX > Posn then
|
||
|
Dec(I);
|
||
|
F := Items[I];
|
||
|
OHang := F.Overhang;
|
||
|
Result := F.TheFont;
|
||
|
end;
|
||
|
|
||
|
//-- BG ---------------------------------------------------------- 25.08.2013 --
|
||
|
function TfrxHtFontList.GetFontObjAt(Posn, Leng: Integer; out Obj: TfrxHtFontObj): Integer;
|
||
|
{Given a position, returns the FontObj which applies there and the number of chars before the font changes}
|
||
|
var
|
||
|
I: Integer;
|
||
|
begin
|
||
|
I := Count;
|
||
|
while I > 0 do
|
||
|
begin
|
||
|
Dec(I);
|
||
|
Obj := Items[I];
|
||
|
if Obj.Pos <= Posn then
|
||
|
begin
|
||
|
Result := Leng - Posn;
|
||
|
Exit;
|
||
|
end;
|
||
|
Leng := Obj.Pos;
|
||
|
end;
|
||
|
Obj := nil;
|
||
|
Result := Leng - Posn;
|
||
|
end;
|
||
|
|
||
|
{----------------TfrxHtFontList.GetFontObjAt}
|
||
|
|
||
|
function TfrxHtFontList.GetFontObjAt(Posn: Integer): TfrxHtFontObj;
|
||
|
{Given a position, returns the FontObj which applies there}
|
||
|
var
|
||
|
I: Integer;
|
||
|
begin
|
||
|
I := Count;
|
||
|
while I > 0 do
|
||
|
begin
|
||
|
Dec(I);
|
||
|
Result := Items[I];
|
||
|
if Result.Pos <= Posn then
|
||
|
Exit;
|
||
|
end;
|
||
|
Result := nil;
|
||
|
end;
|
||
|
|
||
|
{----------------TfrxHtFontList.Decrement}
|
||
|
|
||
|
procedure TfrxHtFontList.Decrement(N: Integer; Document: TfrxHtDocument);
|
||
|
{called when a character is removed to change the Position figure}
|
||
|
var
|
||
|
I, J: Integer;
|
||
|
FO, FO1: TfrxHtFontObj;
|
||
|
begin
|
||
|
I := 0;
|
||
|
while I < Count do
|
||
|
begin
|
||
|
FO := Items[I];
|
||
|
if FO.Pos > N then
|
||
|
Dec(FO.Pos);
|
||
|
if (I > 0) and (Items[I - 1].Pos = FO.Pos) then
|
||
|
begin
|
||
|
FO1 := Items[I - 1];
|
||
|
J := Document.LinkList.IndexOf(FO1);
|
||
|
if J >= 0 then
|
||
|
Document.LinkList.Delete(J);
|
||
|
Delete(I - 1);
|
||
|
end
|
||
|
else
|
||
|
Inc(I);
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
{ TfrxHtLinkList }
|
||
|
|
||
|
//-- BG ---------------------------------------------------------- 10.02.2013 --
|
||
|
constructor TfrxHtLinkList.Create;
|
||
|
begin
|
||
|
inherited Create(False);
|
||
|
end;
|
||
|
|
||
|
{ TfrxFrHtImageObj.Create }
|
||
|
|
||
|
constructor TfrxFrHtImageObj.Create(Parent: TfrxHtCellBasic; Position: Integer; L: TfrxHtAttributeList; Prop: TfrxHTProperties);
|
||
|
var
|
||
|
I: Integer;
|
||
|
S: ThtString;
|
||
|
T: TfrxHtAttribute;
|
||
|
begin
|
||
|
inherited Create(Parent,Position,L,Prop);
|
||
|
for I := 0 to L.Count - 1 do
|
||
|
with L[I] do
|
||
|
case Which of
|
||
|
SrcSy:
|
||
|
FSource := htTrim(Name);
|
||
|
|
||
|
AltSy:
|
||
|
begin
|
||
|
SetAlt(CodePage, Name);
|
||
|
Title := Alt;
|
||
|
end;
|
||
|
|
||
|
BorderSy:
|
||
|
begin
|
||
|
BorderWidth := Min(Max(0, Value), 10);
|
||
|
// if not Prop.HasBorderWidth then
|
||
|
// Prop.BorderWidth := Min(Max(0, Value), 10);
|
||
|
// if not Prop.HasBorderStyle then
|
||
|
// Prop.BorderStyle := bssSolid;
|
||
|
end;
|
||
|
|
||
|
IsMapSy:
|
||
|
IsMap := True;
|
||
|
|
||
|
UseMapSy:
|
||
|
begin
|
||
|
UseMap := True;
|
||
|
S := htUpperCase(htTrim(Name));
|
||
|
if (Length(S) > 1) and (S[1] = '#') then
|
||
|
System.Delete(S, 1, 1);
|
||
|
MapName := S;
|
||
|
end;
|
||
|
|
||
|
ActiveSy:
|
||
|
begin
|
||
|
end;
|
||
|
|
||
|
NameSy:
|
||
|
Document.IDNameList.AddObject(Name, Self);
|
||
|
end;
|
||
|
|
||
|
NoBorder := (BorderWidth = 0) and (not Prop.HasBorderStyle or not Prop.HasBorderWidth);
|
||
|
T := nil;
|
||
|
if L.Find(TitleSy, T) then
|
||
|
Title := T.Name; {has higher priority than Alt loaded above}
|
||
|
end;
|
||
|
|
||
|
constructor TfrxFrHtImageObj.SimpleCreate(Parent: TfrxHtCellBasic; const AnURL: ThtString);
|
||
|
begin
|
||
|
inherited SimpleCreate(Parent);
|
||
|
FSource := AnURL;
|
||
|
end;
|
||
|
|
||
|
constructor TfrxFrHtImageObj.CreateCopy(Parent: TfrxHtCellBasic; Source: TfrxHtmlNode);
|
||
|
var
|
||
|
T: TfrxFrHtImageObj absolute Source;
|
||
|
begin
|
||
|
inherited CreateCopy(Parent,Source);
|
||
|
AltHeight := T.AltHeight;
|
||
|
AltWidth := T.AltWidth;
|
||
|
FImage := T.Image;
|
||
|
FSource := T.FSource;
|
||
|
IsMap := T.IsMap;
|
||
|
MapName := T.MapName;
|
||
|
Missing := T.Missing;
|
||
|
ObjHeight := T.ObjHeight;
|
||
|
ObjWidth := T.ObjWidth;
|
||
|
OrigImage := T.OrigImage;
|
||
|
Swapped := T.Swapped;
|
||
|
Transparent := T.Transparent;
|
||
|
UseMap := T.UseMap;
|
||
|
end;
|
||
|
|
||
|
function TfrxFrHtImageObj.GetGraphic: TGraphic;
|
||
|
begin
|
||
|
if (Image = nil) or (Image = ErrorImage) then
|
||
|
Result := nil
|
||
|
else
|
||
|
Result := Image.Graphic;
|
||
|
end;
|
||
|
|
||
|
{----------------TfrxFrHtImageObj.DrawLogic}
|
||
|
|
||
|
procedure TfrxFrHtImageObj.DrawLogicInline(Canvas: TCanvas; FO: TfrxHtFontObj; AvailableWidth, AvailableHeight: Integer);
|
||
|
{calculate the height and width}
|
||
|
var
|
||
|
TmpImage: TfrxHtImage;
|
||
|
ViewImages, FromCache: Boolean;
|
||
|
Rslt: ThtString;
|
||
|
ARect: TRect;
|
||
|
SubstImage: Boolean;
|
||
|
HasBlueBox: Boolean;
|
||
|
UName: ThtString;
|
||
|
begin
|
||
|
ViewImages := Document.ShowImages;
|
||
|
case FDisplay of
|
||
|
pdNone:
|
||
|
begin
|
||
|
ObjHeight := 0;
|
||
|
ObjWidth := 0;
|
||
|
|
||
|
ClientHeight := ObjHeight;
|
||
|
ClientWidth := ObjWidth;
|
||
|
Exit;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
if ViewImages then
|
||
|
begin
|
||
|
if FImage = nil then
|
||
|
begin
|
||
|
TmpImage := nil;
|
||
|
UName := htTrim(FSource);
|
||
|
if UName <> '' then
|
||
|
begin
|
||
|
if not Assigned(Document.GetImage) then
|
||
|
FSource := htTrim(Document.TheOwner.HtmlExpandFilename(FSource))
|
||
|
else if Assigned(Document.OnExpandName) then
|
||
|
begin
|
||
|
Document.OnExpandName(Document.TheOwner, FSource, Rslt);
|
||
|
FSource := htTrim(Rslt);
|
||
|
end;
|
||
|
if Document.MissingImages.IndexOf(FSource) = -1 then
|
||
|
TmpImage := Document.GetTheImage(FSource, Transparent, FromCache, Missing)
|
||
|
else
|
||
|
Missing := True; {already in list, don't request it again}
|
||
|
end;
|
||
|
|
||
|
if TmpImage = nil then
|
||
|
begin
|
||
|
if Missing then
|
||
|
begin
|
||
|
FImage := DefImage;
|
||
|
Document.MissingImages.AddObject(FSource, Self); {add it even if it's there already}
|
||
|
end
|
||
|
else
|
||
|
begin
|
||
|
FImage := ErrorImage;
|
||
|
end;
|
||
|
end
|
||
|
else
|
||
|
FImage := TmpImage;
|
||
|
OrigImage := TmpImage;
|
||
|
end;
|
||
|
end
|
||
|
else
|
||
|
FImage := DefImage;
|
||
|
|
||
|
SubstImage := (Image = ErrorImage) or (Image = DefImage);
|
||
|
|
||
|
HasBlueBox := not NoBorder and Assigned(FO) and (FO.URLTarget.Url <> '');
|
||
|
if HasBlueBox then
|
||
|
BorderWidth := Max(1, BorderWidth);
|
||
|
|
||
|
if not ClientSizeKnown or PercentWidth or PercentHeight then
|
||
|
begin
|
||
|
CalcSize(AvailableWidth, AvailableHeight, Image.Width, Image.Height, not SubstImage);
|
||
|
ObjWidth := ClientWidth; // - MargArray[BorderLeftWidth] - MargArray[BorderRightWidth];
|
||
|
ObjHeight := ClientHeight;// - MargArray[BorderTopWidth] - MargArray[BorderBottomWidth];
|
||
|
end;
|
||
|
|
||
|
if not ViewImages or SubstImage then
|
||
|
begin
|
||
|
if ClientSizeKnown or (not SubstImage and ((SpecWidth >= 0) or (SpecHeight >= 0))) then
|
||
|
begin {size to whatever is specified}
|
||
|
AltWidth := ObjWidth;
|
||
|
AltHeight := ObjHeight;
|
||
|
end
|
||
|
else
|
||
|
begin
|
||
|
if FAlt <> '' then {Alt text and no size specified, take as much space as necessary}
|
||
|
begin
|
||
|
Canvas.Font.Name := FontSans; {use same font as in Draw}
|
||
|
Canvas.Font.Size := 8;
|
||
|
ARect := Rect(0, 0, 0, 0);
|
||
|
DrawTextW(Canvas.Handle, PWideChar(FAlt + CRLF), -1, ARect, DT_CALCRECT);
|
||
|
with ARect do
|
||
|
begin
|
||
|
AltWidth := Right + 16 + 8 + 2;
|
||
|
AltHeight := Max(16 + 8, Bottom);
|
||
|
end;
|
||
|
end
|
||
|
else
|
||
|
begin {no Alt text and no size specified}
|
||
|
AltWidth := Max(ObjWidth, 16 + 8);
|
||
|
AltHeight := Max(ObjHeight, 16 + 8);
|
||
|
end;
|
||
|
ClientHeight := AltHeight;
|
||
|
ClientWidth := AltWidth;
|
||
|
end;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
{----------------TfrxFrHtImageObj.DoDraw}
|
||
|
procedure TfrxFrHtImageObj.DoDraw(Canvas: TCanvas; XX, Y: Integer; ddImage: TfrxHtImage);
|
||
|
{Y relative to top of display here}
|
||
|
var
|
||
|
W, H: Integer;
|
||
|
begin
|
||
|
if (ddImage = ErrorImage) or (ddImage = DefImage) then
|
||
|
begin
|
||
|
W := ddImage.Width;
|
||
|
H := ddImage.Height;
|
||
|
end
|
||
|
else if ddImage = nil then
|
||
|
exit
|
||
|
else
|
||
|
begin
|
||
|
W := ObjWidth;
|
||
|
H := ObjHeight;
|
||
|
end;
|
||
|
try
|
||
|
// Yunqa.de removed: ddImage.Transp := Transparent;
|
||
|
if (W > 0) and (H > 0) then
|
||
|
if IsCopy then
|
||
|
ddImage.Print(Canvas, XX, Y, W, H, clWhite)
|
||
|
else
|
||
|
ddImage.Draw(Canvas, XX, Y, W, H);
|
||
|
except
|
||
|
//on E: Exception do
|
||
|
//begin
|
||
|
// LastExceptionMessage := E.Message;
|
||
|
// LastDdImage := ddImage;
|
||
|
//end;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
{----------------TfrxFrHtImageObj.Draw}
|
||
|
|
||
|
//-- BG ---------------------------------------------------------- 12.06.2010 --
|
||
|
procedure GetRaisedColors(SectionList: TfrxHtDocument; Canvas: TCanvas; out Light, Dark: TColor); {$ifdef UseInline} inline; {$endif}
|
||
|
{$ifdef UseInline} inline; {$endif}
|
||
|
var
|
||
|
White: Boolean;
|
||
|
begin
|
||
|
White := (ThemedColor(SectionList.Background) = clWhite);
|
||
|
Dark := ThemedColor(clBtnShadow);
|
||
|
if White then
|
||
|
Light := clSilver
|
||
|
else
|
||
|
Light := ThemedColor(clBtnHighLight);
|
||
|
end;
|
||
|
|
||
|
//BG, 15.10.2010: issue 28: Borland C++ Builder does not accept an array as a result of a function.
|
||
|
// Thus move htStyles and htColors from HtmlUn2.pas to HtmlSubs.pas the only unit where they are used
|
||
|
|
||
|
function htStyles(P0, P1, P2, P3: ThtBorderStyle): ThtBorderStyleArray;
|
||
|
{$ifdef UseInline} inline; {$endif}
|
||
|
begin
|
||
|
Result[0] := P0;
|
||
|
Result[1] := P1;
|
||
|
Result[2] := P2;
|
||
|
Result[3] := P3;
|
||
|
end;
|
||
|
|
||
|
function htColors(C0, C1, C2, C3: TColor): ThtColorArray;
|
||
|
{$ifdef UseInline} inline; {$endif}
|
||
|
begin
|
||
|
Result[0] := C0;
|
||
|
Result[1] := C1;
|
||
|
Result[2] := C2;
|
||
|
Result[3] := C3;
|
||
|
end;
|
||
|
|
||
|
//-- BG ---------------------------------------------------------- 12.06.2010 --
|
||
|
function htRaisedColors(Light, Dark: TColor; Raised: Boolean): ThtColorArray; overload;
|
||
|
{$ifdef UseInline} inline; {$endif}
|
||
|
begin
|
||
|
if Raised then
|
||
|
Result := htColors(Light, Light, Dark, Dark)
|
||
|
else
|
||
|
Result := htColors(Dark, Dark, Light, Light);
|
||
|
end;
|
||
|
|
||
|
//-- BG ---------------------------------------------------------- 12.06.2010 --
|
||
|
function htRaisedColors(SectionList: TfrxHtDocument; Canvas: TCanvas; Raised: Boolean): ThtColorArray; overload;
|
||
|
{$ifdef UseInline} inline; {$endif}
|
||
|
var
|
||
|
Light, Dark: TColor;
|
||
|
begin
|
||
|
GetRaisedColors(SectionList, Canvas, Light, Dark);
|
||
|
Result := htRaisedColors(Light, Dark, Raised);
|
||
|
end;
|
||
|
|
||
|
//-- BG ---------------------------------------------------------- 12.06.2010 --
|
||
|
procedure RaisedRectColor(Canvas: TCanvas;
|
||
|
const ORect, IRect: TRect;
|
||
|
const Colors: ThtColorArray;
|
||
|
Styles: ThtBorderStyleArray); overload;
|
||
|
{$ifdef UseInline} inline; {$endif}
|
||
|
{Draws colored raised or lowered rectangles for table borders}
|
||
|
begin
|
||
|
DrawBorder(Canvas, ORect, IRect, Colors, Styles, clNone, False);
|
||
|
end;
|
||
|
|
||
|
procedure RaisedRect(SectionList: TfrxHtDocument; Canvas: TCanvas;
|
||
|
X1, Y1, X2, Y2: Integer;
|
||
|
Raised: Boolean;
|
||
|
W: Integer);
|
||
|
{$ifdef UseInline} inline; {$endif}
|
||
|
{Draws raised or lowered rectangles for table borders}
|
||
|
begin
|
||
|
RaisedRectColor(Canvas,
|
||
|
Rect(X1, Y1, X2, Y2),
|
||
|
Rect(X1 + W, Y1 + W, X2 - W, Y2 - W),
|
||
|
htRaisedColors(SectionList, Canvas, Raised),
|
||
|
htStyles(bssSolid, bssSolid, bssSolid, bssSolid));
|
||
|
end;
|
||
|
|
||
|
procedure TfrxFrHtImageObj.DrawInline(Canvas: TCanvas; X, Y, YBaseline: Integer; FO: TfrxHtFontObj);
|
||
|
var
|
||
|
TmpImage: TfrxHtImage;
|
||
|
MiddleAlignTop: Integer;
|
||
|
ViewImages: Boolean;
|
||
|
SubstImage: Boolean;
|
||
|
Ofst: Integer;
|
||
|
SaveColor: TColor;
|
||
|
ARect: TRect;
|
||
|
YY: Integer;
|
||
|
begin
|
||
|
ViewImages := Document.ShowImages;
|
||
|
Dec(Y, Document.YOff);
|
||
|
Dec(YBaseLine, Document.YOff);
|
||
|
|
||
|
if ViewImages then
|
||
|
TmpImage := Image
|
||
|
else
|
||
|
TmpImage := DefImage;
|
||
|
SubstImage := not ViewImages or (TmpImage = ErrorImage) or (TmpImage = DefImage); {substitute image}
|
||
|
|
||
|
with Canvas do
|
||
|
begin
|
||
|
Brush.Style := bsClear;
|
||
|
Font.Size := 8;
|
||
|
Font.Name := FontSans; {make this a property?}
|
||
|
Font.Style := Font.Style - [fsBold];
|
||
|
end;
|
||
|
|
||
|
if SubstImage then
|
||
|
Ofst := 4
|
||
|
else
|
||
|
Ofst := 0;
|
||
|
|
||
|
if VertAlign = AMiddle then
|
||
|
MiddleAlignTop := YBaseLine + FO.Descent - (FO.tmHeight div 2) - ((ClientHeight - VSpaceT + VSpaceB) div 2)
|
||
|
else
|
||
|
MiddleAlignTop := 0; {not used}
|
||
|
|
||
|
DrawXX := X;
|
||
|
DrawYY := Y;
|
||
|
if Floating = ANone then
|
||
|
begin
|
||
|
case Positioning of
|
||
|
posAbsolute:
|
||
|
begin
|
||
|
ARect := ContainingBox;
|
||
|
if not IsAuto(GetPosition(reLeft)) then DrawXX := GetPosition(reLeft) + ARect.Left;
|
||
|
if not IsAuto(GetPosition(reTop)) then DrawYY := GetPosition(reTop) + ARect.Top;
|
||
|
end;
|
||
|
|
||
|
posFixed:
|
||
|
begin
|
||
|
ARect := FDocument.ViewPort;
|
||
|
if not IsAuto(GetPosition(reLeft)) then DrawXX := GetPosition(reLeft) + ARect.Left;
|
||
|
if not IsAuto(GetPosition(reTop)) then DrawYY := GetPosition(reTop) + ARect.Top;
|
||
|
end;
|
||
|
|
||
|
else
|
||
|
case VertAlign of
|
||
|
ATop, ANone:
|
||
|
DrawYY := Y + VSpaceT;
|
||
|
AMiddle:
|
||
|
DrawYY := MiddleAlignTop;
|
||
|
ABottom, ABaseline:
|
||
|
DrawYY := YBaseLine - ClientHeight - VSpaceB;
|
||
|
end;
|
||
|
|
||
|
if Positioning = posRelative then
|
||
|
begin
|
||
|
if not IsAuto(GetPosition(reLeft)) then Inc(DrawXX, GetPosition(reLeft));
|
||
|
if not IsAuto(GetPosition(reTop)) then Inc(DrawYY, GetPosition(reTop));
|
||
|
end;
|
||
|
|
||
|
end;
|
||
|
// if MargArray[BorderLeftWidth] > 0 then
|
||
|
// Inc(DrawXX, MargArray[BorderLeftWidth]);
|
||
|
// if MargArray[BorderTopWidth] > 0 then
|
||
|
// Inc(DrawYY, MargArray[BorderTopWidth]);
|
||
|
end;
|
||
|
|
||
|
if not SubstImage or ((AltHeight >= 16 + 8) and (AltWidth >= 16 + 8)) then
|
||
|
Self.DoDraw(Canvas, DrawXX + Ofst, DrawYY + Ofst, TmpImage);
|
||
|
Inc(DrawYY, Document.YOff);
|
||
|
|
||
|
SetTextAlign(Canvas.Handle, TA_Top);
|
||
|
if SubstImage and (BorderWidth = 0) then
|
||
|
begin
|
||
|
Canvas.Font.Color := ThemedColor(FO.TheFont.Color);
|
||
|
{calc the offset from the image's base to the alt= text baseline}
|
||
|
case VertAlign of
|
||
|
ATop, ANone:
|
||
|
begin
|
||
|
if FAlt <> '' then
|
||
|
WrapTextW( Canvas, X + 24, Y + Ofst , X + AltWidth - 2, Y + AltHeight - 1, FAlt);
|
||
|
RaisedRect(Document, Canvas, X , Y , X + AltWidth , Y + AltHeight , False, 1);
|
||
|
end;
|
||
|
AMiddle:
|
||
|
begin {MiddleAlignTop is always initialized}
|
||
|
if FAlt <> '' then
|
||
|
WrapTextW( Canvas, X + 24, MiddleAlignTop + Ofst , X + AltWidth - 2, MiddleAlignTop + AltHeight - 1, FAlt);
|
||
|
RaisedRect(Document, Canvas, X , MiddleAlignTop , X + AltWidth , MiddleAlignTop + AltHeight , False, 1);
|
||
|
end;
|
||
|
ABottom, ABaseline:
|
||
|
begin
|
||
|
if FAlt <> '' then
|
||
|
WrapTextW( Canvas, X + 24, YBaseLine - AltHeight + Ofst - VSpaceB, X + AltWidth - 2, YBaseLine - VSpaceB - 1, FAlt);
|
||
|
RaisedRect(Document, Canvas, X , YBaseLine - AltHeight - VSpaceB, X + AltWidth , YBaseLine - VSpaceB , False, 1);
|
||
|
end;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
if (MargArray[BorderTopWidth] > 0) or (MargArray[BorderRightWidth] > 0) or (MargArray[BorderBottomWidth] > 0) or (MargArray[BorderLeftWidth] > 0) then
|
||
|
with Canvas do
|
||
|
begin
|
||
|
// SaveColor := Pen.Color;
|
||
|
// SaveWidth := Pen.Width;
|
||
|
// SaveStyle := Pen.Style;
|
||
|
Font.Color := ThemedColor(FO.TheFont.Color);
|
||
|
// Pen.Color := Font.Color;
|
||
|
// Pen.Width := BorderSize;
|
||
|
// Pen.Style := psInsideFrame;
|
||
|
try
|
||
|
if (FAlt <> '') and SubstImage then
|
||
|
begin
|
||
|
{output Alt message}
|
||
|
YY := DrawYY - Document.YOff;
|
||
|
case VertAlign of
|
||
|
ATop, ANone:
|
||
|
WrapTextW(Canvas, DrawXX + 24, YY + Ofst, DrawXX + AltWidth - 2, YY + AltHeight - 1, FAlt);
|
||
|
AMiddle:
|
||
|
WrapTextW(Canvas, DrawXX + 24, YY + Ofst, DrawXX + AltWidth - 2, YY + AltHeight - 1, FAlt);
|
||
|
ABottom, ABaseline:
|
||
|
WrapTextW(Canvas, DrawXX + 24, YY + Ofst, DrawXX + AltWidth - 2, YY + AltHeight - 1, FAlt);
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
finally
|
||
|
// Pen.Color := SaveColor;
|
||
|
// Pen.Width := SaveWidth;
|
||
|
// Pen.Style := SaveStyle;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
if IsCopy and Assigned(Document.LinkDrawnEvent) and (FO.UrlTarget.Url <> '')
|
||
|
then
|
||
|
with Canvas do
|
||
|
begin
|
||
|
SaveColor := SetTextColor(Handle, clBlack);
|
||
|
Brush.Color := clWhite;
|
||
|
case VertAlign of
|
||
|
ATop, ANone:
|
||
|
ARect := Rect(X, Y + VSpaceT, X + ClientWidth, Y + VSpaceT + ClientHeight);
|
||
|
AMiddle:
|
||
|
ARect := Rect(X, MiddleAlignTop, X + ClientWidth, MiddleAlignTop + ClientHeight);
|
||
|
ABottom, ABaseline:
|
||
|
ARect := Rect(X, YBaseLine - ClientHeight - VSpaceB, X + ClientWidth, YBaseLine - VSpaceB);
|
||
|
end;
|
||
|
if IsCopy then
|
||
|
Document.LinkDrawnEvent(Document.TheOwner, Document.LinkPage,
|
||
|
FO.UrlTarget.Url, FO.UrlTarget.Target, ARect);
|
||
|
SetTextColor(handle, SaveColor);
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
{----------------TfrxHtCellBasic.Create}
|
||
|
|
||
|
constructor TfrxHtCellBasic.Create(Parent: TfrxHtBlock);
|
||
|
begin
|
||
|
inherited Create;
|
||
|
FOwnerBlock := Parent;
|
||
|
if FOwnerBlock <> nil then
|
||
|
FDocument := FOwnerBlock.Document;
|
||
|
end;
|
||
|
|
||
|
{----------------TfrxHtCellBasic.CreateCopy}
|
||
|
|
||
|
constructor TfrxHtCellBasic.CreateCopy(Parent: TfrxHtBlock; T: TfrxHtCellBasic);
|
||
|
var
|
||
|
I: Integer;
|
||
|
Tmp, Tmp1: TfrxHtSectionBase;
|
||
|
begin
|
||
|
inherited Create;
|
||
|
FOwnerBlock := Parent;
|
||
|
if FOwnerBlock <> nil then
|
||
|
FDocument := FOwnerBlock.Document;
|
||
|
for I := 0 to T.Count - 1 do
|
||
|
begin
|
||
|
Tmp := T.Items[I];
|
||
|
Tmp1 := TSectionClass(Tmp.ClassType).CreateCopy(Self, Tmp);
|
||
|
Add(Tmp1, 0);
|
||
|
end;
|
||
|
// FRenderList := TRenderSectionBaseList.Create(false);
|
||
|
end;
|
||
|
|
||
|
//-- BG ---------------------------------------------------------- 01.12.2013 --
|
||
|
destructor TfrxHtCellBasic.Destroy;
|
||
|
begin
|
||
|
// FRenderList.Free;
|
||
|
inherited;
|
||
|
end;
|
||
|
|
||
|
{----------------TfrxHtCellBasic.Add}
|
||
|
|
||
|
procedure TfrxHtCellBasic.Add(Item: TfrxHtSectionBase; TagIndex: Integer);
|
||
|
var
|
||
|
Section: TfrxHtSection absolute Item;
|
||
|
begin
|
||
|
if Assigned(Item) then
|
||
|
begin
|
||
|
if Item is TfrxHtSection then
|
||
|
Add(Section, TagIndex)
|
||
|
else
|
||
|
inherited Add(Item);
|
||
|
Item.SetDocument(Document);
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
//-- BG ---------------------------------------------------------- 14.01.2015 --
|
||
|
procedure TfrxHtCellBasic.Add(var Section: TfrxHtSection; TagIndex: Integer);
|
||
|
begin
|
||
|
if Assigned(Section) then
|
||
|
begin
|
||
|
if Length(Section.XP) <> 0 then
|
||
|
begin
|
||
|
Section.ProcessText(TagIndex);
|
||
|
if not (Section.WhiteSpaceStyle in [wsPre, wsPreWrap, wsPreLine]) and (Section.Len = 0)
|
||
|
and not Section.AnchorName and (Section.FClearing = clrNone) then
|
||
|
begin
|
||
|
Section.CheckFree;
|
||
|
FreeAndNil(Section); {discard empty TSections that aren't anchors}
|
||
|
Exit;
|
||
|
end;
|
||
|
end;
|
||
|
inherited Add(Section);
|
||
|
Section.SetDocument(Document);
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
//-- BG ---------------------------------------------------------- 07.09.2013 --
|
||
|
function TfrxHtCellBasic.CalcDisplayExtern: ThtDisplayStyle;
|
||
|
var
|
||
|
I: Integer;
|
||
|
begin
|
||
|
// a list of elements is displayed inline, if all elements' are displayed inline.
|
||
|
for I := Count - 1 downto 0 do
|
||
|
if Items[i].CalcDisplayExtern <> pdInline then
|
||
|
begin
|
||
|
Result := pdBlock;
|
||
|
Exit;
|
||
|
end;
|
||
|
Result := pdInline;
|
||
|
end;
|
||
|
|
||
|
function TfrxHtCellBasic.CheckLastBottomMargin: Boolean;
|
||
|
{Look at the last item in this cell. If its bottom margin was set to Auto,
|
||
|
set it to 0}
|
||
|
var
|
||
|
TB: TfrxHtSectionBase;
|
||
|
Block: TfrxHtBlock absolute TB;
|
||
|
I, J: Integer;
|
||
|
begin
|
||
|
Result := False;
|
||
|
|
||
|
I := 0; {find first block that isn't absolute positioning}
|
||
|
while I < Count do
|
||
|
begin
|
||
|
TB := Items[I];
|
||
|
if TB is TfrxHtSection and (Length(Trim(TfrxHtSection(TB).BuffS)) = 0) then
|
||
|
else if not (TB is TfrxHtBlock) or (TfrxHtBlock(TB).Positioning <> PosAbsolute) then
|
||
|
break;
|
||
|
|
||
|
Inc(I);
|
||
|
end;
|
||
|
if I < Count then
|
||
|
begin
|
||
|
if TB is TfrxHtBlock then
|
||
|
begin
|
||
|
if Block.TopAuto then
|
||
|
begin
|
||
|
Block.MargArray[MarginTop] := 0;
|
||
|
// Result := True;
|
||
|
end;
|
||
|
// if TB is TfrxHtBlockLI then
|
||
|
// Result := TfrxHtBlockLI(TB).MyCell.CheckLastBottomMargin;
|
||
|
end
|
||
|
end;
|
||
|
|
||
|
J := Count - 1; {find the preceding block that isn't absolute positioning}
|
||
|
while J >= I do
|
||
|
begin
|
||
|
TB := Items[J];
|
||
|
if TB is TfrxHtSection and (Length(Trim(TfrxHtSection(TB).BuffS)) = 0) then
|
||
|
else if not (TB is TfrxHtBlock) or (TfrxHtBlock(TB).Positioning <> PosAbsolute) then
|
||
|
break;
|
||
|
|
||
|
Dec(J);
|
||
|
end;
|
||
|
if J >= 0 then
|
||
|
begin
|
||
|
if TB is TfrxHtBlock then
|
||
|
begin
|
||
|
if Block.BottomAuto then
|
||
|
begin
|
||
|
Block.MargArray[MarginBottom] := 0;
|
||
|
Result := True;
|
||
|
end;
|
||
|
if TB is TfrxHtBlockLI then
|
||
|
Result := TfrxHtBlockLI(TB).MyCell.CheckLastBottomMargin;
|
||
|
end;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
//-- BG ---------------------------------------------------------- 04.08.2013 --
|
||
|
function TfrxHtCellBasic.IsCopy: Boolean;
|
||
|
begin
|
||
|
Result := Document.IsCopy;
|
||
|
end;
|
||
|
|
||
|
procedure TfrxHtCellBasic.AddSectionsToList;
|
||
|
var
|
||
|
I: Integer;
|
||
|
begin
|
||
|
for I := 0 to Count - 1 do
|
||
|
Items[I].AddSectionsToList;
|
||
|
end;
|
||
|
|
||
|
{----------------TfrxHtCellBasic.FindString}
|
||
|
|
||
|
function TfrxHtCellBasic.FindString(From: Integer; const ToFind: UnicodeString; MatchCase: Boolean): Integer;
|
||
|
var
|
||
|
I: Integer;
|
||
|
begin
|
||
|
Result := -1;
|
||
|
for I := 0 to Count - 1 do
|
||
|
begin
|
||
|
Result := Items[I].FindString(From, ToFind, MatchCase);
|
||
|
if Result >= 0 then
|
||
|
Break;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
{----------------TfrxHtCellBasic.FindStringR}
|
||
|
|
||
|
function TfrxHtCellBasic.FindStringR(From: Integer; const ToFind: UnicodeString; MatchCase: Boolean): Integer;
|
||
|
var
|
||
|
I: Integer;
|
||
|
begin
|
||
|
Result := -1;
|
||
|
for I := Count - 1 downto 0 do
|
||
|
begin
|
||
|
Result := Items[I].FindStringR(From, ToFind, MatchCase);
|
||
|
if Result >= 0 then
|
||
|
Break;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
{----------------TfrxHtCellBasic.FindSourcePos}
|
||
|
|
||
|
function TfrxHtCellBasic.FindSourcePos(DocPos: Integer): Integer;
|
||
|
var
|
||
|
I: Integer;
|
||
|
begin
|
||
|
Result := -1;
|
||
|
for I := 0 to Count - 1 do
|
||
|
begin
|
||
|
Result := Items[I].FindSourcePos(DocPos);
|
||
|
if Result >= 0 then
|
||
|
Break;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
{$ifdef UseFormTree}
|
||
|
procedure TfrxHtCellBasic.FormTree(const Indent: ThtString; var Tree: ThtString);
|
||
|
var
|
||
|
I: Integer;
|
||
|
Item: TfrxHtSectionBase;
|
||
|
begin
|
||
|
for I := 0 to Count - 1 do
|
||
|
begin
|
||
|
Item := Items[I];
|
||
|
if Item is TfrxHtBlock then
|
||
|
TfrxHtBlock(Item).FormTree(Indent, Tree)
|
||
|
else if Item is TfrxHtSection then
|
||
|
Tree := Tree + Indent + Copy(TfrxHtSection(Item).BuffS, 1, 10) + CrChar + LfChar
|
||
|
else
|
||
|
Tree := Tree + Indent + '----'^M^J;
|
||
|
end;
|
||
|
end;
|
||
|
{$endif UseFormTree}
|
||
|
|
||
|
{----------------TfrxHtCellBasic.GetChAtPos}
|
||
|
|
||
|
function TfrxHtCellBasic.GetChAtPos(Pos: Integer; out Ch: WideChar; out Obj: TfrxHtSectionBase): Boolean;
|
||
|
var
|
||
|
I: Integer;
|
||
|
begin
|
||
|
Result := False;
|
||
|
if (Pos >= StartCurs) and (Pos <= StartCurs + Len) then
|
||
|
for I := 0 to Count - 1 do
|
||
|
begin
|
||
|
Result := TfrxHtSectionBase(Items[I]).GetChAtPos(Pos, Ch, Obj);
|
||
|
if Result then
|
||
|
Break;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
|
||
|
{----------------TfrxHtCellBasic.DoLogic}
|
||
|
|
||
|
function TfrxHtCellBasic.DoLogic(Canvas: TCanvas; Y, Width, AHeight, BlHt: Integer;
|
||
|
var ScrollWidth: Integer; var Curs: Integer; ARemainHeight: Integer = 0): Integer;
|
||
|
{Do the entire layout of the cell or document. Return the total cell or document pixel height}
|
||
|
var
|
||
|
I, Sw, TheCount: Integer;
|
||
|
H: Integer;
|
||
|
// InlineSection: TInlineSection;
|
||
|
// Item: TfrxHtSectionBase;
|
||
|
begin
|
||
|
//TODO -oBG, 15.03.2014: support display:inline
|
||
|
{$ifdef DO_PD_INLINE}
|
||
|
// //TODO -oBG, 24.06.2012: merge sections with display=inline etc.
|
||
|
// //TODO -oBG, 30.11.2013: To be more precise:
|
||
|
// // Reading the HTML file must produce the actual document tree rather than preprocessing inline elements to TSections.
|
||
|
// //
|
||
|
// // The Renderer (DoLogic()/DrawLogic()) must produce a processing list. In the list consecutive elements of all child
|
||
|
// // levels with display=inline are gathered in the (anonymous) TInlineSection element while block-level elements are
|
||
|
// // added to the processing list directly. This ends up in a list of block level elements, just like TfrxHtCellBasic has
|
||
|
// // been before property Display was introduced.
|
||
|
// //
|
||
|
// // Actually TInlineSection is intended to collect content of TSections of consecutive inline elements and must draw
|
||
|
// // borders and background of the inlined elements.
|
||
|
// InlineSection := nil;
|
||
|
// FRenderList.Clear;
|
||
|
// for I := 0 to Count - 1 do
|
||
|
// begin
|
||
|
// Item := Items[I];
|
||
|
// if Item.CalcDisplayExtern = pdInline then
|
||
|
// begin
|
||
|
// if InlineSection = nil then
|
||
|
// begin
|
||
|
// InlineSection := TInlineSection.Create(Self);
|
||
|
// FRenderList.Add(InlineSection);
|
||
|
// end;
|
||
|
// if Item is TfrxHtSection then
|
||
|
// InlineSection.AddElement(TfrxHtSection(Item));
|
||
|
// end
|
||
|
// else
|
||
|
// begin
|
||
|
// InlineSection := nil;
|
||
|
// FRenderList.Add(Items[I]);
|
||
|
// end;
|
||
|
// end;
|
||
|
{$endif}
|
||
|
|
||
|
StartCurs := Curs;
|
||
|
H := 0;
|
||
|
ScrollWidth := 0;
|
||
|
TheCount := Count;
|
||
|
I := 0;
|
||
|
while I < TheCount do
|
||
|
begin
|
||
|
try
|
||
|
Sw := 0;
|
||
|
Inc(H, Items[I].DrawLogic1(Canvas, 0, Y + H, 0, 0, Width, AHeight, BlHt, IMgr, Sw, Curs, ARemainHeight));
|
||
|
ScrollWidth := Max(ScrollWidth, Sw);
|
||
|
Inc(I);
|
||
|
except
|
||
|
on E: EProcessError do
|
||
|
begin
|
||
|
// Yunqa.de - Don't want message dialog for individual errors.
|
||
|
// Yunqa.de MessageDlg(e.Message, mtError, [mbOK], 0);
|
||
|
Delete(I);
|
||
|
Dec(TheCount);
|
||
|
end;
|
||
|
end;
|
||
|
end;
|
||
|
Len := Curs - StartCurs;
|
||
|
Result := H;
|
||
|
end;
|
||
|
|
||
|
{----------------TfrxHtCellBasic.MinMaxWidth}
|
||
|
|
||
|
procedure TfrxHtCellBasic.MinMaxWidth(Canvas: TCanvas; out Min, Max: Integer; AvailableWidth, AvailableHeight: Integer);
|
||
|
{Find the Width the cell would take if no wordwrap, Max, and the width if wrapped
|
||
|
at largest word, Min}
|
||
|
var
|
||
|
I, Mn, Mx: Integer;
|
||
|
begin
|
||
|
Max := 0; Min := 0;
|
||
|
for I := 0 to Count - 1 do
|
||
|
begin
|
||
|
Items[I].MinMaxWidth(Canvas, Mn, Mx, AvailableWidth, AvailableHeight);
|
||
|
Max := Math.Max(Max, Mx);
|
||
|
Min := Math.Max(Min, Mn);
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
{----------------TfrxHtCellBasic.Draw}
|
||
|
|
||
|
function TfrxHtCellBasic.Draw(Canvas: TCanvas; ARect: TRect; ClipWidth, X: Integer; Y, XRef, YRef: Integer): Integer;
|
||
|
{draw the document or cell. Note: individual sections not in ARect don't bother
|
||
|
drawing}
|
||
|
var
|
||
|
I: Integer;
|
||
|
H: Integer;
|
||
|
begin
|
||
|
H := Y;
|
||
|
for I := 0 to Count - 1 do
|
||
|
H := Items[I].Draw1(Canvas, ARect, IMgr, X, XRef, YRef);
|
||
|
Result := H;
|
||
|
end;
|
||
|
|
||
|
{----------------TfrxHtBlock.Create}
|
||
|
|
||
|
constructor TfrxHtBlock.Create(Parent: TfrxHtCellBasic; Attributes: TfrxHtAttributeList; Prop: TfrxHTProperties);
|
||
|
var
|
||
|
S: ThtString;
|
||
|
begin
|
||
|
inherited Create(Parent, 0, Attributes, Prop);
|
||
|
MyCell := TfrxHtBlockCell.Create(Self);
|
||
|
DrawList := TfrxHtSectionBaseList.Create(False);
|
||
|
|
||
|
Prop.GetVMarginArray(MargArrayO);
|
||
|
HasBorderStyle := Prop.HasBorderStyle;
|
||
|
FGColor := Prop.Props[Color];
|
||
|
|
||
|
BlockTitle := Prop.PropTitle;
|
||
|
if not (Self is TfrxHtBodyBlock) and not (Self is TfrxHtTableAndCaptionBlock)
|
||
|
and Prop.GetBackgroundImage(S) and (S <> '') then
|
||
|
begin {body handles its own image}
|
||
|
BGImage := TfrxFrHtImageObj.SimpleCreate(MyCell, S);
|
||
|
Prop.GetBackgroundPos(EmSize, ExSize, PRec);
|
||
|
end;
|
||
|
|
||
|
Visibility := Prop.GetVisibility;
|
||
|
Prop.GetPageBreaks(BreakBefore, BreakAfter, KeepIntact);
|
||
|
if Positioning <> posStatic then
|
||
|
begin
|
||
|
ZIndex := 10 * Prop.GetZIndex;
|
||
|
if (Positioning = posAbsolute) and (ZIndex = 0) then
|
||
|
ZIndex := 1; {abs on top unless otherwise specified}
|
||
|
end;
|
||
|
if (Floating in [ALeft, ARight]) and (ZIndex = 0) then
|
||
|
ZIndex := 1;
|
||
|
if not IsInFlow then
|
||
|
begin
|
||
|
MyIMgr := TfrxHtIndentManager.Create;
|
||
|
MyCell.IMgr := MyIMgr;
|
||
|
end;
|
||
|
if not (Self is TfrxHtTableBlock) and not (Self is TfrxHtTableAndCaptionBlock) then
|
||
|
CollapseAdjoiningMargins;
|
||
|
HideOverflow := Prop.IsOverflowHidden;
|
||
|
|
||
|
RTL := Prop.Props[TextDirection] = 'rtl';
|
||
|
|
||
|
if VarIsEmpty(Prop.Props[TextAlign]) then // check for unassigned
|
||
|
begin
|
||
|
if RTL then
|
||
|
Justify := Right
|
||
|
else
|
||
|
Justify := Left;
|
||
|
end
|
||
|
else if Prop.Props[TextAlign] = 'right' then
|
||
|
Justify := Right
|
||
|
else if Prop.Props[TextAlign] = 'center' then
|
||
|
Justify := Centered
|
||
|
else
|
||
|
Justify := Left;
|
||
|
|
||
|
end;
|
||
|
|
||
|
//-- BG ---------------------------------------------------------- 17.05.2014 --
|
||
|
function Collapse(A, B: Integer): Integer; {$ifdef UseInline} inline; {$endif}
|
||
|
begin
|
||
|
if A >= 0 then
|
||
|
if B >= 0 then
|
||
|
Result := Max(A, B)
|
||
|
else
|
||
|
Result := A + B
|
||
|
else
|
||
|
if B >= 0 then
|
||
|
Result := B + A
|
||
|
else
|
||
|
Result := Min(A, B);
|
||
|
end;
|
||
|
|
||
|
procedure TfrxHtBlock.CollapseAdjoiningMargins;
|
||
|
{adjacent vertical margins need to be reduced}
|
||
|
var
|
||
|
TB: TfrxHtSectionBase;
|
||
|
Block: TfrxHtBlock absolute TB;
|
||
|
LastMargin, I: Integer;
|
||
|
Tag: TElemSymb;
|
||
|
CD: ThtConvData;
|
||
|
begin
|
||
|
CD := ConvData(100, 100 {width and height not known at this point}, EmSize, ExSize, BorderWidth);
|
||
|
ConvVertMargins(MargArrayO, CD, MargArray);
|
||
|
TopAuto := MarginTop in CD.IsAutoParagraph;
|
||
|
BottomAuto := MarginBottom in CD.IsAutoParagraph;
|
||
|
if (MargArray[PaddingTop] <> 0) or (MargArray[BorderTopWidth] <> 0) then {do nothing}
|
||
|
else if Positioning = posAbsolute then
|
||
|
begin
|
||
|
if TopAuto then
|
||
|
MargArray[MarginTop] := 0;
|
||
|
end
|
||
|
else if Floating in [ALeft, ARight] then {do nothing}
|
||
|
else if Display = pdNone then {do nothing}
|
||
|
else
|
||
|
begin
|
||
|
TB := nil;
|
||
|
I := OwnerCell.Count - 1; {find the preceding block that isn't absolute positioning}
|
||
|
while I >= 0 do
|
||
|
begin
|
||
|
TB := OwnerCell[I];
|
||
|
if TB.Display <> pdNone then
|
||
|
if not (TB is TfrxHtBlock) or (TfrxHtBlock(TB).Positioning <> PosAbsolute) then
|
||
|
break;
|
||
|
Dec(I);
|
||
|
end;
|
||
|
|
||
|
if OwnerCell.OwnerBlock <> nil then
|
||
|
Tag := OwnerCell.OwnerBlock.Symbol
|
||
|
else
|
||
|
Tag := OtherChar;
|
||
|
if I < 0 then
|
||
|
begin {no previous non absolute block, remove any Auto paragraph space}
|
||
|
case Tag of
|
||
|
BodySy:
|
||
|
MargArray[MarginTop] := Max(0, MargArray[MarginTop] - OwnerBlock.MargArray[MarginTop]);
|
||
|
else
|
||
|
if TopAuto then
|
||
|
MargArray[MarginTop] := 0;
|
||
|
end;
|
||
|
end
|
||
|
else
|
||
|
begin
|
||
|
if ((TB is TfrxHtTableBlock) or (TB is TfrxHtTableAndCaptionBlock)) and (TfrxHtBlock(TB).Floating in [ALeft, ARight]) and TopAuto then
|
||
|
MargArray[MarginTop] := 0
|
||
|
else if TB is TfrxHtBlock then
|
||
|
begin
|
||
|
if Block.Positioning = posStatic then
|
||
|
begin
|
||
|
LastMargin := Block.MargArray[MarginBottom];
|
||
|
Block.MargArray[MarginBottom] := 0;
|
||
|
MargArray[MarginTop] := Collapse(LastMargin, MargArray[MarginTop]);
|
||
|
end
|
||
|
end
|
||
|
else if (Tag = LISy) and TopAuto and (Symbol in [ULSy, OLSy]) then
|
||
|
MargArray[MarginTop] := 0; {removes space from nested lists}
|
||
|
end;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
//-- BG ---------------------------------------------------------- 16.05.2014 --
|
||
|
procedure TfrxHtBlock.CollapseNestedMargins;
|
||
|
var
|
||
|
TB: TfrxHtSectionBase;
|
||
|
Block: TfrxHtBlock absolute TB;
|
||
|
I, J, M: Integer;
|
||
|
begin
|
||
|
if (OwnerCell <> Document) and (MargArray[piHeight] = 0) and (MargArray[piMinHeight] = 0) then
|
||
|
begin
|
||
|
J := 0;
|
||
|
if MargArray[BorderTopWidth] = 0 then
|
||
|
begin
|
||
|
// collapse with first sectionbase, if it is an in-flow block.
|
||
|
|
||
|
// find block to collapse
|
||
|
while J < MyCell.Count do
|
||
|
begin
|
||
|
TB := MyCell[J];
|
||
|
if TB.Display <> pdNone then
|
||
|
if not (TB is TfrxHtBlock) or ((Block.Positioning <> PosAbsolute) and (Block.Floating = aNone)) then
|
||
|
break;
|
||
|
Inc(J);
|
||
|
end;
|
||
|
|
||
|
if J < MyCell.Count then
|
||
|
begin
|
||
|
if (TB is TfrxHtBlock) and (Block.Positioning = posStatic) then
|
||
|
begin
|
||
|
// collapse margins, if it has no top padding
|
||
|
if (Block.MargArray[PaddingTop] = 0) then
|
||
|
begin
|
||
|
M := Block.MargArray[MarginTop];
|
||
|
Block.MargArray[MarginTop] := 0;
|
||
|
MargArray[MarginTop] := Collapse(MargArray[MarginTop], M);
|
||
|
end;
|
||
|
end;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
if MargArray[BorderBottomWidth] = 0 then
|
||
|
begin
|
||
|
// collapse with last sectionbase, if it is an in-flow block.
|
||
|
|
||
|
// find block to collapse
|
||
|
I := MyCell.Count - 1;
|
||
|
while I >= J do
|
||
|
begin
|
||
|
TB := MyCell[I];
|
||
|
if TB.Display <> pdNone then
|
||
|
if not (TB is TfrxHtBlock) or ((Block.Positioning <> PosAbsolute) and (Block.Floating = aNone)) then
|
||
|
break;
|
||
|
Dec(I);
|
||
|
end;
|
||
|
|
||
|
if I >= 0 then
|
||
|
begin
|
||
|
if (TB is TfrxHtBlock) and (Block.Positioning = posStatic) then
|
||
|
begin
|
||
|
// collapse margins, if it has no bottom padding
|
||
|
if (Block.MargArray[PaddingBottom] = 0) then
|
||
|
begin
|
||
|
M := Block.MargArray[MarginBottom];
|
||
|
Block.MargArray[MarginBottom] := 0;
|
||
|
MargArray[MarginBottom] := Collapse(MargArray[MarginBottom], M);
|
||
|
end;
|
||
|
end;
|
||
|
end;
|
||
|
end;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
//-- BG ---------------------------------------------------------- 09.10.2010 --
|
||
|
procedure TfrxHtBlock.ContentMinMaxWidth(Canvas: TCanvas; out Min, Max: Integer; AvailableWidth, AvailableHeight: Integer);
|
||
|
begin
|
||
|
MyCell.MinMaxWidth(Canvas, Min, Max, AvailableWidth, AvailableHeight);
|
||
|
end;
|
||
|
|
||
|
//-- BG ---------------------------------------------------------- 06.10.2010 --
|
||
|
procedure TfrxHtBlock.ConvMargArray(BaseWidth, BaseHeight: Integer; out AutoCount: Integer);
|
||
|
begin
|
||
|
frxHTMLStyleUn.ConvMargArray(MargArrayO, BaseWidth, BaseHeight, EmSize, ExSize, BorderWidth, AutoCount, MargArray);
|
||
|
end;
|
||
|
|
||
|
{----------------TfrxHtBlock.CreateCopy}
|
||
|
|
||
|
constructor TfrxHtBlock.CreateCopy(Parent: TfrxHtCellBasic; Source: TfrxHtmlNode);
|
||
|
var
|
||
|
T: TfrxHtBlock absolute Source;
|
||
|
begin
|
||
|
inherited CreateCopy(Parent,Source);
|
||
|
System.Move(T.MargArray, MargArray, PtrSub(@Converted, @MargArray) + Sizeof(Converted));
|
||
|
MyCell := TfrxHtBlockCell.CreateCopy(Self, T.MyCell);
|
||
|
DrawList := TfrxHtSectionBaseList.Create(False);
|
||
|
if Assigned(T.BGImage) and Document.PrintTableBackground then
|
||
|
BGImage := TfrxFrHtImageObj.CreateCopy(MyCell, T.BGImage);
|
||
|
MargArrayO := T.MargArrayO;
|
||
|
if not IsInFlow then
|
||
|
begin
|
||
|
MyIMgr := TfrxHtIndentManager.Create;
|
||
|
MyCell.IMgr := MyIMgr;
|
||
|
end;
|
||
|
BlockTitle := T.BlockTitle; // Thanks to Nagy Ervin.
|
||
|
end;
|
||
|
|
||
|
destructor TfrxHtBlock.Destroy;
|
||
|
begin
|
||
|
BGImage.Free;
|
||
|
TiledImage.Free;
|
||
|
if MyIMgr <> nil then
|
||
|
begin
|
||
|
MyCell.IMgr := nil;
|
||
|
FreeAndNil(MyIMgr);
|
||
|
end;
|
||
|
FreeAndNil(MyCell);
|
||
|
DrawList.Free;
|
||
|
inherited Destroy;
|
||
|
end;
|
||
|
|
||
|
procedure TfrxHtBlock.MinMaxWidth(Canvas: TCanvas; out Min, Max: Integer; AvailableWidth, AvailableHeight: Integer);
|
||
|
var
|
||
|
MinCell, MaxCell: Integer;
|
||
|
LeftSide, RightSide, AutoCount: Integer;
|
||
|
begin
|
||
|
if (Display = pdNone) or (Positioning in [PosAbsolute, posFixed]) then
|
||
|
begin
|
||
|
Min := 0;
|
||
|
Max := 0;
|
||
|
Exit;
|
||
|
end;
|
||
|
|
||
|
{$ifdef DO_BLOCK_INLINE}
|
||
|
if Display = pdInline then
|
||
|
begin
|
||
|
inherited MinMaxWidth(Canvas, Min, Max, AvailableWidth, AvailableHeight);
|
||
|
exit;
|
||
|
end;
|
||
|
{$endif}
|
||
|
|
||
|
ConvMargArray(AvailableWidth, AvailableHeight, AutoCount);
|
||
|
//HideOverflow := HideOverflow and (MargArray[piWidth] <> Auto) and (MargArray[piWidth] > 20);
|
||
|
if HideOverflow and (MargArray[piWidth] <> Auto) and (MargArray[piWidth] > 20) then
|
||
|
begin
|
||
|
MinCell := MargArray[piWidth];
|
||
|
MaxCell := MinCell;
|
||
|
end
|
||
|
else
|
||
|
ContentMinMaxWidth(Canvas, MinCell, MaxCell, AvailableWidth, AvailableHeight);
|
||
|
if MargArray[MarginLeft] = Auto then
|
||
|
MargArray[MarginLeft] := 0;
|
||
|
if MargArray[MarginRight] = Auto then
|
||
|
MargArray[MarginRight] := 0;
|
||
|
if MargArray[piWidth] = Auto then
|
||
|
MargArray[piWidth] := 0;
|
||
|
LeftSide := MargArray[MarginLeft] + MargArray[BorderLeftWidth] + MargArray[PaddingLeft];
|
||
|
RightSide := MargArray[MarginRight] + MargArray[BorderRightWidth] + MargArray[PaddingRight];
|
||
|
if MargArray[piWidth] > 0 then
|
||
|
begin
|
||
|
Min := MargArray[piWidth] + LeftSide + RightSide;
|
||
|
Max := Min;
|
||
|
end
|
||
|
else
|
||
|
begin
|
||
|
Min := Math.Max(MinCell, MargArray[piWidth]) + LeftSide + RightSide;
|
||
|
Max := Math.Max(MaxCell, MargArray[piWidth]) + LeftSide + RightSide;
|
||
|
end;
|
||
|
if (MargArray[piMinWidth] > 0) and (MargArray[piMinWidth] > Min) then
|
||
|
Min := MargArray[piMinWidth];
|
||
|
if (MargArray[piMaxWidth] > 0) and (MargArray[piMaxWidth] < Max) then
|
||
|
Max := MargArray[piMaxWidth];
|
||
|
end;
|
||
|
|
||
|
{----------------TfrxHtBlock.FindString}
|
||
|
|
||
|
function TfrxHtBlock.FindString(From: Integer; const ToFind: UnicodeString; MatchCase: Boolean): Integer;
|
||
|
begin
|
||
|
case Display of
|
||
|
pdNone: Result := -1;
|
||
|
{$ifdef DO_BLOCK_INLINE}
|
||
|
pdInline: Result := inherited FindString(From, ToFind, MatchCase);
|
||
|
{$endif}
|
||
|
else
|
||
|
Result := MyCell.FindString(From, ToFind, MatchCase);
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
{----------------TfrxHtBlock.FindStringR}
|
||
|
|
||
|
function TfrxHtBlock.FindStringR(From: Integer; const ToFind: UnicodeString; MatchCase: Boolean): Integer;
|
||
|
begin
|
||
|
case Display of
|
||
|
pdNone: Result := -1;
|
||
|
{$ifdef DO_BLOCK_INLINE}
|
||
|
pdInline: Result := inherited FindStringR(From, ToFind, MatchCase);
|
||
|
{$endif}
|
||
|
else
|
||
|
Result := MyCell.FindStringR(From, ToFind, MatchCase);
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
procedure TfrxHtBlock.AddSectionsToList;
|
||
|
begin
|
||
|
MyCell.AddSectionsToList;
|
||
|
end;
|
||
|
|
||
|
{----------------TfrxHtBlock.GetChAtPos}
|
||
|
|
||
|
function TfrxHtBlock.GetChAtPos(Pos: Integer; out Ch: WideChar; out Obj: TfrxHtSectionBase): Boolean;
|
||
|
begin
|
||
|
Obj := nil;
|
||
|
case Display of
|
||
|
pdNone: Result := False;
|
||
|
{$ifdef DO_BLOCK_INLINE}
|
||
|
pdInline: Result := inherited GetChAtPos(Pos, Ch, Obj);
|
||
|
{$endif}
|
||
|
else
|
||
|
Result := MyCell.GetChAtPos(Pos, Ch, Obj);
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
//-- BG ---------------------------------------------------------- 30.11.2013 --
|
||
|
function TfrxHtBlock.CalcDisplayExtern: ThtDisplayStyle;
|
||
|
begin
|
||
|
Result := inherited CalcDisplayExtern;
|
||
|
case Result of
|
||
|
pdInline:
|
||
|
Result := MyCell.CalcDisplayExtern;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
//-- BG ---------------------------------------------------------- 07.09.2013 --
|
||
|
function TfrxHtBlock.CalcDisplayIntern: ThtDisplayStyle;
|
||
|
begin
|
||
|
Result := inherited CalcDisplayIntern;
|
||
|
// case Result of
|
||
|
// pdNone:;
|
||
|
// else
|
||
|
// //Result := MyCell.CalcDisplayExtern;
|
||
|
// end;
|
||
|
end;
|
||
|
|
||
|
function TfrxHtBlock.FindDocPos(SourcePos: Integer; Prev: Boolean): Integer;
|
||
|
begin
|
||
|
case Display of
|
||
|
pdNone: Result := -1;
|
||
|
{$ifdef DO_BLOCK_INLINE}
|
||
|
pdInline: Result := inherited FindDocPos(SourcePos, Prev);
|
||
|
{$endif}
|
||
|
else
|
||
|
Result := MyCell.FindDocPos(SourcePos, Prev);
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
function TfrxHtBlock.FindSourcePos(DocPos: Integer): Integer;
|
||
|
begin
|
||
|
case Display of
|
||
|
pdNone: Result := -1;
|
||
|
{$ifdef DO_BLOCK_INLINE}
|
||
|
pdInline: Result := inherited FindSourcePos(DocPos);
|
||
|
{$endif}
|
||
|
else
|
||
|
Result := MyCell.FindSourcePos(DocPos);
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
{----------------TfrxHtBlock.FindWidth}
|
||
|
|
||
|
function TfrxHtBlock.FindWidth(Canvas: TCanvas; AWidth, AHeight, AutoCount: Integer): Integer;
|
||
|
var
|
||
|
Marg2: Integer;
|
||
|
MinWidth, MaxWidth: Integer;
|
||
|
|
||
|
function BordPad: Integer;
|
||
|
begin
|
||
|
Result := MargArray[BorderLeftWidth] + MargArray[BorderRightWidth] +
|
||
|
MargArray[PaddingLeft] + MargArray[PaddingRight];
|
||
|
end;
|
||
|
|
||
|
function BordWidth: Integer;
|
||
|
begin
|
||
|
Result := MargArray[BorderLeftWidth] + MargArray[BorderRightWidth] +
|
||
|
MargArray[PaddingLeft] + MargArray[PaddingRight] +
|
||
|
MargArray[MarginLeft] + MargArray[MarginRight];
|
||
|
end;
|
||
|
|
||
|
procedure CalcWidth;
|
||
|
begin
|
||
|
if Positioning = posAbsolute then
|
||
|
begin
|
||
|
if (MargArray[piLeft] = Auto) and (MargArray[piRight] <> Auto) then
|
||
|
MargArray[piWidth] := MaxWidth
|
||
|
else
|
||
|
MargArray[piWidth] := Max(MinWidth, AWidth - BordWidth - LeftP);
|
||
|
end
|
||
|
else if (Floating in [ALeft, ARight]) then
|
||
|
MargArray[piWidth] := Min(MaxWidth, AWidth - BordWidth)
|
||
|
else
|
||
|
MargArray[piWidth] := Max(MinWidth, AWidth - BordWidth);
|
||
|
end;
|
||
|
|
||
|
procedure CalcMargRt;
|
||
|
begin
|
||
|
MargArray[MarginRight] := Max(0, AWidth - BordPad - MargArray[MarginLeft] - MargArray[piWidth]);
|
||
|
end;
|
||
|
|
||
|
procedure CalcMargLf;
|
||
|
begin
|
||
|
MargArray[MarginLeft] := Max(0, AWidth - BordPad - MargArray[MarginRight] - MargArray[piWidth]);
|
||
|
end;
|
||
|
|
||
|
begin
|
||
|
ContentMinMaxWidth(Canvas, MinWidth, MaxWidth, AWidth, AHeight);
|
||
|
//HideOverflow := HideOverflow and (MargArray[piWidth] <> Auto) and (MargArray[piWidth] > 20);
|
||
|
case AutoCount of
|
||
|
0:
|
||
|
begin
|
||
|
if (Justify in [centered, Right]) and (Positioning = posStatic)
|
||
|
and not (Floating in [ALeft, ARight]) and
|
||
|
(MargArray[MarginLeft] = 0) and (MargArray[MarginRight] = 0) then
|
||
|
begin
|
||
|
ApplyBoxWidthSettings(MargArray, MinWidth, MaxWidth);
|
||
|
Marg2 := Max(0, AWidth - MargArray[piWidth] - BordPad);
|
||
|
case Justify of
|
||
|
centered:
|
||
|
begin
|
||
|
MargArray[MarginLeft] := Marg2 div 2;
|
||
|
MargArray[MarginRight] := Marg2 div 2;
|
||
|
end;
|
||
|
right:
|
||
|
MargArray[MarginLeft] := Marg2;
|
||
|
end;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
1:
|
||
|
if MargArray[piWidth] = Auto then begin
|
||
|
ApplyBoxWidthSettings(MargArray, MinWidth, MaxWidth);
|
||
|
CalcWidth;
|
||
|
end
|
||
|
else
|
||
|
begin
|
||
|
if MargArray[MarginRight] = Auto then
|
||
|
if (Floating in [ALeft, ARight]) then
|
||
|
MargArray[MarginRight] := 0
|
||
|
else
|
||
|
CalcMargRt
|
||
|
else
|
||
|
CalcMargLf;
|
||
|
end;
|
||
|
|
||
|
2:
|
||
|
if MargArray[piWidth] = Auto then
|
||
|
begin
|
||
|
if MargArray[MarginLeft] = Auto then
|
||
|
MargArray[MarginLeft] := 0
|
||
|
else
|
||
|
MargArray[MarginRight] := 0;
|
||
|
ApplyBoxWidthSettings(MargArray, MinWidth, MaxWidth);
|
||
|
CalcWidth;
|
||
|
end
|
||
|
else
|
||
|
begin
|
||
|
Marg2 := Max(0, AWidth - MargArray[piWidth] - BordPad);
|
||
|
MargArray[MarginLeft] := Marg2 div 2;
|
||
|
MargArray[MarginRight] := Marg2 - MargArray[MarginLeft];
|
||
|
end;
|
||
|
|
||
|
3:
|
||
|
begin
|
||
|
MargArray[MarginLeft] := 0;
|
||
|
MargArray[MarginRight] := 0;
|
||
|
ApplyBoxWidthSettings(MargArray, MinWidth, MaxWidth);
|
||
|
CalcWidth;
|
||
|
end;
|
||
|
end;
|
||
|
Result := MargArray[piWidth];
|
||
|
end;
|
||
|
|
||
|
{----------------TfrxHtBlock.DrawLogic}
|
||
|
|
||
|
function TfrxHtBlock.DrawLogic1(Canvas: TCanvas; X, Y, XRef, YRef, AWidth, AHeight, BlHt: Integer; IMgr: TfrxHtIndentManager;
|
||
|
var MaxWidth, Curs: Integer; ARemainHeight: Integer): Integer;
|
||
|
var
|
||
|
ScrollWidth, YClear: Integer;
|
||
|
LIndex, RIndex: Integer;
|
||
|
SaveID: TObject;
|
||
|
TotalWidth, LeftWidths, RightWidths, MiscWidths: Integer;
|
||
|
AutoCount: Integer;
|
||
|
BlockHeight: Integer;
|
||
|
IB, Xin: Integer;
|
||
|
|
||
|
function GetClientContentBot(ClientContentBot: Integer): Integer;
|
||
|
var
|
||
|
H: Integer;
|
||
|
begin
|
||
|
if VarIsIntNull(MargArrayO[piHeight]) then
|
||
|
Result := Max(ContentTop, ClientContentBot)
|
||
|
else
|
||
|
begin
|
||
|
if Pos('%', VarToStr(MargArrayO[piHeight])) > 0 then
|
||
|
H := LengthConv(MargArrayO[piHeight], False, AHeight, EmSize, ExSize, 0)
|
||
|
else
|
||
|
H := MargArray[piHeight];
|
||
|
Result := Max(H + ContentTop, ContentTop);
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
procedure DrawLogicAsBlock;
|
||
|
var
|
||
|
LIndent, RIndent: Integer;
|
||
|
ARect: TRect;
|
||
|
begin
|
||
|
YDraw := Y;
|
||
|
Xin := X;
|
||
|
ClearAddOn := GetClearSpace(IMgr, Y);
|
||
|
StartCurs := Curs;
|
||
|
MaxWidth := AWidth;
|
||
|
|
||
|
ConvMargArray(AWidth, AHeight, AutoCount);
|
||
|
HasBorderStyle :=
|
||
|
(ThtBorderStyle(MargArray[BorderTopStyle]) <> bssNone) or
|
||
|
(ThtBorderStyle(MargArray[BorderRightStyle]) <> bssNone) or
|
||
|
(ThtBorderStyle(MargArray[BorderBottomStyle]) <> bssNone) or
|
||
|
(ThtBorderStyle(MargArray[BorderLeftStyle]) <> bssNone);
|
||
|
|
||
|
ApplyBoxSettings(MargArray);
|
||
|
ContentWidth := FindWidth(Canvas, AWidth, AHeight, AutoCount);
|
||
|
LeftWidths := MargArray[MarginLeft] + MargArray[PaddingLeft] + MargArray[BorderLeftWidth];
|
||
|
RightWidths := MargArray[MarginRight] + MargArray[PaddingRight] + MargArray[BorderRightWidth];
|
||
|
MiscWidths := LeftWidths + RightWidths;
|
||
|
TotalWidth := MiscWidths + ContentWidth;
|
||
|
|
||
|
case Positioning of
|
||
|
posAbsolute:
|
||
|
ARect := ContainingBox;
|
||
|
|
||
|
posFixed:
|
||
|
ARect := Document.ViewPort;
|
||
|
end;
|
||
|
|
||
|
FIndent := LeftWidths;
|
||
|
TopP := 0;
|
||
|
LeftP := 0;
|
||
|
case Positioning of
|
||
|
posAbsolute,
|
||
|
posFixed:
|
||
|
begin
|
||
|
if not IsAuto(GetPosition(reLeft)) then
|
||
|
X := ARect.Left + GetPosition(reLeft)
|
||
|
else if not IsAuto(GetPosition(reRight)) and not IsAuto(MargArray[piWidth]) then
|
||
|
X := ARect.Right - GetPosition(reRight) - MargArray[piWidth];
|
||
|
LeftP := X;
|
||
|
|
||
|
if not IsAuto(GetPosition(reTop)) then
|
||
|
Y := ARect.Top + GetPosition(reTop)
|
||
|
else if not IsAuto(GetPosition(reBottom)) and not IsAuto(MargArray[piHeight]) then
|
||
|
Y := ARect.Bottom - GetPosition(reBottom) - MargArray[piHeight];
|
||
|
TopP := Y;
|
||
|
|
||
|
DrawTop := TopP + Max(0, MargArray[MarginTop]); {Border top}
|
||
|
end;
|
||
|
else
|
||
|
if Positioning = posRelative then
|
||
|
begin
|
||
|
if not IsAuto(GetPosition(reLeft)) then Inc(LeftP, GetPosition(reLeft));
|
||
|
if not IsAuto(GetPosition(reTop)) then Inc(TopP, GetPosition(reTop));
|
||
|
end;
|
||
|
|
||
|
case Floating of
|
||
|
ALeft:
|
||
|
begin
|
||
|
YClear := Y;
|
||
|
LIndent := IMgr.AlignLeft(YClear, TotalWidth);
|
||
|
FIndent := LIndent + LeftWidths - X;
|
||
|
end;
|
||
|
|
||
|
ARight:
|
||
|
begin
|
||
|
YClear := Y;
|
||
|
RIndent := IMgr.AlignRight(YClear, TotalWidth);
|
||
|
FIndent := RIndent + LeftWidths - X;
|
||
|
end;
|
||
|
else
|
||
|
YClear := Y + ClearAddon;
|
||
|
end;
|
||
|
DrawTop := YClear + Max(0, MargArray[MarginTop]); {Border top}
|
||
|
end;
|
||
|
Inc(X, FIndent);
|
||
|
|
||
|
ContentTop := DrawTop + MargArray[PaddingTop] + MargArray[BorderTopWidth];
|
||
|
|
||
|
if not IsInFlow then
|
||
|
begin
|
||
|
RefIMgr := IMgr;
|
||
|
if MyCell.IMgr = nil then
|
||
|
begin
|
||
|
MyIMgr := TfrxHtIndentManager.Create;
|
||
|
MyCell.IMgr := MyIMgr;
|
||
|
end;
|
||
|
IMgr := MyCell.IMgr;
|
||
|
IMgr.Init(0, ContentWidth);
|
||
|
end
|
||
|
else
|
||
|
begin
|
||
|
MyCell.IMgr := IMgr;
|
||
|
end;
|
||
|
|
||
|
SaveID := IMgr.CurrentID;
|
||
|
IMgr.CurrentID := Self;
|
||
|
|
||
|
LIndex := IMgr.SetLeftIndent(X, YClear);
|
||
|
RIndex := IMgr.SetRightIndent(X + ContentWidth, YClear);
|
||
|
|
||
|
if MargArray[piHeight] > 0 then
|
||
|
BlockHeight := MargArray[piHeight]
|
||
|
else if AHeight > 0 then
|
||
|
BlockHeight := AHeight
|
||
|
else
|
||
|
BlockHeight := BlHt;
|
||
|
|
||
|
case Positioning of
|
||
|
posRelative:
|
||
|
begin
|
||
|
MyCell.DoLogicX(Canvas,
|
||
|
X,
|
||
|
ContentTop + TopP,
|
||
|
XRef,
|
||
|
ContentTop + TopP,
|
||
|
ContentWidth, MargArray[piHeight], BlockHeight, ScrollWidth, Curs, ARemainHeight);
|
||
|
MaxWidth := ScrollWidth + MiscWidths - MargArray[MarginRight] + LeftP - Xin;
|
||
|
ClientContentBot := GetClientContentBot(MyCell.tcContentBot - TopP);
|
||
|
end;
|
||
|
|
||
|
posAbsolute:
|
||
|
begin
|
||
|
MyCell.DoLogicX(Canvas,
|
||
|
X,
|
||
|
ContentTop,
|
||
|
XRef + LeftP + MargArray[MarginLeft] + MargArray[BorderLeftWidth],
|
||
|
YRef + TopP + MargArray[MarginTop] + MargArray[BorderTopWidth],
|
||
|
ContentWidth, MargArray[piHeight], BlockHeight, ScrollWidth, Curs, ARemainHeight);
|
||
|
MaxWidth := ScrollWidth + MiscWidths - MargArray[MarginRight] + LeftP - Xin;
|
||
|
ClientContentBot := GetClientContentBot(MyCell.tcContentBot);
|
||
|
IB := IMgr.ImageBottom; {check for image overhang}
|
||
|
if IB > ClientContentBot then
|
||
|
ClientContentBot := IB;
|
||
|
end;
|
||
|
|
||
|
posFixed:
|
||
|
begin
|
||
|
MyCell.DoLogicX(Canvas,
|
||
|
X,
|
||
|
ContentTop,
|
||
|
XRef + LeftP + MargArray[MarginLeft] + MargArray[BorderLeftWidth],
|
||
|
YRef + TopP + MargArray[MarginTop] + MargArray[BorderTopWidth],
|
||
|
ContentWidth, MargArray[piHeight], BlockHeight, ScrollWidth, Curs, ARemainHeight);
|
||
|
MaxWidth := ScrollWidth + MiscWidths - MargArray[MarginRight] + LeftP - Xin;
|
||
|
ClientContentBot := GetClientContentBot(MyCell.tcContentBot);
|
||
|
IB := IMgr.ImageBottom; {check for image overhang}
|
||
|
if IB > ClientContentBot then
|
||
|
ClientContentBot := IB;
|
||
|
end;
|
||
|
|
||
|
else
|
||
|
MyCell.DoLogicX(Canvas,
|
||
|
X,
|
||
|
ContentTop,
|
||
|
XRef,
|
||
|
YRef,
|
||
|
ContentWidth, MargArray[piHeight], BlockHeight, ScrollWidth, Curs, ARemainHeight);
|
||
|
MaxWidth := Indent + ScrollWidth + RightWidths;
|
||
|
ClientContentBot := GetClientContentBot(MyCell.tcContentBot);
|
||
|
end;
|
||
|
Len := Curs - StartCurs;
|
||
|
|
||
|
ContentBot := ClientContentBot + MargArray[PaddingBottom] + MargArray[BorderBottomWidth] + MargArray[MarginBottom];
|
||
|
if ContentBot = ContentTop then
|
||
|
if IsInFlow then
|
||
|
begin
|
||
|
// no content, hide top margin
|
||
|
DrawTop := YClear;
|
||
|
ContentTop := DrawTop;
|
||
|
ClientContentBot := ContentTop;
|
||
|
ContentBot := ClientContentBot;
|
||
|
end;
|
||
|
|
||
|
DrawBot := Max(ClientContentBot, MyCell.tcDrawBot) + MargArray[PaddingBottom] + MargArray[BorderBottomWidth];
|
||
|
|
||
|
Result := ContentBot - Y;
|
||
|
|
||
|
if Assigned(BGImage) and Document.ShowImages then
|
||
|
begin
|
||
|
BGImage.DrawLogicInline(Canvas, nil, 100, 0);
|
||
|
if BGImage.Image = ErrorImage then
|
||
|
begin
|
||
|
FreeAndNil(BGImage);
|
||
|
NeedDoImageStuff := False;
|
||
|
end
|
||
|
else
|
||
|
begin
|
||
|
BGImage.ClientSizeKnown := True; {won't need reformat on InsertImage}
|
||
|
NeedDoImageStuff := True;
|
||
|
end;
|
||
|
end;
|
||
|
SectionHeight := Result;
|
||
|
IMgr.FreeLeftIndentRec(LIndex);
|
||
|
IMgr.FreeRightIndentRec(RIndex);
|
||
|
if not IsInFlow then
|
||
|
begin
|
||
|
case Positioning of
|
||
|
posAbsolute,
|
||
|
posFixed:
|
||
|
DrawHeight := 0
|
||
|
else
|
||
|
DrawHeight := 0; //SectionHeight;
|
||
|
case Floating of
|
||
|
ALeft: RefIMgr.AddLeft(YClear, ContentBot, TotalWidth);
|
||
|
ARight: RefIMgr.AddRight(YClear, ContentBot, TotalWidth);
|
||
|
end;
|
||
|
end;
|
||
|
//SectionHeight := 0;
|
||
|
Result := 0;
|
||
|
end
|
||
|
else
|
||
|
begin
|
||
|
DrawHeight := IMgr.ImageBottom - Y; {in case image overhangs}
|
||
|
if DrawHeight < SectionHeight then
|
||
|
DrawHeight := SectionHeight;
|
||
|
end;
|
||
|
IMgr.CurrentID := SaveID;
|
||
|
if DrawList.Count = 0 then
|
||
|
DrawSort;
|
||
|
end;
|
||
|
|
||
|
procedure DrawLogicInline;
|
||
|
begin
|
||
|
//TODO -oBG, 15.03.2014: draw logic inline
|
||
|
DrawLogicAsBlock;
|
||
|
end;
|
||
|
|
||
|
procedure Invisible;
|
||
|
begin
|
||
|
SectionHeight := 0;
|
||
|
DrawHeight := 0;
|
||
|
ContentBot := 0;
|
||
|
DrawBot := 0;
|
||
|
MaxWidth := 0;
|
||
|
Result := 0;
|
||
|
end;
|
||
|
|
||
|
begin {TfrxHtBlock.DrawLogic1}
|
||
|
case CalcDisplayIntern of
|
||
|
|
||
|
pdInline:
|
||
|
DrawLogicInline;
|
||
|
|
||
|
pdNone:
|
||
|
Invisible;
|
||
|
else
|
||
|
// pdBlock:
|
||
|
// pdTable:
|
||
|
DrawLogicAsBlock;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
{----------------TfrxHtBlock.DrawSort}
|
||
|
|
||
|
procedure TfrxHtBlock.DrawSort;
|
||
|
var
|
||
|
I, ZeroIndx, EndZeroIndx, SBZIndex: Integer;
|
||
|
SB: TfrxHtSectionBase;
|
||
|
|
||
|
procedure InsertSB(I1, I2: Integer);
|
||
|
var
|
||
|
J: Integer;
|
||
|
Inserted: Boolean;
|
||
|
begin
|
||
|
Inserted := False;
|
||
|
for J := I1 to I2 - 1 do
|
||
|
if SBZIndex < DrawList[J].ZIndex then
|
||
|
begin
|
||
|
DrawList.Insert(J, SB);
|
||
|
Inserted := True;
|
||
|
Break;
|
||
|
end;
|
||
|
if not Inserted then
|
||
|
DrawList.Insert(I2, SB);
|
||
|
end;
|
||
|
|
||
|
begin
|
||
|
ZeroIndx := 0;
|
||
|
EndZeroIndx := 0;
|
||
|
for I := 0 to MyCell.Count - 1 do
|
||
|
begin
|
||
|
SB := MyCell.Items[I];
|
||
|
SB.FOwnerBlock := Self;
|
||
|
SBZIndex := SB.ZIndex;
|
||
|
if SBZIndex < 0 then
|
||
|
begin
|
||
|
InsertSB(0, ZeroIndx);
|
||
|
Inc(ZeroIndx);
|
||
|
Inc(EndZeroIndx);
|
||
|
end
|
||
|
else if SBZIndex = 0 then {most items go here}
|
||
|
begin
|
||
|
DrawList.Insert(EndZeroIndx, SB);
|
||
|
Inc(EndZeroIndx);
|
||
|
end
|
||
|
else
|
||
|
InsertSB(EndZeroIndx, DrawList.Count);
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
{----------------TfrxHtBlock.Draw1}
|
||
|
|
||
|
function TfrxHtBlock.Draw1(Canvas: TCanvas; const ARect: TRect; IMgr: TfrxHtIndentManager; X, XRef, YRef: Integer): Integer;
|
||
|
|
||
|
procedure DrawAsBlock;
|
||
|
var
|
||
|
Y: Integer;
|
||
|
begin
|
||
|
Y := YDraw;
|
||
|
Result := Y + SectionHeight;
|
||
|
|
||
|
if Visibility = viHidden then
|
||
|
Exit;
|
||
|
|
||
|
if Document.SkipDraw then
|
||
|
begin
|
||
|
Document.SkipDraw := False;
|
||
|
Exit;
|
||
|
end;
|
||
|
|
||
|
case Positioning of
|
||
|
posRelative:
|
||
|
DrawBlock(Canvas, ARect, IMgr, X + LeftP, Y + TopP, XRef, YRef);
|
||
|
|
||
|
posAbsolute:
|
||
|
DrawBlock(Canvas, ARect, IMgr, LeftP, TopP, 0, 0);
|
||
|
|
||
|
posFixed:
|
||
|
DrawBlock(Canvas, ARect, IMgr, LeftP, TopP, 0, 0);
|
||
|
|
||
|
else
|
||
|
if Floating in [ALeft, ARight] then
|
||
|
DrawBlock(Canvas, ARect, IMgr, X, Y, XRef, YRef)
|
||
|
else
|
||
|
DrawBlock(Canvas, ARect, IMgr, X, Y, XRef, YRef);
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
procedure DrawInline;
|
||
|
begin
|
||
|
DrawAsBlock;
|
||
|
end;
|
||
|
|
||
|
begin
|
||
|
case CalcDisplayIntern of
|
||
|
|
||
|
pdInline:
|
||
|
DrawInline;
|
||
|
|
||
|
pdNone:
|
||
|
Result := 0;
|
||
|
|
||
|
else
|
||
|
// pdBlock:
|
||
|
// pdTable:
|
||
|
DrawAsBlock;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
{----------------TfrxHtBlock.DrawBlock}
|
||
|
|
||
|
procedure TfrxHtBlock.DrawBlock(Canvas: TCanvas; const ARect: TRect;
|
||
|
IMgr: TfrxHtIndentManager; X, Y, XRef, YRef: Integer);
|
||
|
|
||
|
var
|
||
|
YOffset: Integer;
|
||
|
XR, YB, RefX, RefY, TmpHt: Integer;
|
||
|
SaveID: TObject;
|
||
|
ImgOK, HasBackgroundColor: Boolean;
|
||
|
IT, IH, FT, IW: Integer;
|
||
|
Rgn, SaveRgn, SaveRgn1: HRgn;
|
||
|
OpenRgn: Boolean;
|
||
|
PdRect, CnRect: TRect; // padding rect, content rect
|
||
|
NegativeMargins: Boolean;
|
||
|
begin
|
||
|
YOffset := Document.YOff;
|
||
|
|
||
|
case Floating of
|
||
|
ALeft, ARight:
|
||
|
begin
|
||
|
//X := IMgr.LfEdge + Indent;
|
||
|
X := X + Indent;
|
||
|
RefX := X - MargArray[PaddingLeft] - MargArray[BorderLeftWidth];
|
||
|
XR := X + ContentWidth + MargArray[PaddingRight] + MargArray[BorderRightWidth];
|
||
|
RefY := DrawTop;
|
||
|
YB := ContentBot - MargArray[MarginBottom];
|
||
|
end;
|
||
|
else
|
||
|
// BG, 08.09.2013: inline vs block:
|
||
|
// X of centered blocks may differ from (DrawRect.Left - MargArray[MarginLeft]) calculated in DrawLogic1().
|
||
|
RefX := X + MargArray[MarginLeft];
|
||
|
|
||
|
X := X + Indent;
|
||
|
|
||
|
// RefX := DrawRect.Left;
|
||
|
// X := RefX - MargArray[MarginLeft] + Indent;
|
||
|
XR := X + ContentWidth + MargArray[PaddingRight] + MargArray[BorderRightWidth]; {current right edge}
|
||
|
RefY := Y + ClearAddon + MargArray[MarginTop];
|
||
|
YB := ContentBot - MargArray[MarginBottom];
|
||
|
case Positioning of
|
||
|
posRelative:
|
||
|
Inc(YB, TopP);
|
||
|
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
// MyRect is the outmost rectangle of this block incl. border and padding but without margins in screen coordinates.
|
||
|
case Positioning of
|
||
|
posFixed:
|
||
|
MyRect := Rect(RefX, RefY, XR, YB);
|
||
|
else
|
||
|
MyRect := Rect(RefX, RefY - YOffset, XR, YB - YOffset);
|
||
|
end;
|
||
|
|
||
|
// PdRect is the border rectangle of this block incl. padding in screen coordinates
|
||
|
PdRect.Left := MyRect.Left + MargArray[BorderLeftWidth];
|
||
|
PdRect.Top := MyRect.Top + MargArray[BorderTopWidth];
|
||
|
PdRect.Right := MyRect.Right - MargArray[BorderRightWidth];
|
||
|
PdRect.Bottom := MyRect.Bottom - MargArray[BorderBottomWidth];
|
||
|
|
||
|
// CnRect is the content rectangle of this block in screen coordinates
|
||
|
CnRect.Left := PdRect.Left + MargArray[PaddingLeft];
|
||
|
CnRect.Top := PdRect.Top + MargArray[PaddingTop];
|
||
|
CnRect.Right := PdRect.Right - MargArray[PaddingRight];
|
||
|
CnRect.Bottom := PdRect.Bottom - MargArray[PaddingBottom];
|
||
|
|
||
|
IT := Max(0, ARect.Top - 2 - PdRect.Top);
|
||
|
FT := Max(PdRect.Top, ARect.Top - 2); {top of area drawn, screen coordinates}
|
||
|
IH := Min(PdRect.Bottom, ARect.Bottom) - FT; {height of area actually drawn}
|
||
|
IW := PdRect.Right - PdRect.Left;
|
||
|
|
||
|
NegativeMargins := (MargArray[MarginLeft] < 0) or (MargArray[MarginTop] < 0) or (MargArray[MarginBottom] < 0) or (MargArray[MarginRight] < 0);
|
||
|
SaveRgn1 := 0;
|
||
|
OpenRgn := ((Positioning <> PosStatic) or NegativeMargins) and (Document.TableNestLevel > 0);
|
||
|
if OpenRgn then
|
||
|
begin
|
||
|
SaveRgn1 := CreateRectRgn(0, 0, 1, 1);
|
||
|
case GetClipRgn(Canvas.Handle, SaveRgn1) of
|
||
|
-1, // failed to get the clip region
|
||
|
0: // there is no clip region
|
||
|
begin
|
||
|
DeleteObject(SaveRgn1);
|
||
|
SaveRgn1 := 0;
|
||
|
end;
|
||
|
else
|
||
|
//1: got the clip region
|
||
|
SelectClipRgn(Canvas.Handle, 0);
|
||
|
end;
|
||
|
end;
|
||
|
try
|
||
|
if (MyRect.Top <= ARect.Bottom) and (MyRect.Bottom >= ARect.Top) then
|
||
|
begin
|
||
|
HasBackgroundColor := MargArray[BackgroundColor] <> clNone;
|
||
|
try
|
||
|
if NeedDoImageStuff and Assigned(BGImage) and (BGImage.Image <> DefImage) then
|
||
|
begin
|
||
|
if BGImage.Image = ErrorImage then {Skip the background image}
|
||
|
FreeAndNil(BGImage)
|
||
|
else
|
||
|
try
|
||
|
if Floating in [ALeft, ARight] then
|
||
|
TmpHt := DrawBot - ContentTop + MargArray[PaddingTop] + MargArray[PaddingBottom]
|
||
|
else
|
||
|
TmpHt := ClientContentBot - ContentTop + MargArray[PaddingTop] + MargArray[PaddingBottom];
|
||
|
|
||
|
BgImage.Image.TileImage( PRec,
|
||
|
MargArray[PaddingLeft] + ContentWidth + MargArray[PaddingRight], TmpHt,
|
||
|
TiledImage, NoMask);
|
||
|
if IsCopy and Assigned(TiledImage) then
|
||
|
TiledImage.Bitmap.HandleType := bmDIB;
|
||
|
except {bad image, get rid of it}
|
||
|
FreeAndNil(BGImage);
|
||
|
FreeAndNil(TiledImage);
|
||
|
end;
|
||
|
NeedDoImageStuff := False;
|
||
|
end;
|
||
|
|
||
|
if Document.NoOutput then
|
||
|
exit;
|
||
|
|
||
|
ImgOK := not NeedDoImageStuff and (BGImage <> nil) and (BGImage.Image <> DefImage) and (TiledImage <> nil) and Document.ShowImages;
|
||
|
|
||
|
if HasBackgroundColor {and (not Document.Printing or Document.PrintBackground)} then
|
||
|
begin {color the Padding Region}
|
||
|
Canvas.Brush.Style := bsSolid;
|
||
|
Canvas.Brush.Color := ThemedColor(MargArray[BackgroundColor]) or PalRelative;
|
||
|
end
|
||
|
else
|
||
|
Canvas.Brush.Style := bsClear;
|
||
|
|
||
|
if ImgOK then
|
||
|
if not IsCopy then
|
||
|
TiledImage.DrawUnstretched(Canvas, PdRect.Left, FT, IW, IH, 0, IT, HasBackgroundColor )
|
||
|
else
|
||
|
TiledImage.PrintUnstretched(Canvas, PdRect.Left, FT, IW, IH, 0, IT, HasBackgroundColor and Document.PrintBackground )
|
||
|
else
|
||
|
Canvas.FillRect(Rect(PdRect.Left, FT, PdRect.Right, FT + IH));
|
||
|
except
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
if HideOverflow then
|
||
|
begin
|
||
|
Rgn := 0;
|
||
|
SaveRgn := 0;
|
||
|
if Floating = ANone then
|
||
|
GetClippingRgn(Canvas, CnRect, False, Rgn, SaveRgn)
|
||
|
else
|
||
|
GetClippingRgn(Canvas, PdRect, False, Rgn, SaveRgn);
|
||
|
SelectClipRgn(Canvas.Handle, Rgn);
|
||
|
end;
|
||
|
try
|
||
|
SaveID := IMgr.CurrentID;
|
||
|
Imgr.CurrentID := Self;
|
||
|
case Positioning of
|
||
|
posRelative:
|
||
|
DrawTheList(Canvas, ARect, ContentWidth, X,
|
||
|
RefX + MargArray[BorderLeftWidth] + MargArray[PaddingLeft],
|
||
|
Y + MargArray[MarginTop] + MargArray[BorderTopWidth] + MargArray[PaddingTop]);
|
||
|
|
||
|
posAbsolute:
|
||
|
DrawTheList(Canvas, ARect, ContentWidth, X,
|
||
|
RefX + MargArray[BorderLeftWidth],
|
||
|
Y + MargArray[MarginTop] + MargArray[BorderTopWidth]);
|
||
|
|
||
|
posFixed:
|
||
|
DrawTheList(Canvas, ARect, ContentWidth, X,
|
||
|
PdRect.Left,
|
||
|
PdRect.Top);
|
||
|
else
|
||
|
DrawTheList(Canvas, ARect, ContentWidth, X, XRef, YRef);
|
||
|
end;
|
||
|
Imgr.CurrentID := SaveID;
|
||
|
finally
|
||
|
if HideOverflow then {restore any previous clip region}
|
||
|
begin
|
||
|
SelectClipRgn(Canvas.Handle, SaveRgn);
|
||
|
DeleteObject(Rgn);
|
||
|
if SaveRgn <> 0 then
|
||
|
DeleteObject(SaveRgn);
|
||
|
end;
|
||
|
end;
|
||
|
DrawBlockBorder(Canvas, MyRect, PdRect);
|
||
|
finally
|
||
|
if SaveRgn1 <> 0 then
|
||
|
begin
|
||
|
SelectClipRgn(Canvas.Handle, SaveRgn1);
|
||
|
DeleteObject(SaveRgn1);
|
||
|
end;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
procedure TfrxHtBlock.DrawBlockBorder(Canvas: TCanvas; const ORect, IRect: TRect);
|
||
|
begin
|
||
|
if HasBorderStyle then
|
||
|
if (ORect.Left <> IRect.Left) or (ORect.Top <> IRect.Top) or (ORect.Right <> IRect.Right) or (ORect.Bottom <> IRect.Bottom) then
|
||
|
DrawBorder(Canvas, ORect, IRect,
|
||
|
htColors(MargArray[BorderLeftColor], MargArray[BorderTopColor], MargArray[BorderRightColor], MargArray[BorderBottomColor]),
|
||
|
htStyles(ThtBorderStyle(MargArray[BorderLeftStyle]), ThtBorderStyle(MargArray[BorderTopStyle]), ThtBorderStyle(MargArray[BorderRightStyle]), ThtBorderStyle(MargArray[BorderBottomStyle])),
|
||
|
MargArray[BackgroundColor], False)
|
||
|
end;
|
||
|
|
||
|
procedure TfrxHtBlock.DrawTheList(Canvas: TCanvas; const ARect: TRect; ClipWidth, X, XRef, YRef: Integer);
|
||
|
{draw the list sorted by Z order.}
|
||
|
var
|
||
|
I: Integer;
|
||
|
SaveID: TObject;
|
||
|
begin
|
||
|
if not IsInFlow then
|
||
|
with MyCell do
|
||
|
begin
|
||
|
SaveID := IMgr.CurrentID;
|
||
|
IMgr.Reset(RefIMgr.LfEdge);
|
||
|
IMgr.ClipWidth := ClipWidth;
|
||
|
IMgr.CurrentID := SaveID;
|
||
|
end
|
||
|
else
|
||
|
MyCell.IMgr.ClipWidth := ClipWidth;
|
||
|
for I := 0 to DrawList.Count - 1 do
|
||
|
begin
|
||
|
if RTL then
|
||
|
if (DrawList[I] is TfrxHtBlockLI) then
|
||
|
DrawList[I].OwnerIndent := Indent
|
||
|
else if (Self is TfrxHtBlockLI) and (DrawList[I] is TfrxHtSection) then
|
||
|
DrawList[I].OwnerIndent := OwnerIndent;
|
||
|
DrawList[I].Draw1(Canvas, ARect, MyCell.IMgr, X, XRef, YRef);
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
{$ifdef UseFormTree}
|
||
|
procedure TfrxHtBlock.FormTree(const Indent: ThtString; var Tree: ThtString);
|
||
|
var
|
||
|
MyIndent: ThtString;
|
||
|
TM, BM: ThtString;
|
||
|
begin
|
||
|
MyIndent := Indent + ' ';
|
||
|
TM := IntToStr(MargArray[MarginTop]);
|
||
|
BM := IntToStr(MargArray[MarginBottom]);
|
||
|
Tree := Tree + Indent + TagClass + ' ' + TM + ' ' + BM + CrChar + LfChar;
|
||
|
MyCell.FormTree(MyIndent, Tree);
|
||
|
end;
|
||
|
{$endif UseFormTree}
|
||
|
|
||
|
//-- BG ---------------------------------------------------------- 24.08.2010 --
|
||
|
function TfrxHtBlock.GetBorderWidth: Integer;
|
||
|
begin
|
||
|
Result := 3;
|
||
|
end;
|
||
|
|
||
|
{----------------TfrxHtTableAndCaptionBlock.Create}
|
||
|
|
||
|
constructor TfrxHtTableAndCaptionBlock.Create(
|
||
|
Parent: TfrxHtCellBasic; Attributes: TfrxHtAttributeList; Prop: TfrxHTProperties; ATableBlock: TfrxHtTableBlock);
|
||
|
var
|
||
|
I: Integer;
|
||
|
begin
|
||
|
inherited Create(Parent, Attributes, Prop);
|
||
|
TableBlock := ATableBlock;
|
||
|
Justify := TableBlock.Justify;
|
||
|
|
||
|
for I := 0 to Attributes.Count - 1 do
|
||
|
with Attributes[I] do
|
||
|
case Which of
|
||
|
AlignSy:
|
||
|
if htCompareText(Name, 'CENTER') = 0 then
|
||
|
Justify := Centered
|
||
|
else if htCompareText(Name, 'LEFT') = 0 then
|
||
|
begin
|
||
|
if FFloating = ANone then
|
||
|
FFloating := ALeft;
|
||
|
end
|
||
|
else if htCompareText(Name, 'RIGHT') = 0 then
|
||
|
begin
|
||
|
if FFloating = ANone then
|
||
|
FFloating := ARight;
|
||
|
end;
|
||
|
end;
|
||
|
TableID := Attributes.TheID;
|
||
|
|
||
|
{CollapseMargins has already been called by TableBlock, copy the results here}
|
||
|
MargArray[MarginTop] := TableBlock.MargArray[MarginTop];
|
||
|
MargArray[MarginBottom] := TableBlock.MargArray[MarginBottom];
|
||
|
|
||
|
TagClass := 'TableAndCaption.';
|
||
|
end;
|
||
|
|
||
|
{----------------TfrxHtTableAndCaptionBlock.CancelUsage}
|
||
|
|
||
|
procedure TfrxHtTableAndCaptionBlock.CancelUsage;
|
||
|
{called when it's found that this block isn't needed (no caption)}
|
||
|
begin
|
||
|
{assign the ID back to the Table}
|
||
|
if TableID <> '' then
|
||
|
Document.IDNameList.AddObject(TableID, TableBlock);
|
||
|
end;
|
||
|
|
||
|
{----------------TfrxHtTableAndCaptionBlock.CreateCopy}
|
||
|
|
||
|
constructor TfrxHtTableAndCaptionBlock.CreateCopy(OwnerCell: TfrxHtCellBasic; Source: TfrxHtmlNode);
|
||
|
var
|
||
|
T: TfrxHtTableAndCaptionBlock absolute Source;
|
||
|
Item: TObject;
|
||
|
I1, I2: Integer;
|
||
|
begin
|
||
|
inherited CreateCopy(OwnerCell,Source);
|
||
|
TopCaption := T.TopCaption;
|
||
|
TagClass := 'TableAndCaption.';
|
||
|
I1 := Ord(TopCaption);
|
||
|
I2 := Ord(not TopCaption);
|
||
|
Item := MyCell.Items[I2];
|
||
|
FCaptionBlock := (Item as TfrxHtBlock);
|
||
|
Item := MyCell.Items[I1];
|
||
|
TableBlock := (Item as TfrxHtTableBlock);
|
||
|
end;
|
||
|
|
||
|
procedure TfrxHtTableAndCaptionBlock.SetCaptionBlock(Value: TfrxHtBlock);
|
||
|
begin
|
||
|
FCaptionBlock := Value;
|
||
|
TableBlock.HasCaption := True;
|
||
|
end;
|
||
|
|
||
|
{----------------TfrxHtTableAndCaptionBlock.FindWidth}
|
||
|
|
||
|
function TfrxHtTableAndCaptionBlock.FindWidth(Canvas: TCanvas; AWidth, AHeight, AutoCount: Integer): Integer;
|
||
|
var
|
||
|
Mx, Mn, FWidth: Integer;
|
||
|
begin
|
||
|
HasBorderStyle := False; //bssNone; {has no border}
|
||
|
MargArray[BorderLeftWidth] := 0;
|
||
|
MargArray[BorderTopWidth] := 0;
|
||
|
MargArray[BorderRightWidth] := 0;
|
||
|
MargArray[BorderBottomWidth] := 0;
|
||
|
MargArray[PaddingLeft] := 0;
|
||
|
MargArray[PaddingTop] := 0;
|
||
|
MargArray[PaddingRight] := 0;
|
||
|
MargArray[PaddingBottom] := 0;
|
||
|
MargArray[BackgroundColor] := clNone;
|
||
|
|
||
|
TableBlock.FFloating := ANone;
|
||
|
TableBlock.Table.Float := False;
|
||
|
|
||
|
CaptionBlock.MinMaxWidth(Canvas, Mn, Mx, AWidth, AHeight);
|
||
|
FWidth := TableBlock.FindWidth1(Canvas, AWidth, AHeight, MargArray[MarginLeft] + MargArray[MarginRight]);
|
||
|
Result := Max(FWidth, Mn);
|
||
|
if (Result < AWidth) and (MargArray[MarginLeft] = 0) and (MargArray[MarginRight] = 0) then
|
||
|
case Justify of
|
||
|
Centered:
|
||
|
MargArray[MarginLeft] := (AWidth - Result) div 2;
|
||
|
Right:
|
||
|
MargArray[MarginLeft] := AWidth - Result;
|
||
|
end;
|
||
|
TableBlock.Justify := Centered;
|
||
|
end;
|
||
|
|
||
|
{----------------TfrxHtTableAndCaptionBlock.MinMaxWidth}
|
||
|
|
||
|
procedure TfrxHtTableAndCaptionBlock.MinMaxWidth(Canvas: TCanvas; out Min, Max: Integer; AvailableWidth, AvailableHeight: Integer);
|
||
|
var
|
||
|
Mx, Mn, MxTable, MnTable: Integer;
|
||
|
begin
|
||
|
TableBlock.MinMaxWidth(Canvas, MnTable, MxTable, AvailableWidth, AvailableHeight);
|
||
|
FCaptionBlock.MinMaxWidth(Canvas, Mn, Mx, AvailableWidth, AvailableHeight);
|
||
|
Min := Math.Max(MnTable, Mn);
|
||
|
Max := Math.Max(MxTable, Mn);
|
||
|
end;
|
||
|
|
||
|
function TfrxHtTableAndCaptionBlock.FindDocPos(SourcePos: Integer; Prev: Boolean): Integer;
|
||
|
begin
|
||
|
if not Prev then
|
||
|
begin
|
||
|
Result := FCaptionBlock.FindDocPos(SourcePos, Prev);
|
||
|
if Result < 0 then
|
||
|
Result := TableBlock.FindDocPos(SourcePos, Prev);
|
||
|
end
|
||
|
else {Prev, iterate backwards}
|
||
|
begin
|
||
|
Result := TableBlock.FindDocPos(SourcePos, Prev);
|
||
|
if Result < 0 then
|
||
|
Result := FCaptionBlock.FindDocPos(SourcePos, Prev);
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
{----------------TfrxHtTableBlock.Create}
|
||
|
|
||
|
constructor TfrxHtTableBlock.Create(Parent: TfrxHtCellBasic; Attr: TfrxHtAttributeList; Prop: TfrxHTProperties; TableLevel: Integer);
|
||
|
var
|
||
|
I, AutoCount: Integer;
|
||
|
BorderWidth: Integer;
|
||
|
Percent: Boolean;
|
||
|
TheProps, MyProps: TfrxHTProperties;
|
||
|
begin
|
||
|
Table := TfrxHtmlTable.Create(Self, Parent, Attr, Prop);
|
||
|
|
||
|
// BG, 20.01.2013: translate table attributes to block property defaults:
|
||
|
MyProps := TfrxHTProperties.CreateCopy(Prop);
|
||
|
TheProps := MyProps;
|
||
|
try
|
||
|
if Table.BorderColor <> clNone then
|
||
|
MyProps.SetPropertyDefaults([BorderBottomColor, BorderRightColor, BorderTopColor, BorderLeftColor], Table.BorderColor)
|
||
|
else
|
||
|
begin
|
||
|
if Table.HasBorderWidthAttr then
|
||
|
MyProps.SetPropertyDefaults([BorderBottomColor, BorderRightColor, BorderTopColor, BorderLeftColor], clGray)
|
||
|
else
|
||
|
MyProps.SetPropertyDefaults([BorderBottomColor, BorderRightColor, BorderTopColor, BorderLeftColor], clNone);
|
||
|
end;
|
||
|
|
||
|
MyProps.SetPropertyDefault(BorderSpacingHorz, Table.CellSpacingHorz);
|
||
|
MyProps.SetPropertyDefault(BorderSpacingVert, Table.CellSpacingVert);
|
||
|
|
||
|
if Table.HasBorderWidthAttr then
|
||
|
MyProps.SetPropertyDefaults([BorderBottomWidth, BorderRightWidth, BorderTopWidth, BorderLeftWidth], Table.brdWidthAttr);
|
||
|
|
||
|
case Table.Frame of
|
||
|
tfBox, tfBorder:
|
||
|
MyProps.SetPropertyDefaults([BorderBottomStyle, BorderRightStyle, BorderTopStyle, BorderLeftStyle], bssOutset);
|
||
|
|
||
|
tfHSides:
|
||
|
begin
|
||
|
MyProps.SetPropertyDefaults([BorderTopStyle, BorderBottomStyle], bssSolid);
|
||
|
MyProps.SetPropertyDefaults([BorderLeftStyle, BorderRightStyle], bssNone);
|
||
|
end;
|
||
|
|
||
|
tfVSides:
|
||
|
begin
|
||
|
MyProps.SetPropertyDefaults([BorderTopStyle, BorderBottomStyle], bssNone);
|
||
|
MyProps.SetPropertyDefaults([BorderLeftStyle, BorderRightStyle], bssSolid);
|
||
|
end;
|
||
|
|
||
|
tfAbove:
|
||
|
begin
|
||
|
MyProps.SetPropertyDefault(BorderTopStyle, bssSolid);
|
||
|
MyProps.SetPropertyDefaults([BorderBottomStyle, BorderRightStyle, BorderLeftStyle], bssNone);
|
||
|
end;
|
||
|
|
||
|
tfBelow:
|
||
|
begin
|
||
|
MyProps.SetPropertyDefault(BorderBottomStyle, bssSolid);
|
||
|
MyProps.SetPropertyDefaults([BorderRightStyle, BorderTopStyle, BorderLeftStyle], bssNone);
|
||
|
end;
|
||
|
|
||
|
tfLhs:
|
||
|
begin
|
||
|
MyProps.SetPropertyDefault(BorderLeftStyle, bssSolid);
|
||
|
MyProps.SetPropertyDefaults([BorderBottomStyle, BorderRightStyle, BorderTopStyle], bssNone);
|
||
|
end;
|
||
|
|
||
|
tfRhs:
|
||
|
begin
|
||
|
MyProps.SetPropertyDefault(BorderRightStyle, bssSolid);
|
||
|
MyProps.SetPropertyDefaults([BorderBottomStyle, BorderTopStyle, BorderLeftStyle], bssNone);
|
||
|
end;
|
||
|
else
|
||
|
if Table.HasBorderWidthAttr then
|
||
|
if Table.brdWidthAttr > 0 then
|
||
|
MyProps.SetPropertyDefaults([BorderBottomStyle, BorderRightStyle, BorderTopStyle, BorderLeftStyle], bssOutset)
|
||
|
else
|
||
|
MyProps.SetPropertyDefaults([BorderBottomStyle, BorderRightStyle, BorderTopStyle, BorderLeftStyle], bssNone);
|
||
|
end;
|
||
|
|
||
|
inherited Create(Parent, Attr, TheProps);
|
||
|
finally
|
||
|
MyProps.Free;
|
||
|
end;
|
||
|
|
||
|
Justify := NoJustify;
|
||
|
RTL := Prop.Props[TextDirection] = 'rtl';
|
||
|
|
||
|
for I := 0 to Attr.Count - 1 do
|
||
|
with Attr[I] do
|
||
|
case Which of
|
||
|
|
||
|
AlignSy:
|
||
|
if htCompareText(Name, 'CENTER') = 0 then
|
||
|
Justify := Centered
|
||
|
else if htCompareText(Name, 'LEFT') = 0 then
|
||
|
begin
|
||
|
//TODO: BG, 14.07.2013: The table block is not floating, but justified!
|
||
|
if FFloating = ANone then
|
||
|
FFloating := ALeft;
|
||
|
// Justify := Left;
|
||
|
end
|
||
|
else if htCompareText(Name, 'RIGHT') = 0 then
|
||
|
begin
|
||
|
//TODO: BG, 14.07.2013: The table block is not floating, but justified!
|
||
|
if FFloating = ANone then
|
||
|
FFloating := ARight;
|
||
|
// Justify := Right;
|
||
|
end;
|
||
|
|
||
|
BGColorSy:
|
||
|
BkGnd := TryStrToColor(Name, False, BkColor);
|
||
|
|
||
|
BackgroundSy:
|
||
|
if not Assigned(BGImage) and (Length(Name) > 0) then
|
||
|
begin
|
||
|
BGImage := TfrxFrHtImageObj.SimpleCreate(MyCell, Name);
|
||
|
PRec.X.PosType := bpDim;
|
||
|
PRec.X.Value := 0;
|
||
|
PRec.X.RepeatD := True;
|
||
|
PRec.Y := PRec.X;
|
||
|
end;
|
||
|
|
||
|
HSpaceSy:
|
||
|
HSpace := Min(40, Abs(Value));
|
||
|
|
||
|
VSpaceSy:
|
||
|
VSpace := Min(200, Abs(Value));
|
||
|
|
||
|
WidthSy:
|
||
|
if Pos('%', Name) > 0 then
|
||
|
begin
|
||
|
if (Value > 0) and (Value <= 100) then
|
||
|
WidthAttr := Value * 10;
|
||
|
AsPercent := True;
|
||
|
end
|
||
|
else
|
||
|
WidthAttr := Value;
|
||
|
|
||
|
HeightSy:
|
||
|
if (VarType(MargArrayO[piHeight]) in VarInt) and (MargArrayO[piHeight] = IntNull) then
|
||
|
MargArrayO[piHeight] := Name;
|
||
|
end;
|
||
|
|
||
|
if Table.BorderWidth > 0 then
|
||
|
BorderWidth := Table.BorderWidth
|
||
|
else
|
||
|
BorderWidth := 3;
|
||
|
|
||
|
{need to see if width is defined in style}
|
||
|
Percent := (VarIsStr(MargArrayO[piWidth])) and (Pos('%', MargArrayO[piWidth]) > 0);
|
||
|
frxHTMLStyleUn.ConvMargArray(MargArrayO, 100, 0, EmSize, ExSize, BorderWidth, AutoCount, MargArray);
|
||
|
if MargArray[piWidth] > 0 then
|
||
|
begin
|
||
|
if Percent then
|
||
|
begin
|
||
|
AsPercent := True;
|
||
|
WidthAttr := Min(1000, MargArray[piWidth] * 10);
|
||
|
end
|
||
|
else
|
||
|
begin
|
||
|
WidthAttr := MargArray[piWidth];
|
||
|
{By custom (not by specs), tables handle CSS Width property differently. The
|
||
|
Width includes the padding and border.}
|
||
|
MargArray[piWidth] := WidthAttr - MargArray[BorderLeftWidth] - MargArray[BorderRightWidth]
|
||
|
- MargArray[PaddingLeft] - MargArray[PaddingRight];
|
||
|
MargArrayO[piWidth] := MargArray[piWidth];
|
||
|
AsPercent := False;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
CollapseAdjoiningMargins;
|
||
|
Table.Float := Floating in [ALeft, ARight];
|
||
|
if Table.Float and (ZIndex = 0) then
|
||
|
ZIndex := 1;
|
||
|
end;
|
||
|
|
||
|
{----------------TfrxHtTableBlock.CreateCopy}
|
||
|
|
||
|
constructor TfrxHtTableBlock.CreateCopy(OwnerCell: TfrxHtCellBasic; Source: TfrxHtmlNode);
|
||
|
var
|
||
|
T: TfrxHtTableBlock absolute Source;
|
||
|
Item: TObject;
|
||
|
begin
|
||
|
inherited CreateCopy(OwnerCell,Source);
|
||
|
System.Move(T.WidthAttr, WidthAttr, PtrSub(@TableBorder, @WidthAttr) + SizeOf(WidthAttr));
|
||
|
Item := MyCell.Items[0];
|
||
|
Table := Item as TfrxHtmlTable;
|
||
|
end;
|
||
|
|
||
|
{----------------TfrxHtTableBlock.MinMaxWidth}
|
||
|
|
||
|
procedure TfrxHtTableBlock.MinMaxWidth(Canvas: TCanvas; out Min, Max: Integer; AvailableWidth, AvailableHeight: Integer);
|
||
|
var
|
||
|
TmpWidth: Integer;
|
||
|
begin
|
||
|
if AsPercent then
|
||
|
TmpWidth := 0
|
||
|
else
|
||
|
TmpWidth := Math.Max(0, WidthAttr - MargArray[BorderLeftWidth] - MargArray[BorderRightWidth]
|
||
|
- MargArray[PaddingLeft] - MargArray[PaddingRight]);
|
||
|
Table.tblWidthAttr := TmpWidth;
|
||
|
inherited MinMaxWidth(Canvas, Min, Max, AvailableWidth, AvailableHeight);
|
||
|
if TmpWidth > 0 then
|
||
|
begin
|
||
|
Min := Math.Max(Min, TmpWidth);
|
||
|
Max := Min;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
{----------------TfrxHtTableBlock.FindWidth1}
|
||
|
|
||
|
function TfrxHtTableBlock.FindWidth1(Canvas: TCanvas; AWidth, AHeight, ExtMarg: Integer): Integer;
|
||
|
{called by TfrxHtTableAndCaptionBlock to assist in it's FindWidth Calculation.
|
||
|
This method is called before TTableBlockFindWidth but is called only if there
|
||
|
is a caption on the table. AWidth is the full width available to the
|
||
|
TfrxHtTableAndCaptionBlock.}
|
||
|
var
|
||
|
PaddingAndBorder: Integer;
|
||
|
Min, Max, Allow: Integer;
|
||
|
begin
|
||
|
MargArray[MarginLeft] := 0;
|
||
|
MargArray[MarginRight] := 0;
|
||
|
MargArray[MarginTop] := 0;
|
||
|
MargArray[MarginBottom] := 0;
|
||
|
|
||
|
PaddingAndBorder :=
|
||
|
MargArray[BorderLeftWidth] + MargArray[PaddingLeft] +
|
||
|
MargArray[BorderRightWidth] + MargArray[PaddingRight];
|
||
|
Table.tblWidthAttr := 0;
|
||
|
if WidthAttr > 0 then
|
||
|
begin
|
||
|
if AsPercent then
|
||
|
Result := Math.Min(MulDiv(AWidth, WidthAttr, 1000), AWidth - ExtMarg)
|
||
|
else
|
||
|
Result := WidthAttr;
|
||
|
Result := Result - PaddingAndBorder;
|
||
|
Table.tblWidthAttr := Result;
|
||
|
Table.MinMaxWidth(Canvas, Min, Max, AWidth, AHeight);
|
||
|
Result := Math.Max(Min, Result);
|
||
|
Table.tblWidthAttr := Result;
|
||
|
end
|
||
|
else
|
||
|
begin
|
||
|
Table.MinMaxWidth(Canvas, Min, Max, AWidth, AHeight);
|
||
|
Allow := AWidth - PaddingAndBorder;
|
||
|
if Max <= Allow then
|
||
|
Result := Max
|
||
|
else if Min >= Allow then
|
||
|
Result := Min
|
||
|
else
|
||
|
Result := Allow;
|
||
|
end;
|
||
|
Result := Result + PaddingAndBorder;
|
||
|
end;
|
||
|
|
||
|
//-- BG ---------------------------------------------------------- 24.08.2010 --
|
||
|
function TfrxHtTableBlock.GetBorderWidth: Integer;
|
||
|
begin
|
||
|
Result := Table.BorderWidth;
|
||
|
if Result = 0 then
|
||
|
Result := 3;
|
||
|
end;
|
||
|
|
||
|
{----------------TfrxHtTableBlock.FindWidth}
|
||
|
|
||
|
function TfrxHtTableBlock.FindWidth(Canvas: TCanvas; AWidth, AHeight, AutoCount: Integer): Integer;
|
||
|
var
|
||
|
LeftSide, RightSide: Integer;
|
||
|
Min, Max, M, P: Integer;
|
||
|
begin
|
||
|
if not HasCaption then
|
||
|
begin
|
||
|
inherited FindWidth(Canvas, AWidth, AHeight, AUtoCount);
|
||
|
// if MargArray[MarginLeft] = Auto then
|
||
|
// MargArray[MarginLeft] := 0;
|
||
|
// if MargArray[MarginRight] = Auto then
|
||
|
// MargArray[MarginRight] := 0;
|
||
|
//
|
||
|
// if Floating in [ALeft, ARight] then
|
||
|
// begin
|
||
|
// if MargArray[MarginLeft] = 0 then
|
||
|
// MargArray[MarginLeft] := HSpace;
|
||
|
// if MargArray[MarginRight] = 0 then
|
||
|
// MargArray[MarginRight] := HSpace;
|
||
|
// if MargArray[MarginTop] = 0 then
|
||
|
// MargArray[MarginTop] := VSpace;
|
||
|
// if MargArray[MarginBottom] = 0 then
|
||
|
// MargArray[MarginBottom] := VSpace;
|
||
|
// end;
|
||
|
end
|
||
|
else
|
||
|
begin
|
||
|
MargArray[MarginLeft] := 0;
|
||
|
MargArray[MarginRight] := 0;
|
||
|
end;
|
||
|
|
||
|
if BkGnd and (MargArray[BackgroundColor] = clNone) then
|
||
|
MargArray[BackgroundColor] := BkColor;
|
||
|
Table.FBkGnd := (MargArray[BackgroundColor] <> clNone) and not Assigned(BGImage);
|
||
|
Table.FBkColor := MargArray[BackgroundColor]; {to be passed on to cells}
|
||
|
|
||
|
LeftSide := MargArray[MarginLeft] + MargArray[PaddingLeft] + MargArray[BorderLeftWidth];
|
||
|
RightSide := MargArray[MarginRight] + MargArray[PaddingRight] + MargArray[BorderRightWidth];
|
||
|
|
||
|
if not HasCaption then
|
||
|
Table.tblWidthAttr := 0;
|
||
|
if WidthAttr > 0 then
|
||
|
begin
|
||
|
if not HasCaption then {already done if HasCaption}
|
||
|
begin
|
||
|
if AsPercent then
|
||
|
Result := MulDiv(AWidth, WidthAttr, 1000) - LeftSide - RightSide
|
||
|
else
|
||
|
Result := WidthAttr - (MargArray[PaddingLeft] + MargArray[BorderLeftWidth] + MargArray[PaddingRight] + MargArray[BorderRightWidth]);
|
||
|
Table.tblWidthAttr := Result;
|
||
|
Table.MinMaxWidth(Canvas, Min, Max, AWidth, AHeight);
|
||
|
Table.tblWidthAttr := Math.Max(Min, Math.Min(Max, Result));
|
||
|
end;
|
||
|
Result := Table.tblWidthAttr;
|
||
|
end
|
||
|
else
|
||
|
begin
|
||
|
Result := AWidth - LeftSide - RightSide;
|
||
|
Table.MinMaxWidth(Canvas, Min, Max, AWidth, AHeight);
|
||
|
P := Math.Min(Sum(Table.Percents), 1000);
|
||
|
if P > 0 then
|
||
|
begin
|
||
|
P := MulDiv(Result, P, 1000);
|
||
|
Min := Math.Max(Min, P);
|
||
|
Max := Math.Max(Max, P);
|
||
|
end;
|
||
|
if Result > Max then
|
||
|
Result := Max
|
||
|
else if Result < Min then
|
||
|
Result := Min;
|
||
|
end;
|
||
|
MargArray[piWidth] := Result;
|
||
|
|
||
|
if (MargArray[MarginLeft] = 0) and (MargArray[MarginRight] = 0) and (Result + LeftSide + RightSide < AWidth) then
|
||
|
begin
|
||
|
M := AWidth - LeftSide - Result - RightSide;
|
||
|
case Justify of
|
||
|
Centered:
|
||
|
begin
|
||
|
MargArray[MarginLeft] := M div 2;
|
||
|
MargArray[MarginRight] := M - MargArray[MarginLeft];
|
||
|
end;
|
||
|
|
||
|
Right:
|
||
|
MargArray[MarginLeft] := M;
|
||
|
|
||
|
Left:
|
||
|
MargArray[MarginRight] := M;
|
||
|
|
||
|
end;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
function TfrxHtTableBlock.DrawLogic1(Canvas: TCanvas; X, Y, XRef, YRef, AWidth, AHeight, BlHt: Integer; IMgr: TfrxHtIndentManager;
|
||
|
var MaxWidth, Curs: Integer; ARemainHeight: Integer): Integer;
|
||
|
var
|
||
|
X1, Tmp: Integer;
|
||
|
begin
|
||
|
if not (Floating in [ALeft, ARight]) then
|
||
|
begin
|
||
|
Tmp := X;
|
||
|
X := Max(Tmp, IMgr.LeftIndent(Y));
|
||
|
TableIndent := X - Tmp;
|
||
|
X1 := Min(Tmp + AWidth, IMgr.RightSide(Y));
|
||
|
AWidth := X1 - X;
|
||
|
end;
|
||
|
Result := inherited DrawLogic1(Canvas, X, Y, XRef, YRef, AWidth, AHeight, BlHt, IMgr, MaxWidth, Curs, ARemainHeight);
|
||
|
end;
|
||
|
|
||
|
function TfrxHtTableBlock.Draw1(Canvas: TCanvas; const ARect: TRect; IMgr: TfrxHtIndentManager; X, XRef, YRef: Integer): Integer;
|
||
|
begin
|
||
|
X := X + TableIndent;
|
||
|
Result := inherited Draw1(Canvas, ARect, IMgr, X, XRef, YRef);
|
||
|
end;
|
||
|
|
||
|
procedure TfrxHtTableBlock.AddSectionsToList;
|
||
|
begin {Sections in Table not added only table itself}
|
||
|
Document.PositionList.Add(Table);
|
||
|
end;
|
||
|
|
||
|
constructor TfrxHtHRBlock.CreateCopy(OwnerCell: TfrxHtCellBasic; Source: TfrxHtmlNode);
|
||
|
var
|
||
|
T: TfrxHtHRBlock absolute Source;
|
||
|
begin
|
||
|
inherited CreateCopy(OwnerCell,Source);
|
||
|
Align := T.Align;
|
||
|
end;
|
||
|
|
||
|
{----------------TfrxHtHRBlock.FindWidth}
|
||
|
|
||
|
function TfrxHtHRBlock.FindWidth(Canvas: TCanvas; AWidth, AHeight, AutoCount: Integer): Integer;
|
||
|
var
|
||
|
LeftSide, RightSide, SWidth: Integer;
|
||
|
Diff: Integer;
|
||
|
begin
|
||
|
if Positioning = posAbsolute then
|
||
|
Align := Left;
|
||
|
LeftSide := MargArray[MarginLeft] + MargArray[PaddingLeft] + MargArray[BorderLeftWidth];
|
||
|
RightSide := MargArray[MarginRight] + MargArray[PaddingRight] + MargArray[BorderRightWidth];
|
||
|
SWidth := MargArray[piWidth];
|
||
|
|
||
|
if SWidth > 0 then
|
||
|
Result := Min(SWidth, AWidth - LeftSide - RightSide)
|
||
|
else
|
||
|
Result := Max(15, AWidth - LeftSide - RightSide);
|
||
|
MargArray[piWidth] := Result;
|
||
|
{note that above could be inherited; if LeftSide and Rightside were fields
|
||
|
of TfrxHtBlock}
|
||
|
|
||
|
if Align <> Left then
|
||
|
begin
|
||
|
Diff := AWidth - Result - LeftSide - RightSide;
|
||
|
if Diff > 0 then
|
||
|
case Align of
|
||
|
Centered: Inc(MargArray[MarginLeft], Diff div 2);
|
||
|
Right: Inc(MargArray[MarginLeft], Diff);
|
||
|
end;
|
||
|
end;
|
||
|
if not IsCopy then
|
||
|
TfrxHtHorzLine(MyHRule).VSize := MargArray[piHeight];
|
||
|
end;
|
||
|
|
||
|
{----------------TfrxHtBlockLI.Create}
|
||
|
|
||
|
constructor TfrxHtBlockLI.Create(Parent: TfrxHtCellBasic; Attributes: TfrxHtAttributeList; Prop: TfrxHTProperties;
|
||
|
Sy: TElemSymb; APlain: Boolean; AIndexType: ThtChar; AListNumb, ListLevel: Integer);
|
||
|
var
|
||
|
Tmp: ThtBulletStyle;
|
||
|
S: ThtString;
|
||
|
begin
|
||
|
inherited Create(Parent, Attributes, Prop);
|
||
|
|
||
|
Tmp := Prop.GetListStyleType;
|
||
|
if Tmp <> lbBlank then
|
||
|
FListStyleType := Tmp;
|
||
|
case Sy of
|
||
|
|
||
|
UlSy, DirSy, MenuSy:
|
||
|
begin
|
||
|
FListType := Unordered;
|
||
|
if APlain or (Display = pdInline) then
|
||
|
FListStyleType := lbNone
|
||
|
else
|
||
|
if Tmp = lbBlank then
|
||
|
case AIndexType of // type="disc|circle|square"
|
||
|
'd': FListStyleType := lbDisc;
|
||
|
'c': FListStyleType := lbCircle;
|
||
|
's': FListStyleType := lbSquare;
|
||
|
else
|
||
|
case ListLevel mod 3 of
|
||
|
1: FListStyleType := lbDisc;
|
||
|
2: FListStyleType := lbCircle;
|
||
|
0: FListStyleType := lbSquare;
|
||
|
end;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
OLSy:
|
||
|
begin
|
||
|
FListType := Ordered;
|
||
|
if Tmp = lbBlank then
|
||
|
case AIndexType of
|
||
|
'a': FListStyleType := lbLowerAlpha;
|
||
|
'A': FListStyleType := lbUpperAlpha;
|
||
|
'i': FListStyleType := lbLowerRoman;
|
||
|
'I': FListStyleType := lbUpperRoman;
|
||
|
else
|
||
|
FListStyleType := lbDecimal;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
DLSy:
|
||
|
FListType := Definition;
|
||
|
else
|
||
|
FListType := liAlone;
|
||
|
if Tmp = lbBlank then
|
||
|
FListStyleType := lbDisc;
|
||
|
if (VarType(MargArrayO[MarginLeft]) in varInt) and
|
||
|
((MargArrayO[MarginLeft] = IntNull) or (MargArrayO[MarginLeft] = 0)) then
|
||
|
MargArrayO[MarginLeft] := 16;
|
||
|
end;
|
||
|
|
||
|
if (VarType(MargArrayO[MarginLeft]) in varInt) and (MargArrayO[MarginLeft] = IntNull) then
|
||
|
case Sy of
|
||
|
|
||
|
OLSy, ULSy, DirSy, MenuSy, DLSy:
|
||
|
MargArrayO[MarginLeft] := 0;
|
||
|
|
||
|
else
|
||
|
MargArrayO[MarginLeft] := ListIndent;
|
||
|
end;
|
||
|
|
||
|
FListNumb := AListNumb;
|
||
|
FListFont := TfrxHtFont.Create;
|
||
|
FListFont.Assign(Prop.Font);
|
||
|
|
||
|
S := Prop.GetListStyleImage;
|
||
|
if S <> '' then
|
||
|
Image := TfrxFrHtImageObj.SimpleCreate(MyCell, S);
|
||
|
end;
|
||
|
|
||
|
constructor TfrxHtBlockLI.CreateCopy(OwnerCell: TfrxHtCellBasic; Source: TfrxHtmlNode);
|
||
|
var
|
||
|
T: TfrxHtBlockLI absolute Source;
|
||
|
begin
|
||
|
inherited CreateCopy(OwnerCell,Source);
|
||
|
FListType := T.FListType;
|
||
|
FListNumb := T.FListNumb;
|
||
|
FListStyleType := T.FListStyleType;
|
||
|
if Assigned(T.Image) then
|
||
|
Image := TfrxFrHtImageObj.CreateCopy(MyCell, T.Image);
|
||
|
FListFont := TfrxHtFont.Create;
|
||
|
FListFont.Assign(T.ListFont);
|
||
|
end;
|
||
|
|
||
|
destructor TfrxHtBlockLI.Destroy;
|
||
|
begin
|
||
|
ListFont.Free;
|
||
|
Image.Free;
|
||
|
inherited Destroy;
|
||
|
end;
|
||
|
|
||
|
function TfrxHtBlockLI.DrawLogic1(Canvas: TCanvas; X, Y, XRef, YRef, AWidth, AHeight, BlHt: Integer; IMgr: TfrxHtIndentManager;
|
||
|
var MaxWidth, Curs: Integer; ARemainHeight: Integer): Integer;
|
||
|
begin
|
||
|
if Assigned(Image) then
|
||
|
begin
|
||
|
Image.DrawLogicInline(Canvas, nil, 100, 0);
|
||
|
if Image.Image = ErrorImage then
|
||
|
FreeAndNil(Image);
|
||
|
end;
|
||
|
Document.FirstLineHtPtr := @FirstLineHt;
|
||
|
FirstLineHt := 0;
|
||
|
try
|
||
|
Result := inherited DrawLogic1(Canvas, X, Y, XRef, YRef, AWidth, AHeight, BlHt, IMgr, MaxWidth, Curs, ARemainHeight);
|
||
|
finally
|
||
|
Document.FirstLineHtPtr := nil;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
//-- BG ---------------------------------------------------------- 31.01.2012 --
|
||
|
procedure TfrxHtBlockLI.SetListFont(const Value: TFont);
|
||
|
begin
|
||
|
FListFont.Assign(Value);
|
||
|
end;
|
||
|
|
||
|
{----------------TfrxHtBlockLI.Draw}
|
||
|
|
||
|
function TfrxHtBlockLI.Draw1(Canvas: TCanvas; const ARect: TRect; IMgr: TfrxHtIndentManager; X, XRef, YRef: Integer): Integer;
|
||
|
|
||
|
const
|
||
|
MaxNumb = 26;
|
||
|
LowerAlpha: string = 'abcdefghijklmnopqrstuvwxyz';
|
||
|
HigherAlpha: string = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
|
||
|
LowerRoman: array[1..MaxNumb] of string = ('i', 'ii', 'iii', 'iv', 'v', 'vi',
|
||
|
'vii', 'viii', 'ix', 'x', 'xi', 'xii', 'xiii', 'xiv', 'xv', 'xvi', 'xvii',
|
||
|
'xviii', 'xix', 'xx', 'xxi', 'xxii', 'xxiii', 'xxiv', 'xxv', 'xxvi');
|
||
|
HigherRoman: array[1..MaxNumb] of string = ('I', 'II', 'III', 'IV', 'V', 'VI',
|
||
|
'VII', 'VIII', 'IX', 'X', 'XI', 'XII', 'XIII', 'XIV', 'XV', 'XVI', 'XVII',
|
||
|
'XVIII', 'XIX', 'XX', 'XXI', 'XXII', 'XXIII', 'XXIV', 'XXV', 'XXVI');
|
||
|
var
|
||
|
NStr: string;
|
||
|
BkMode, TAlign: Integer;
|
||
|
PenColor, BrushColor: TColor;
|
||
|
PenStyle: TPenStyle;
|
||
|
BrushStyle: TBrushStyle;
|
||
|
YB, AlphaNumb: Integer;
|
||
|
begin
|
||
|
Result := inherited Draw1(Canvas, ARect, IMgr, X, XRef, YRef);
|
||
|
|
||
|
X := IfInt(RTL, X + ContentWidth - 40, X + Indent);
|
||
|
|
||
|
if FirstLineHt > 0 then
|
||
|
begin
|
||
|
YB := FirstLineHt - Document.YOff;
|
||
|
if (YB < ARect.Top - 50) or (YB > ARect.Bottom + 50) then
|
||
|
Exit;
|
||
|
if Assigned(Image) and (Image.Image <> DefImage) and Document.ShowImages then
|
||
|
Image.DoDraw(Canvas, X - 16, YB - Image.ObjHeight, Image.Image)
|
||
|
else if not (ListType in [None, Definition]) then
|
||
|
begin
|
||
|
if ListStyleType in [lbDecimal, lbLowerAlpha, lbLowerRoman, lbUpperAlpha, lbUpperRoman] then
|
||
|
begin
|
||
|
AlphaNumb := Min(ListNumb, MaxNumb);
|
||
|
case ListStyleType of
|
||
|
lbLowerAlpha: NStr := LowerAlpha[AlphaNumb];
|
||
|
lbUpperAlpha: NStr := HigherAlpha[AlphaNumb];
|
||
|
lbLowerRoman: NStr := LowerRoman[AlphaNumb];
|
||
|
lbUpperRoman: NStr := HigherRoman[AlphaNumb];
|
||
|
else
|
||
|
NStr := IntToStr(ListNumb);
|
||
|
end;
|
||
|
Canvas.Font := ListFont;
|
||
|
Canvas.Font.Color := ThemedColor(ListFont.Color);
|
||
|
NStr := NStr + '.';
|
||
|
BkMode := SetBkMode(Canvas.Handle, Transparent);
|
||
|
|
||
|
if RTL then
|
||
|
TAlign := SetTextAlign(Canvas.Handle, TA_BASELINE or TA_RTLREADING)
|
||
|
else
|
||
|
TAlign := SetTextAlign(Canvas.Handle, TA_BASELINE);
|
||
|
if RTL then
|
||
|
Canvas.TextOut(X + 5, YB, NStr)
|
||
|
else
|
||
|
Canvas.TextOut(X - 5 - Canvas.TextWidth(NStr), YB, NStr);
|
||
|
|
||
|
SetTextAlign(Canvas.Handle, TAlign);
|
||
|
SetBkMode(Canvas.Handle, BkMode);
|
||
|
end
|
||
|
else if (ListStyleType in [lbCircle, lbDisc, lbSquare]) then
|
||
|
with Canvas do
|
||
|
begin
|
||
|
PenColor := Pen.Color;
|
||
|
PenStyle := Pen.Style;
|
||
|
Pen.Color := ThemedColor(ListFont.Color);
|
||
|
Pen.Style := psSolid;
|
||
|
BrushStyle := Brush.Style;
|
||
|
BrushColor := Brush.Color;
|
||
|
Brush.Style := bsSolid;
|
||
|
Brush.Color := ThemedColor(ListFont.Color);
|
||
|
X := IfInt(RTL, X + 25, X);
|
||
|
case ListStyleType of
|
||
|
lbCircle:
|
||
|
begin
|
||
|
Brush.Style := bsClear;
|
||
|
Circle(Canvas, X - 16, YB, 7);
|
||
|
end;
|
||
|
lbDisc:
|
||
|
Circle(Canvas, X - 15, YB - 1, 5);
|
||
|
lbSquare:
|
||
|
Rectangle(X - 15, YB - 6, X - 10, YB - 1);
|
||
|
end;
|
||
|
Brush.Color := BrushColor;
|
||
|
Brush.Style := BrushStyle;
|
||
|
Pen.Color := PenColor;
|
||
|
Pen.Style := PenStyle;
|
||
|
end;
|
||
|
end;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
{----------------TfrxHtBodyBlock.Create}
|
||
|
|
||
|
constructor TfrxHtBodyBlock.Create(Parent: TfrxHtCellBasic; Attributes: TfrxHtAttributeList; Prop: TfrxHTProperties);
|
||
|
var
|
||
|
PRec: PtPositionRec;
|
||
|
Image: ThtString;
|
||
|
Val: TColor;
|
||
|
begin
|
||
|
inherited Create(Parent,Attributes,Prop);
|
||
|
FPositioning := PosStatic; {7.28}
|
||
|
Prop.GetBackgroundPos(0, 0, PRec);
|
||
|
if Prop.GetBackgroundImage(Image) and (Image <> '') then
|
||
|
Document.SetBackgroundImage(Image, PRec);
|
||
|
Val := Prop.GetBackgroundColor;
|
||
|
if Val <> clNone then
|
||
|
Document.SetBackGround(Val or PalRelative);
|
||
|
end;
|
||
|
|
||
|
|
||
|
{----------------TfrxHtBodyBlock.DrawLogic}
|
||
|
|
||
|
function TfrxHtBodyBlock.DrawLogic1(Canvas: TCanvas; X, Y, XRef, YRef, AWidth, AHeight, BlHt: Integer; IMgr: TfrxHtIndentManager;
|
||
|
var MaxWidth, Curs: Integer; ARemainHeight: Integer): Integer;
|
||
|
var
|
||
|
ScrollWidth: Integer;
|
||
|
Lindex, RIndex, AutoCount: Integer;
|
||
|
SaveID: TObject;
|
||
|
ClientContentBot: Integer;
|
||
|
begin
|
||
|
YDraw := Y;
|
||
|
StartCurs := Curs;
|
||
|
frxHTMLStyleUn.ConvMargArray(MargArrayO, AWidth, AHeight, EmSize, ExSize, BorderWidth, AutoCount, MargArray);
|
||
|
if IsAuto(MargArray[MarginLeft]) then MargArray[MarginLeft] := 0;
|
||
|
if IsAuto(MargArray[MarginRight]) then MargArray[MarginRight] := 0;
|
||
|
ApplyBoxSettings(MargArray);
|
||
|
|
||
|
X := MargArray[MarginLeft] + MargArray[PaddingLeft] + MargArray[BorderLeftWidth];
|
||
|
ContentWidth := IMgr.Width - (X + MargArray[MarginRight] + MargArray[PaddingRight] + MargArray[BorderRightWidth]);
|
||
|
|
||
|
DrawTop := MargArray[MarginTop];
|
||
|
|
||
|
MyCell.IMgr := IMgr;
|
||
|
|
||
|
SaveID := IMgr.CurrentID;
|
||
|
Imgr.CurrentID := Self;
|
||
|
LIndex := IMgr.SetLeftIndent(X, Y);
|
||
|
RIndex := IMgr.SetRightIndent(X + ContentWidth, Y);
|
||
|
|
||
|
ContentTop := Y + MargArray[MarginTop] + MargArray[PaddingTop] + MargArray[BorderTopWidth];
|
||
|
MyCell.DoLogicX(Canvas, X, ContentTop, 0, 0, ContentWidth,
|
||
|
AHeight - MargArray[MarginTop] - MargArray[MarginBottom], BlHt, ScrollWidth, Curs, ARemainHeight);
|
||
|
|
||
|
Len := Curs - StartCurs;
|
||
|
|
||
|
ClientContentBot := Max(ContentTop, MyCell.tcContentBot);
|
||
|
ContentBot := ClientContentBot + MargArray[PaddingBottom] + MargArray[BorderBottomWidth] + MargArray[MarginBottom];
|
||
|
DrawBot := Max(ClientContentBot, MyCell.tcDrawBot) + MargArray[PaddingBottom] + MargArray[BorderBottomWidth];
|
||
|
|
||
|
MyCell.tcDrawTop := 0;
|
||
|
MyCell.tcContentBot := 999000;
|
||
|
|
||
|
Result := DrawBot + MargArray[MarginBottom] - Y;
|
||
|
SectionHeight := Result;
|
||
|
IMgr.FreeLeftIndentRec(LIndex);
|
||
|
IMgr.FreeRightIndentRec(RIndex);
|
||
|
DrawHeight := IMgr.ImageBottom - Y; {in case image overhangs}
|
||
|
Imgr.CurrentID := SaveID;
|
||
|
if DrawHeight < SectionHeight then
|
||
|
DrawHeight := SectionHeight;
|
||
|
MaxWidth := Max(IMgr.Width, Max(ScrollWidth, ContentWidth) + MargArray[MarginLeft] + MargArray[MarginRight]);
|
||
|
if DrawList.Count = 0 then
|
||
|
DrawSort;
|
||
|
end;
|
||
|
|
||
|
{----------------TfrxHtBodyBlock.Draw}
|
||
|
|
||
|
function TfrxHtBodyBlock.Draw1(Canvas: TCanvas; const ARect: TRect; IMgr: TfrxHtIndentManager; X, XRef, YRef: Integer): Integer;
|
||
|
var
|
||
|
SaveID: TObject;
|
||
|
Y: Integer;
|
||
|
begin
|
||
|
Y := YDraw;
|
||
|
Result := Y + SectionHeight;
|
||
|
|
||
|
X := IMgr.LfEdge + MargArray[MarginLeft] + MargArray[BorderLeftWidth] + MargArray[PaddingLeft];
|
||
|
SaveID := IMgr.CurrentID;
|
||
|
Imgr.CurrentID := Self;
|
||
|
DrawTheList(Canvas, ARect, ContentWidth, X, IMgr.LfEdge, 0);
|
||
|
Imgr.CurrentID := SaveID;
|
||
|
end;
|
||
|
|
||
|
{ TfrxHtDocument }
|
||
|
|
||
|
//-- BG ---------------------------------------------------------- 04.03.2011 --
|
||
|
// moving from TfrxHtIDObjectList to TfrxHtDocument removed field OwnerList from TfrxHtIDObjectList
|
||
|
function TfrxHtDocument.AddChPosObjectToIDNameList(const S: ThtString; Pos: Integer): Integer;
|
||
|
begin
|
||
|
Result := IDNameList.AddObject(S, TfrxHtChPosObj.Create(Self, Pos));
|
||
|
end;
|
||
|
|
||
|
constructor TfrxHtDocument.Create(Owner: TfrxHtmlViewerBase);
|
||
|
begin
|
||
|
FDocument := Self;
|
||
|
inherited Create(nil);
|
||
|
FPropStack := TfrxHtmlPropStack.Create;
|
||
|
TheOwner := Owner;
|
||
|
IDNameList := TfrxHtIDObjectList.Create; //(Self);
|
||
|
MissingImages := ThtStringList.Create;
|
||
|
MissingImages.Sorted := False;
|
||
|
LinkList := TfrxHtLinkList.Create;
|
||
|
Styles := TfrxHtmlStyleList.Create(Self);
|
||
|
DrawList := TfrxHtDrawList.Create;
|
||
|
PositionList := TfrxHtSectionBaseList.Create(False);
|
||
|
InLineList := TInlineList.Create(Self);
|
||
|
ScaleX := 1.0;
|
||
|
ScaleY := 1.0;
|
||
|
end;
|
||
|
|
||
|
//------------------------------------------------------------------------------
|
||
|
constructor TfrxHtDocument.CreateCopy(T: TfrxHtDocument);
|
||
|
begin
|
||
|
PrintTableBackground := T.PrintTableBackground;
|
||
|
PrintBackground := T.PrintBackground;
|
||
|
ImageCache := T.ImageCache; {same list}
|
||
|
InlineList := T.InlineList; {same list}
|
||
|
IsCopy := True;
|
||
|
System.Move(T.ShowImages, ShowImages, PtrSub(@Background, @ShowImages) + Sizeof(Integer));
|
||
|
PreFontName := T.PreFontName;
|
||
|
MissingImages := ThtStringList.Create;
|
||
|
DrawList := TfrxHtDrawList.Create;
|
||
|
FDocument := Self;
|
||
|
inherited CreateCopy(nil, T);
|
||
|
ScaleX := 1.0;
|
||
|
ScaleY := 1.0;
|
||
|
end;
|
||
|
|
||
|
destructor TfrxHtDocument.Destroy;
|
||
|
begin
|
||
|
inherited Destroy; // Yunqa.de: Destroy calls Clear, so do this first.
|
||
|
IDNameList.Free;
|
||
|
MissingImages.Free;
|
||
|
LinkList.Free;
|
||
|
Styles.Free;
|
||
|
DrawList.Free;
|
||
|
PositionList.Free;
|
||
|
if not IsCopy then
|
||
|
InlineList.Free;
|
||
|
FPropStack.Free;
|
||
|
end;
|
||
|
|
||
|
//-- BG ---------------------------------------------------------- 14.02.2016 --
|
||
|
function TfrxHtDocument.GetViewPort: TRect;
|
||
|
begin
|
||
|
Result := Bounds(0, 0, TheOwner.Width, TheOwner.Height);
|
||
|
end;
|
||
|
|
||
|
procedure TfrxHtDocument.SetYOffset(Y: Integer);
|
||
|
begin
|
||
|
YOff := Y;
|
||
|
YOffChange := True;
|
||
|
end;
|
||
|
|
||
|
procedure TfrxHtDocument.Clear;
|
||
|
begin
|
||
|
if not IsCopy then
|
||
|
begin
|
||
|
IDNameList.Clear;
|
||
|
PositionList.Clear;
|
||
|
TInlineList(InlineList).Clear;
|
||
|
end;
|
||
|
BackgroundImage := nil;
|
||
|
BackgroundImageName := '';
|
||
|
BackgroundImageLoaded := False;
|
||
|
MissingImages.Clear;
|
||
|
if Assigned(LinkList) then
|
||
|
LinkList.Clear;
|
||
|
if not IsCopy then
|
||
|
Styles.Clear;
|
||
|
inherited Clear;
|
||
|
end;
|
||
|
|
||
|
//------------------------------------------------------------------------------
|
||
|
function TfrxHtDocument.DoLogic(Canvas: TCanvas; Y: Integer; Width, AHeight, BlHt: Integer;
|
||
|
var ScrollWidth, Curs: Integer; ARemainHeight: Integer): Integer;
|
||
|
begin
|
||
|
Inc(CycleNumber);
|
||
|
TableNestLevel := 0;
|
||
|
InLogic2 := False;
|
||
|
SetTextJustification(Canvas.Handle, 0, 0);
|
||
|
TInlineList(InlineList).NeedsConverting := True;
|
||
|
|
||
|
Result := inherited DoLogic(Canvas, Y, Width, AHeight, BlHt, ScrollWidth, Curs, ARemainHeight);
|
||
|
|
||
|
if not IsCopy and (PositionList.Count = 0) then
|
||
|
begin
|
||
|
AddSectionsToList;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
//-- BG ---------------------------------------------------------- 11.09.2010 --
|
||
|
procedure TfrxHtDocument.AddSectionsToPositionList(Sections: TfrxHtSectionBase);
|
||
|
begin
|
||
|
inherited;
|
||
|
PositionList.Add(Sections);
|
||
|
end;
|
||
|
|
||
|
//------------------------------------------------------------------------------
|
||
|
function TfrxHtDocument.Draw(Canvas: TCanvas; ARect: TRect; ClipWidth, X: Integer;
|
||
|
Y, XRef, YRef: Integer): Integer;
|
||
|
var
|
||
|
OldPal: HPalette;
|
||
|
begin
|
||
|
PageBottom := ARect.Bottom + YOff;
|
||
|
PageShortened := False;
|
||
|
FirstPageItem := True;
|
||
|
TableNestLevel := 0;
|
||
|
SkipDraw := False;
|
||
|
|
||
|
if (ColorBits <= 8) then
|
||
|
begin
|
||
|
OldPal := SelectPalette(Canvas.Handle, ThePalette, True);
|
||
|
RealizePalette(Canvas.Handle);
|
||
|
end
|
||
|
else
|
||
|
OldPal := 0;
|
||
|
DrawList.Clear;
|
||
|
try
|
||
|
Result := inherited Draw(Canvas, ARect, ClipWidth, X, Y, XRef, YRef);
|
||
|
if DrawList.Count > 0 then
|
||
|
begin
|
||
|
DrawList.DrawImages;
|
||
|
DrawList.Clear;
|
||
|
Printed := True;
|
||
|
end;
|
||
|
finally
|
||
|
if OldPal <> 0 then
|
||
|
SelectPalette(Canvas.Handle, OldPal, True);
|
||
|
end;
|
||
|
if YOffChange or XOffChange then
|
||
|
begin
|
||
|
XOffChange := False;
|
||
|
YOffChange := False;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
procedure TfrxHtDocument.SetFonts(const Name, PreName: ThtString; ASize: Double;
|
||
|
AColor, AHotSpot, AVisitedColor, AActiveColor, ABackground: TColor; LnksActive, LinkUnderLine: Boolean;
|
||
|
ACodePage: TBuffCodePage; ACharSet: TFontCharSet; MarginHeight, MarginWidth: Integer);
|
||
|
begin
|
||
|
Styles.Initialize(Name, PreName, ASize, AColor, AHotspot, AVisitedColor,
|
||
|
AActiveColor, LinkUnderLine, ACodePage, ACharSet, MarginHeight, MarginWidth);
|
||
|
InitializeFontSizes(ASize);
|
||
|
PreFontName := htStringToString(PreName);
|
||
|
HotSpotColor := AHotSpot;
|
||
|
LinkVisitedColor := AVisitedColor;
|
||
|
LinkActiveColor := AActiveColor;
|
||
|
LinksActive := LnksActive;
|
||
|
SetBackground(ABackground);
|
||
|
end;
|
||
|
|
||
|
procedure TfrxHtDocument.SetBackground(ABackground: TColor);
|
||
|
begin
|
||
|
Background := ABackground;
|
||
|
if Assigned(OnBackGroundChange) then
|
||
|
OnBackgroundChange(Self);
|
||
|
end;
|
||
|
|
||
|
procedure TfrxHtDocument.SetBackgroundImage(const Name: ThtString; const APrec: PtPositionRec);
|
||
|
begin
|
||
|
BackgroundImage := nil;
|
||
|
BackgroundImageName := Name;
|
||
|
BackgroundImageLoaded := False;
|
||
|
BackgroundImagePosition := APrec;
|
||
|
end;
|
||
|
|
||
|
//------------------------------------------------------------------------------
|
||
|
function TfrxHtDocument.GetTheImage(const BMName: ThtString; var Transparent: ThtImageTransparency; out FromCache, Delay: Boolean): TfrxHtImage;
|
||
|
{Transparent may be set to itrNone or itrLLCorner on entry but may discover it's itrIntrinsic here}
|
||
|
|
||
|
procedure GetTheStream;
|
||
|
{Note: streams gotten by OnImageRequest are on "loan". We do not destroy them}
|
||
|
var
|
||
|
Stream: TStream;
|
||
|
begin
|
||
|
if Assigned(GetImage) then
|
||
|
begin {the OnImageRequest}
|
||
|
Stream := nil;
|
||
|
GetImage(TheOwner, BMName, Stream);
|
||
|
if Stream = WaitStream then
|
||
|
Delay := True
|
||
|
else if Stream = ErrorStream then
|
||
|
Result := nil
|
||
|
else if Stream <> nil then
|
||
|
begin
|
||
|
try
|
||
|
Result := LoadImageFromStream(Stream, Transparent);
|
||
|
finally
|
||
|
if Assigned(GottenImage) then
|
||
|
GottenImage(TheOwner, BMName, Stream);
|
||
|
end;
|
||
|
end;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
procedure GetTheBase64(Name: ThtString);
|
||
|
var
|
||
|
I: Integer;
|
||
|
Stream: TStream;
|
||
|
S: String;
|
||
|
AnsiS: AnsiString;
|
||
|
begin
|
||
|
I := Pos(';base64,', Name);
|
||
|
if I >= 11 then
|
||
|
begin
|
||
|
// Firefox 11 saves multiline inline images by writing %0A for the linefeeds.
|
||
|
// BTW: Internet Explorer 9 shows but does not save inline images at all.
|
||
|
// Using StringReplace() here is a quick and dirty hack.
|
||
|
// Better decode %encoded attribute values while reading the attributes.
|
||
|
S := StringReplace(htStringToString(Name), '%0A', #$0A, [rfReplaceAll]);
|
||
|
AnsiS := AnsiString(Trim(Copy(S, I + 8, MaxInt)));
|
||
|
Stream := TMemoryStream.Create;
|
||
|
try
|
||
|
AnsiS := Base64Decode(AnsiS);
|
||
|
Stream.Write(AnsiS[1], Length(AnsiS));
|
||
|
Stream.Position := 0;
|
||
|
Result := LoadImageFromStream(Stream, Transparent);
|
||
|
Result.IsInternal := True;
|
||
|
finally
|
||
|
Stream.Free;
|
||
|
end;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
procedure GetTheFile(Name: ThtString);
|
||
|
var
|
||
|
Stream: TStream;
|
||
|
Scheme, Specific, ResType: ThtString;
|
||
|
begin
|
||
|
Name := TheOwner.HtmlExpandFilename(Name);
|
||
|
SplitScheme(Name, Scheme, Specific);
|
||
|
if Scheme = 'res' then
|
||
|
begin
|
||
|
Specific := HTMLToRes(Name, ResType);
|
||
|
Stream := TResourceStream.Create(HInstance, htStringToString(Specific), PChar({$ifdef LCL}string(ResType){$else}String(ResType){$endif}) );
|
||
|
end
|
||
|
else if FileExists(Name) then
|
||
|
Stream := TFileStream.Create( htStringToString(Name), fmOpenRead or fmShareDenyWrite)
|
||
|
else
|
||
|
Stream := nil;
|
||
|
|
||
|
if Stream <> nil then
|
||
|
try
|
||
|
Result := LoadImageFromStream(Stream, Transparent);
|
||
|
finally
|
||
|
Stream.Free;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
procedure GetTheURL(Name: String);
|
||
|
var
|
||
|
Stream: TStream;
|
||
|
Scheme, Specific: ThtString;
|
||
|
LProtocol: TfrxCustomDatalinkProtocolClass;
|
||
|
begin
|
||
|
if Length(Name) = 0 then Exit;
|
||
|
Name := TheOwner.HtmlExpandFilename(Name);
|
||
|
SplitScheme(Name, Scheme, Specific);
|
||
|
LProtocol := frxDataProtocols.GetProtocol(Name);
|
||
|
if not Assigned(LProtocol) then Exit;
|
||
|
Stream := TMemoryStream.Create;
|
||
|
try
|
||
|
if LProtocol.LoadBy(Name, Stream) then
|
||
|
begin
|
||
|
Stream.Position := 0;
|
||
|
Result := LoadImageFromStream(Stream, Transparent);
|
||
|
end;
|
||
|
except
|
||
|
Result := nil;
|
||
|
end;
|
||
|
Stream.Free;
|
||
|
end;
|
||
|
|
||
|
var
|
||
|
UName, Name: ThtString;
|
||
|
I: Integer;
|
||
|
bIsEmbedded: Boolean;
|
||
|
begin
|
||
|
Result := nil;
|
||
|
Delay := False;
|
||
|
FromCache := False;
|
||
|
if BMName <> '' then
|
||
|
begin
|
||
|
Name := htTrim(BMName);
|
||
|
//UName := htUpperCase(Name);
|
||
|
UName := Name;
|
||
|
bIsEmbedded := (Copy(Name, 1, 11) = 'data:image/');
|
||
|
if bIsEmbedded then
|
||
|
UName := String(MD5String(AnsiString(UName)));
|
||
|
if ImageCache.IsFound(UName, I) then // handle the case where the image is already loaded
|
||
|
begin
|
||
|
Result := ImageCache.GetImage(I);
|
||
|
FromCache := True;
|
||
|
end
|
||
|
else
|
||
|
begin
|
||
|
{The image is not loaded yet, need to get it}
|
||
|
if bIsEmbedded then
|
||
|
GetTheBase64(Name)
|
||
|
else
|
||
|
begin
|
||
|
if (Result = nil) and not Delay then
|
||
|
GetTheStream;
|
||
|
if (Result = nil) and not Delay then
|
||
|
GetTheFile(BMName);
|
||
|
if (Result = nil) and not Delay then
|
||
|
GetTheURL(BMName);
|
||
|
end;
|
||
|
|
||
|
if Result <> nil then {put in Image List for use later also}
|
||
|
ImageCache.AddObject(UName, Result); {put new image in list}
|
||
|
end;
|
||
|
end;
|
||
|
if Assigned(Result) then
|
||
|
Result.AddRef;
|
||
|
end;
|
||
|
|
||
|
//------------------------------------------------------------------------------
|
||
|
function TfrxHtDocument.FindSectionAtPosition(Pos: Integer; out TopPos, Index: Integer): TfrxHtSectionBase;
|
||
|
var
|
||
|
I: Integer;
|
||
|
begin
|
||
|
for I := PositionList.Count - 1 downto 0 do
|
||
|
begin
|
||
|
Result := PositionList[I];
|
||
|
if Result.YPosition <= Pos then
|
||
|
begin
|
||
|
TopPos := Result.YPosition;
|
||
|
Index := I;
|
||
|
Exit;
|
||
|
end;
|
||
|
end;
|
||
|
Result := nil;
|
||
|
end;
|
||
|
|
||
|
procedure TfrxHtDocument.GetBackgroundImage;
|
||
|
var
|
||
|
Dummy1: ThtImageTransparency;
|
||
|
FromCache, Delay: Boolean;
|
||
|
Rslt: ThtString;
|
||
|
I: Integer;
|
||
|
UName: ThtString;
|
||
|
begin
|
||
|
UName := htTrim(BackgroundImageName);
|
||
|
if ShowImages and (UName <> '') then
|
||
|
if BackgroundImage = nil then
|
||
|
begin
|
||
|
if BackgroundImageLoaded then
|
||
|
begin
|
||
|
I := ImageCache.IndexOf(UName); {first see if the bitmap is already loaded}
|
||
|
if I >= 0 then
|
||
|
BackgroundImage := ImageCache.GetImage(I);
|
||
|
end
|
||
|
else
|
||
|
begin
|
||
|
Dummy1 := itrNone;
|
||
|
if not Assigned(GetImage) then
|
||
|
BackgroundImageName := TheOwner.HtmlExpandFilename(BackgroundImageName)
|
||
|
else if Assigned(OnExpandName) then
|
||
|
begin
|
||
|
OnExpandName(TheOwner, BackgroundImageName, Rslt);
|
||
|
BackgroundImageName := Rslt;
|
||
|
end;
|
||
|
BackgroundImage := GetTheImage(BackgroundImageName, Dummy1, FromCache, Delay); {might be Nil}
|
||
|
if Delay then
|
||
|
MissingImages.AddObject(htTrim(BackgroundImageName), Self);
|
||
|
BackgroundImageLoaded := True;
|
||
|
end;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
//-- BG ---------------------------------------------------------- 14.02.2016 --
|
||
|
procedure TfrxHtDocument.SetPageArea(const Value: TRect);
|
||
|
begin
|
||
|
FPageArea := Value;
|
||
|
end;
|
||
|
|
||
|
//-- BG ---------------------------------------------------------- 16.07.2017 --
|
||
|
procedure TfrxHtDocument.SetPrinted(const Value: Boolean);
|
||
|
begin
|
||
|
FPrinted := Value;
|
||
|
end;
|
||
|
|
||
|
//------------------------------------------------------------------------------
|
||
|
function TfrxHtDocument.FindDocPos(SourcePos: Integer; Prev: Boolean): Integer;
|
||
|
begin
|
||
|
Result := inherited FindDocPos(SourcePos, Prev);
|
||
|
if Result < 0 then {if not found return 1 past last ThtChar}
|
||
|
Result := Len;
|
||
|
end;
|
||
|
|
||
|
procedure TfrxHtDocument.ProcessInlines(SIndex: Integer; Prop: TfrxHTProperties; Start: Boolean);
|
||
|
{called when an inline property is found to specify a border}
|
||
|
var
|
||
|
I, EmSize, ExSize: Integer;
|
||
|
Result: ThtInlineRec;
|
||
|
MargArrayO: ThtVMarginArray;
|
||
|
Dummy1: Integer;
|
||
|
begin
|
||
|
with TInlineList(InlineList) do
|
||
|
begin
|
||
|
if Start then
|
||
|
begin {this is for border start}
|
||
|
Result := ThtInlineRec.Create;
|
||
|
Add(Result);
|
||
|
with Result do
|
||
|
begin
|
||
|
StartBDoc := SIndex; {Source index for border start}
|
||
|
IDB := Prop.ID; {property ID}
|
||
|
EndB := 999999; {end isn't known yet}
|
||
|
Prop.GetVMarginArray(MargArrayO);
|
||
|
EmSize := Prop.EmSize;
|
||
|
ExSize := Prop.ExSize;
|
||
|
ConvMargArray(MargArrayO, 200, 200, EmSize, ExSize, 0{4}, Dummy1, MargArray);
|
||
|
end;
|
||
|
end
|
||
|
else {this call has end information}
|
||
|
for I := Count - 1 downto 0 do {the record we want is probably the last one}
|
||
|
begin
|
||
|
Result := Items[I];
|
||
|
if Prop.ID = Result.IDB then {check the ID to make sure}
|
||
|
begin
|
||
|
Result.EndBDoc := SIndex; {the source position of the border end}
|
||
|
Break;
|
||
|
end;
|
||
|
end;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
{----------------TInlineList.Create}
|
||
|
|
||
|
constructor TInlineList.Create(AnOwner: TfrxHtDocument);
|
||
|
begin
|
||
|
inherited Create;
|
||
|
Owner := AnOwner;
|
||
|
NeedsConverting := True;
|
||
|
end;
|
||
|
|
||
|
procedure TInlineList.Clear;
|
||
|
begin
|
||
|
inherited Clear;
|
||
|
NeedsConverting := True;
|
||
|
end;
|
||
|
|
||
|
procedure TInlineList.AdjustValues;
|
||
|
{convert all the list data from source ThtChar positions to display ThtChar positions}
|
||
|
var
|
||
|
I: Integer;
|
||
|
begin
|
||
|
for I := 0 to Count - 1 do
|
||
|
with Items[I] do
|
||
|
begin
|
||
|
StartB := Owner.FindDocPos(StartBDoc, False);
|
||
|
EndB := Owner.FindDocPos(EndBDoc, False);
|
||
|
if StartB = EndB then
|
||
|
Dec(StartB); {this takes care of images, form controls}
|
||
|
end;
|
||
|
NeedsConverting := False;
|
||
|
end;
|
||
|
|
||
|
function TInlineList.GetStartB(I: Integer): Integer;
|
||
|
begin
|
||
|
if NeedsConverting then
|
||
|
AdjustValues;
|
||
|
if (I < Count) and (I >= 0) then
|
||
|
Result := Items[I].StartB
|
||
|
else
|
||
|
Result := 99999999;
|
||
|
end;
|
||
|
|
||
|
//-- BG ---------------------------------------------------------- 06.10.2016 --
|
||
|
function TInlineList.Get(Index: Integer): ThtInlineRec;
|
||
|
begin
|
||
|
Result := inherited Get(Index);
|
||
|
end;
|
||
|
|
||
|
function TInlineList.GetEndB(I: Integer): Integer;
|
||
|
begin
|
||
|
if NeedsConverting then
|
||
|
AdjustValues;
|
||
|
if (I < Count) and (I >= 0) then
|
||
|
Result := Items[I].EndB
|
||
|
else
|
||
|
Result := 99999999;
|
||
|
end;
|
||
|
|
||
|
{ TfrxHtfrcHtCellObjBase }
|
||
|
|
||
|
//-- BG ---------------------------------------------------------- 19.02.2013 --
|
||
|
procedure TfrxHtfrcHtCellObjBase.AssignTo(Destin: TfrxHtfrcHtCellObjBase);
|
||
|
begin
|
||
|
Move(FColSpan, Destin.FColSpan, PtrSub(@FSpecHt, @FColSpan) + sizeof(FSpecHt) );
|
||
|
end;
|
||
|
|
||
|
{ TfrxHtDummyCellObj }
|
||
|
|
||
|
//-- BG ---------------------------------------------------------- 19.02.2013 --
|
||
|
function TfrxHtDummyCellObj.Clone(Parent: TfrxHtBlock): TfrxHtfrcHtCellObjBase;
|
||
|
begin
|
||
|
Result := TfrxHtDummyCellObj.Create(RowSpan);
|
||
|
AssignTo(Result);
|
||
|
end;
|
||
|
|
||
|
//-- BG ---------------------------------------------------------- 19.02.2013 --
|
||
|
constructor TfrxHtDummyCellObj.Create(RSpan: Integer);
|
||
|
begin
|
||
|
inherited Create;
|
||
|
FColSpan := 0;
|
||
|
FRowSpan := RSpan;
|
||
|
end;
|
||
|
|
||
|
//-- BG ---------------------------------------------------------- 19.02.2013 --
|
||
|
procedure TfrxHtDummyCellObj.Draw(Canvas: TCanvas; const ARect: TRect; X, Y, CellSpacingHorz, CellSpacingVert: Integer; Border: Boolean; Light,
|
||
|
Dark: TColor);
|
||
|
begin
|
||
|
//abstract: inherited Draw(Canvas,ARect,X,Y,CellSpacing,Border,Light,Dark);
|
||
|
end;
|
||
|
|
||
|
//-- BG ---------------------------------------------------------- 19.02.2013 --
|
||
|
procedure TfrxHtDummyCellObj.DrawLogic2(Canvas: TCanvas; Y, CellSpacingHorz,CellSpacingVert: Integer; var Curs: Integer);
|
||
|
begin
|
||
|
//abstract: inherited DrawLogic2(Canvas,Y,CellSpacing,Curs);
|
||
|
end;
|
||
|
|
||
|
//-- BG ---------------------------------------------------------- 19.02.2013 --
|
||
|
function TfrxHtDummyCellObj.GetCell: TfrxHtCellObjCell;
|
||
|
begin
|
||
|
Result := nil;
|
||
|
end;
|
||
|
|
||
|
{ TfrxHtCellObj }
|
||
|
|
||
|
//-- BG ---------------------------------------------------------- 19.02.2013 --
|
||
|
procedure TfrxHtCellObj.AssignTo(Destin: TfrxHtfrcHtCellObjBase);
|
||
|
var
|
||
|
CellObj: TfrxHtCellObj absolute Destin;
|
||
|
begin
|
||
|
inherited AssignTo(Destin);
|
||
|
if Destin is TfrxHtCellObj then
|
||
|
begin
|
||
|
Move(FWd, CellObj.FWd, PtrSub(@FCell, @FWd));
|
||
|
|
||
|
if CellObj.Cell.Document.PrintTableBackground then
|
||
|
begin
|
||
|
CellObj.Cell.BkGnd := Cell.BkGnd;
|
||
|
CellObj.Cell.BkColor := Cell.BkColor;
|
||
|
if Assigned(BGImage) then
|
||
|
// TODO: BG, 26.08.2013: is this correct?
|
||
|
CellObj.BGImage := TfrxFrHtImageObj.CreateCopy(CellObj.Cell, BGImage);
|
||
|
end
|
||
|
else
|
||
|
CellObj.Cell.BkGnd := False;
|
||
|
CellObj.MargArrayO := MargArrayO;
|
||
|
CellObj.MargArray := MargArray;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
//-- BG ---------------------------------------------------------- 19.02.2013 --
|
||
|
function TfrxHtCellObj.Clone(Parent: TfrxHtBlock): TfrxHtfrcHtCellObjBase;
|
||
|
begin
|
||
|
Result := TfrxHtCellObj.CreateCopy(Parent, Self);
|
||
|
end;
|
||
|
|
||
|
constructor TfrxHtCellObj.Create(Parent: TfrxHtTableBlock; AVAlign: ThtAlignmentStyle; Attr: TfrxHtAttributeList; Prop: TfrxHTProperties);
|
||
|
{Note: on entry Attr and Prop may be Nil when dummy cells are being created}
|
||
|
var
|
||
|
I, AutoCount: Integer;
|
||
|
Color: TColor;
|
||
|
BackgroundImage: ThtString;
|
||
|
Algn: ThtAlignmentStyle;
|
||
|
begin
|
||
|
inherited Create;
|
||
|
FCell := TfrxHtCellObjCell.Create(Parent);
|
||
|
if Assigned(Prop) then
|
||
|
Cell.Title := Prop.PropTitle;
|
||
|
ColSpan := 1;
|
||
|
RowSpan := 1;
|
||
|
VAlign := AVAlign;
|
||
|
if Assigned(Attr) then
|
||
|
for I := 0 to Attr.Count - 1 do
|
||
|
with Attr[I] do
|
||
|
case Which of
|
||
|
ColSpanSy:
|
||
|
if Value > 1 then
|
||
|
ColSpan := Value;
|
||
|
|
||
|
RowSpanSy:
|
||
|
if Value > 1 then
|
||
|
RowSpan := Value;
|
||
|
|
||
|
WidthSy:
|
||
|
if Value >= 0 then
|
||
|
FSpecWd := ToSpecWidth(Value, Name);
|
||
|
|
||
|
HeightSy:
|
||
|
if Value >= 0 then
|
||
|
FSpecHt := ToSpecWidth(Value, Name);
|
||
|
|
||
|
BGColorSy:
|
||
|
Cell.BkGnd := TryStrToColor(Name, False, Cell.BkColor);
|
||
|
|
||
|
BackgroundSy:
|
||
|
BackgroundImage := Name;
|
||
|
|
||
|
HRefSy:
|
||
|
Cell.Url := Name;
|
||
|
|
||
|
TargetSy:
|
||
|
Cell.Target := Name;
|
||
|
|
||
|
end;
|
||
|
|
||
|
if Assigned(Prop) then
|
||
|
begin {Caption does not have Prop}
|
||
|
if Prop.GetVertAlign(Algn) and (Algn in [Atop, AMiddle, ABottom]) then
|
||
|
Valign := Algn;
|
||
|
Prop.GetVMarginArray(MargArrayO);
|
||
|
EmSize := Prop.EmSize;
|
||
|
ExSize := Prop.ExSize;
|
||
|
ConvMargArray(MargArrayO, 100, 0, EmSize, ExSize, 0, AutoCount, MargArray);
|
||
|
if VarIsStr(MargArrayO[piWidth]) and (MargArray[piWidth] >= 0) then
|
||
|
FSpecWd := ToSpecWidth(MargArray[piWidth], MargArrayO[piWidth]);
|
||
|
if VarIsStr(MargArrayO[piHeight]) and (MargArray[piHeight] >= 0) then
|
||
|
FSpecHt := ToSpecWidth(MargArray[piHeight], MargArrayO[piHeight]);
|
||
|
|
||
|
Color := Prop.GetBackgroundColor;
|
||
|
if Color <> clNone then
|
||
|
begin
|
||
|
Cell.BkGnd := True;
|
||
|
Cell.BkColor := Color;
|
||
|
end;
|
||
|
Prop.GetBackgroundImage(BackgroundImage); {'none' will change ThtString to empty}
|
||
|
if BackgroundImage <> '' then
|
||
|
begin
|
||
|
BGImage := TfrxFrHtImageObj.SimpleCreate(Cell, BackgroundImage);
|
||
|
Prop.GetBackgroundPos(EmSize, ExSize, FPRec);
|
||
|
end;
|
||
|
|
||
|
{In the following, Padding widths in percent aren't accepted}
|
||
|
ConvMargArrayForCellPadding(MargArrayO, EmSize, ExSize, MargArray);
|
||
|
FPad.Top := MargArray[PaddingTop];
|
||
|
FPad.Right := MargArray[PaddingRight];
|
||
|
FPad.Bottom := MargArray[PaddingBottom];
|
||
|
FPad.Left := MargArray[PaddingLeft];
|
||
|
|
||
|
HasBorderStyle := False;
|
||
|
if ThtBorderStyle(MargArray[BorderTopStyle]) <> bssNone then
|
||
|
begin
|
||
|
HasBorderStyle := True;
|
||
|
FBrd.Top := MargArray[BorderTopWidth];
|
||
|
end;
|
||
|
if ThtBorderStyle(MargArray[BorderRightStyle]) <> bssNone then
|
||
|
begin
|
||
|
HasBorderStyle := True;
|
||
|
FBrd.Right := MargArray[BorderRightWidth];
|
||
|
end;
|
||
|
if ThtBorderStyle(MargArray[BorderBottomStyle]) <> bssNone then
|
||
|
begin
|
||
|
HasBorderStyle := True;
|
||
|
FBrd.Bottom := MargArray[BorderBottomWidth];
|
||
|
end;
|
||
|
if ThtBorderStyle(MargArray[BorderLeftStyle]) <> bssNone then
|
||
|
begin
|
||
|
HasBorderStyle := True;
|
||
|
FBrd.Left := MargArray[BorderLeftWidth];
|
||
|
end;
|
||
|
|
||
|
Prop.GetPageBreaks(BreakBefore, BreakAfter, KeepIntact);
|
||
|
ShowEmptyCells := Prop.ShowEmptyCells;
|
||
|
HideOverflow := Prop.IsOverflowHidden;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
constructor TfrxHtCellObj.CreateCopy(Parent: TfrxHtBlock; T: TfrxHtCellObj);
|
||
|
begin
|
||
|
inherited Create;
|
||
|
FCell := TfrxHtCellObjCell.CreateCopy(Parent, T.Cell);
|
||
|
T.AssignTo(Self);
|
||
|
end;
|
||
|
|
||
|
destructor TfrxHtCellObj.Destroy;
|
||
|
begin
|
||
|
Cell.Free;
|
||
|
BGImage.Free;
|
||
|
TiledImage.Free;
|
||
|
inherited Destroy;
|
||
|
end;
|
||
|
|
||
|
//-- BG ---------------------------------------------------------- 08.01.2012 --
|
||
|
function TfrxHtCellObj.GetBorderBottom: Integer;
|
||
|
begin
|
||
|
Result := FBrd.Bottom;
|
||
|
end;
|
||
|
|
||
|
//-- BG ---------------------------------------------------------- 08.01.2012 --
|
||
|
function TfrxHtCellObj.GetBorderLeft: Integer;
|
||
|
begin
|
||
|
Result := FBrd.Left;
|
||
|
end;
|
||
|
|
||
|
//-- BG ---------------------------------------------------------- 08.01.2012 --
|
||
|
function TfrxHtCellObj.GetBorderRight: Integer;
|
||
|
begin
|
||
|
Result := FBrd.Right;
|
||
|
end;
|
||
|
|
||
|
//-- BG ---------------------------------------------------------- 08.01.2012 --
|
||
|
function TfrxHtCellObj.GetBorderTop: Integer;
|
||
|
begin
|
||
|
Result := FBrd.Top;
|
||
|
end;
|
||
|
|
||
|
//-- BG ---------------------------------------------------------- 19.02.2013 --
|
||
|
function TfrxHtCellObj.GetCell: TfrxHtCellObjCell;
|
||
|
begin
|
||
|
Result := FCell;
|
||
|
end;
|
||
|
|
||
|
//-- BG ---------------------------------------------------------- 08.01.2012 --
|
||
|
function TfrxHtCellObj.GetPaddingBottom: Integer;
|
||
|
begin
|
||
|
Result := FPad.Bottom;
|
||
|
end;
|
||
|
|
||
|
//-- BG ---------------------------------------------------------- 08.01.2012 --
|
||
|
function TfrxHtCellObj.GetPaddingLeft: Integer;
|
||
|
begin
|
||
|
Result := FPad.Left;
|
||
|
end;
|
||
|
|
||
|
//-- BG ---------------------------------------------------------- 08.01.2012 --
|
||
|
function TfrxHtCellObj.GetPaddingRight: Integer;
|
||
|
begin
|
||
|
Result := FPad.Right;
|
||
|
end;
|
||
|
|
||
|
//-- BG ---------------------------------------------------------- 08.01.2012 --
|
||
|
function TfrxHtCellObj.GetPaddingTop: Integer;
|
||
|
begin
|
||
|
Result := FPad.Top;
|
||
|
end;
|
||
|
|
||
|
{----------------TfrxHtCellObj.InitializeCell}
|
||
|
|
||
|
procedure TfrxHtCellObj.Initialize(TablePadding: Integer; const BkImageName: ThtString;
|
||
|
const APRec: PtPositionRec; Border: Boolean);
|
||
|
begin
|
||
|
if FPad.Top < 0 then
|
||
|
FPad.Top := TablePadding;
|
||
|
if FPad.Right < 0 then
|
||
|
FPad.Right := TablePadding;
|
||
|
if FPad.Bottom < 0 then
|
||
|
FPad.Bottom := TablePadding;
|
||
|
if FPad.Left < 0 then
|
||
|
FPad.Left := TablePadding;
|
||
|
if Border and not HasBorderStyle then // (BorderStyle = bssNone) then
|
||
|
begin
|
||
|
FBrd.Left := Max(1, FBrd.Left);
|
||
|
FBrd.Right := Max(1, FBrd.Right);
|
||
|
FBrd.Top := Max(1, FBrd.Top);
|
||
|
FBrd.Bottom := Max(1, FBrd.Bottom);
|
||
|
end;
|
||
|
HzSpace := FPad.Left + FBrd.Left + FBrd.Right + FPad.Right;
|
||
|
VrSpace := FPad.Top + FBrd.Top + FBrd.Bottom + FPad.Bottom;
|
||
|
|
||
|
if (BkImageName <> '') and not Assigned(BGImage) then
|
||
|
begin
|
||
|
BGImage := TfrxFrHtImageObj.SimpleCreate(Cell, BkImageName);
|
||
|
PRec := APrec;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
{----------------TfrxHtCellObj.DrawLogic2}
|
||
|
|
||
|
procedure TfrxHtCellObj.DrawLogic2(Canvas: TCanvas; Y, CellSpacingHorz, CellSpacingVert: Integer; var Curs: Integer);
|
||
|
var
|
||
|
Dummy: Integer;
|
||
|
Tmp: Integer;
|
||
|
begin
|
||
|
if Cell.Count > 0 then
|
||
|
begin
|
||
|
Tmp := Ht - VSize - (VrSpace + CellSpacingVert);
|
||
|
case VAlign of
|
||
|
ATop: YIndent := 0;
|
||
|
AMiddle: YIndent := Tmp div 2;
|
||
|
ABottom, ABaseline: YIndent := Tmp;
|
||
|
end;
|
||
|
Dummy := 0;
|
||
|
Cell.DoLogic(Canvas, Y + FPad.Top + FBrd.Top + CellSpacingVert + YIndent, Wd - (HzSpace + CellSpacingHorz),
|
||
|
Ht - VrSpace - CellSpacingVert, 0, Dummy, Curs);
|
||
|
end;
|
||
|
if Assigned(BGImage) and Cell.Document.ShowImages then
|
||
|
begin
|
||
|
BGImage.DrawLogicInline(Canvas, nil, 100, 0);
|
||
|
if BGImage.Image = ErrorImage then
|
||
|
FreeAndNil(BGImage)
|
||
|
else
|
||
|
begin
|
||
|
BGImage.ClientSizeKnown := True; {won't need reformat on InsertImage}
|
||
|
NeedDoImageStuff := True;
|
||
|
end;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
{----------------TfrxHtCellObj.Draw}
|
||
|
|
||
|
procedure TfrxHtCellObj.Draw(Canvas: TCanvas; const ARect: TRect; X, Y, CellSpacingHorz, CellSpacingVert: Integer;
|
||
|
Border: Boolean; Light, Dark: TColor);
|
||
|
var
|
||
|
YO: Integer;
|
||
|
BL, BT, BR, BB, PL, PT, PR, PB: Integer;
|
||
|
ImgOK: Boolean;
|
||
|
IT, IH, FT, Rslt: Integer;
|
||
|
Rgn, SaveRgn: HRgn;
|
||
|
Point: TPoint;
|
||
|
BRect: TRect;
|
||
|
IsVisible: Boolean;
|
||
|
begin
|
||
|
YO := Y - Cell.Document.YOff;
|
||
|
|
||
|
BL := X + CellSpacingHorz; {Border left and right}
|
||
|
BR := X + Wd;
|
||
|
PL := BL + FBrd.Left; {Padding left and right}
|
||
|
PR := BR - FBrd.Right;
|
||
|
|
||
|
BT := YO + CellSpacingVert; {Border Top and Bottom}
|
||
|
BB := YO + Ht;
|
||
|
PT := BT + FBrd.Top; {Padding Top and Bottom}
|
||
|
PB := BB - FBrd.Bottom;
|
||
|
|
||
|
IT := Max(0, ARect.Top - 2 - PT);
|
||
|
FT := Max(PT, ARect.Top - 2); {top of area drawn, screen coordinates}
|
||
|
IH := Min(PB - FT, ARect.Bottom - FT); {height of area actually drawn}
|
||
|
|
||
|
Cell.MyRect := Rect(BL, BT, BR, BB);
|
||
|
if not (BT <= ARect.Bottom) and (BB >= ARect.Top) then
|
||
|
Exit;
|
||
|
|
||
|
try
|
||
|
if NeedDoImageStuff then
|
||
|
begin
|
||
|
if BGImage = nil then
|
||
|
NeedDoImageStuff := False
|
||
|
else if BGImage.Image <> DefImage then
|
||
|
begin
|
||
|
if BGImage.Image = ErrorImage then {Skip the background image}
|
||
|
FreeAndNil(BGImage)
|
||
|
else
|
||
|
try
|
||
|
BGImage.Image.TileImage( PRec, Wd - CellSpacingHorz, Ht - CellSpacingVert, TiledImage, NoMask);
|
||
|
if Cell.IsCopy then
|
||
|
TiledImage.Bitmap.HandleType := bmDIB;
|
||
|
except {bad image, get rid of it}
|
||
|
FreeAndNil(BGImage);
|
||
|
FreeAndNil(TiledImage);
|
||
|
end;
|
||
|
NeedDoImageStuff := False;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
ImgOK := not NeedDoImageStuff and Assigned(BGImage) and (BGImage.Image <> DefImage) and Cell.Document.ShowImages;
|
||
|
|
||
|
if Cell.BkGnd then
|
||
|
begin
|
||
|
Canvas.Brush.Color := ThemedColor(Cell.BkColor) or PalRelative;
|
||
|
Canvas.Brush.Style := bsSolid;
|
||
|
if not Cell.IsCopy or not ImgOK then
|
||
|
begin
|
||
|
{slip under border to fill gap when printing}
|
||
|
BRect := Rect(PL, FT, PR, FT + IH);
|
||
|
if not HasBorderStyle then // BorderStyle = bssNone then
|
||
|
begin
|
||
|
if MargArray[BorderLeftWidth] > 0 then
|
||
|
Dec(BRect.Left);
|
||
|
if MargArray[BorderTopWidth] > 0 then
|
||
|
Dec(BRect.Top);
|
||
|
if MargArray[BorderRightWidth] > 0 then
|
||
|
Inc(BRect.Right);
|
||
|
if MargArray[BorderBottomWidth] > 0 then
|
||
|
Inc(BRect.Bottom);
|
||
|
end
|
||
|
else
|
||
|
if Border then
|
||
|
InflateRect(BRect, 1, 1);
|
||
|
Canvas.FillRect(BRect);
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
if ImgOK and (TiledImage <> nil) then
|
||
|
begin
|
||
|
if not Cell.IsCopy then
|
||
|
TiledImage.DrawUnstretched(Canvas, PL, FT, Pr - PL, IH, 0, IT, Cell.BkGnd)
|
||
|
else
|
||
|
TiledImage.PrintUnstretched(Canvas, PL, FT, Pr - PL, IH, 0, IT, Cell.BkGnd)
|
||
|
;
|
||
|
end;
|
||
|
except
|
||
|
end;
|
||
|
|
||
|
IsVisible := (YO < ARect.Bottom + 200) and (YO + Ht > -200);
|
||
|
try
|
||
|
if IsVisible and (Cell.Count > 0) then
|
||
|
begin
|
||
|
Rslt := 0;
|
||
|
Rgn := 0;
|
||
|
SaveRgn := 0;
|
||
|
if HideOverflow then
|
||
|
begin
|
||
|
{clip cell contents to prevent overflow. First check to see if there is
|
||
|
already a clip region}
|
||
|
SaveRgn := CreateRectRgn(0, 0, 1, 1);
|
||
|
Rslt := GetClipRgn(Canvas.Handle, SaveRgn); {Rslt = 1 for existing region, 0 for none}
|
||
|
{Form the region for this cell}
|
||
|
GetWindowOrgEx(Canvas.Handle, Point); {when scrolling or animated Gifs, canvas may not start at X=0, Y=0}
|
||
|
Rgn := CreateRectRgn(BL - Point.X, BT - Point.Y, BR - Point.X, BB - Point.Y);
|
||
|
if Rslt = 1 then {if there was a region, use the intersection with this region}
|
||
|
CombineRgn(Rgn, Rgn, SaveRgn, Rgn_And);
|
||
|
SelectClipRgn(Canvas.Handle, Rgn);
|
||
|
end;
|
||
|
try
|
||
|
Cell.Draw(Canvas, ARect, Wd - HzSpace - CellSpacingHorz,
|
||
|
X + FPad.Left + FBrd.Left + CellSpacingHorz,
|
||
|
Y + FPad.Top + FBrd.Top + YIndent, ARect.Left, 0); {possibly should be IRgn.LfEdge}
|
||
|
finally
|
||
|
if HideOverflow then
|
||
|
begin
|
||
|
if Rslt = 1 then {restore any previous clip region}
|
||
|
SelectClipRgn(Canvas.Handle, SaveRgn)
|
||
|
else
|
||
|
SelectClipRgn(Canvas.Handle, 0);
|
||
|
DeleteObject(Rgn);
|
||
|
DeleteObject(SaveRgn);
|
||
|
end;
|
||
|
end;
|
||
|
end;
|
||
|
except
|
||
|
end;
|
||
|
|
||
|
Cell.DrawYY := Y;
|
||
|
if IsVisible and ((Cell.Count > 0) or ShowEmptyCells) then
|
||
|
try
|
||
|
DrawBorder(Canvas, Rect(BL, BT, BR, BB), Rect(PL, PT, PR, PB),
|
||
|
htColors(MargArray[BorderLeftColor], MargArray[BorderTopColor], MargArray[BorderRightColor], MargArray[BorderBottomColor]),
|
||
|
htStyles(ThtBorderStyle(MargArray[BorderLeftStyle]), ThtBorderStyle(MargArray[BorderTopStyle]), ThtBorderStyle(MargArray[BorderRightStyle]), ThtBorderStyle(MargArray[BorderBottomStyle])),
|
||
|
MargArray[BackgroundColor], False);
|
||
|
except
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
//-- BG ---------------------------------------------------------- 08.01.2012 --
|
||
|
procedure TfrxHtCellObj.SetBorderBottom(const Value: Integer);
|
||
|
begin
|
||
|
FBrd.Bottom := Value;
|
||
|
end;
|
||
|
|
||
|
//-- BG ---------------------------------------------------------- 08.01.2012 --
|
||
|
procedure TfrxHtCellObj.SetBorderLeft(const Value: Integer);
|
||
|
begin
|
||
|
FBrd.Left := Value;
|
||
|
end;
|
||
|
|
||
|
//-- BG ---------------------------------------------------------- 08.01.2012 --
|
||
|
procedure TfrxHtCellObj.SetBorderRight(const Value: Integer);
|
||
|
begin
|
||
|
FBrd.Right := Value;
|
||
|
end;
|
||
|
|
||
|
//-- BG ---------------------------------------------------------- 08.01.2012 --
|
||
|
procedure TfrxHtCellObj.SetBorderTop(const Value: Integer);
|
||
|
begin
|
||
|
FBrd.Top := Value;
|
||
|
end;
|
||
|
|
||
|
//-- BG ---------------------------------------------------------- 08.01.2012 --
|
||
|
procedure TfrxHtCellObj.SetPaddingBottom(const Value: Integer);
|
||
|
begin
|
||
|
FPad.Bottom := Value;
|
||
|
end;
|
||
|
|
||
|
//-- BG ---------------------------------------------------------- 08.01.2012 --
|
||
|
procedure TfrxHtCellObj.SetPaddingLeft(const Value: Integer);
|
||
|
begin
|
||
|
FPad.Left := Value;
|
||
|
end;
|
||
|
|
||
|
//-- BG ---------------------------------------------------------- 08.01.2012 --
|
||
|
procedure TfrxHtCellObj.SetPaddingRight(const Value: Integer);
|
||
|
begin
|
||
|
FPad.Right := Value;
|
||
|
end;
|
||
|
|
||
|
//-- BG ---------------------------------------------------------- 08.01.2012 --
|
||
|
procedure TfrxHtCellObj.SetPaddingTop(const Value: Integer);
|
||
|
begin
|
||
|
FPad.Top := Value;
|
||
|
end;
|
||
|
|
||
|
{----------------TfrxHtCellList.Create}
|
||
|
|
||
|
constructor TfrxHtCellList.Create(Attr: TfrxHtAttributeList; Prop: TfrxHTProperties);
|
||
|
var
|
||
|
I: Integer;
|
||
|
Color: TColor;
|
||
|
begin
|
||
|
inherited Create;
|
||
|
if Assigned(Attr) then
|
||
|
for I := 0 to Attr.Count - 1 do
|
||
|
with Attr[I] do
|
||
|
case Which of
|
||
|
BGColorSy:
|
||
|
BkGnd := TryStrToColor(Name, False, BkColor);
|
||
|
BackgroundSy:
|
||
|
BkImage := Name;
|
||
|
HeightSy:
|
||
|
SpecRowHeight := ToSpecWidth(Max(0, Min(Value, 100)), Name);
|
||
|
end;
|
||
|
if Assigned(Prop) then
|
||
|
begin
|
||
|
Color := Prop.GetBackgroundColor;
|
||
|
if Color <> clNone then
|
||
|
begin
|
||
|
BkGnd := True;
|
||
|
BkColor := Color;
|
||
|
end;
|
||
|
Prop.GetBackgroundImage(BkImage); {'none' will change ThtString to empty}
|
||
|
if BkImage <> '' then
|
||
|
Prop.GetBackgroundPos(Prop.EmSize, Prop.ExSize, APRec);
|
||
|
Prop.GetPageBreaks(BreakBefore, BreakAfter, KeepIntact);
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
{----------------TfrxHtCellList.CreateCopy}
|
||
|
|
||
|
constructor TfrxHtCellList.CreateCopy(Parent: TfrxHtBlock; T: TfrxHtCellList);
|
||
|
var
|
||
|
I: Integer;
|
||
|
begin
|
||
|
inherited Create;
|
||
|
BreakBefore := T.BreakBefore;
|
||
|
BreakAfter := T.BreakAfter;
|
||
|
KeepIntact := T.KeepIntact;
|
||
|
RowType := T.Rowtype;
|
||
|
for I := 0 to T.Count - 1 do
|
||
|
if Assigned(T[I]) then
|
||
|
Add(T[I].Clone(Parent))
|
||
|
else
|
||
|
Add(nil);
|
||
|
end;
|
||
|
|
||
|
procedure TfrxHtCellList.Add(CellObjBase: TfrxHtfrcHtCellObjBase);
|
||
|
var
|
||
|
CellObj: TfrxHtCellObj absolute CellObjBase;
|
||
|
begin
|
||
|
inherited Add(CellObjBase);
|
||
|
if CellObjBase is TfrxHtCellObj then
|
||
|
begin
|
||
|
BreakBefore := BreakBefore or CellObj.BreakBefore;
|
||
|
BreakAfter := BreakAfter or CellObj.BreakAfter;
|
||
|
KeepIntact := KeepIntact or CellObj.KeepIntact;
|
||
|
case SpecRowHeight.VType of
|
||
|
wtPercent:
|
||
|
case CellObj.FSpecHt.VType of
|
||
|
wtPercent:
|
||
|
if CellObj.FSpecHt.Value < SpecRowHeight.Value then
|
||
|
CellObj.FSpecHt.Value := SpecRowHeight.Value;
|
||
|
|
||
|
wtNone,
|
||
|
wtRelative: // percentage is stronger
|
||
|
CellObj.FSpecHt := SpecRowHeight;
|
||
|
|
||
|
else
|
||
|
// keep specified absolute value
|
||
|
end;
|
||
|
|
||
|
wtRelative:
|
||
|
case CellObj.FSpecHt.VType of
|
||
|
wtPercent: ; // percentage is stronger
|
||
|
|
||
|
wtNone:
|
||
|
CellObj.FSpecHt := SpecRowHeight;
|
||
|
|
||
|
wtRelative:
|
||
|
if CellObj.FSpecHt.Value < SpecRowHeight.Value then
|
||
|
CellObj.FSpecHt.Value := SpecRowHeight.Value;
|
||
|
else
|
||
|
// keep specified absolute value
|
||
|
end;
|
||
|
|
||
|
wtAbsolute:
|
||
|
case CellObj.FSpecHt.VType of
|
||
|
wtAbsolute:
|
||
|
if CellObj.FSpecHt.Value < SpecRowHeight.Value then
|
||
|
CellObj.FSpecHt.Value := SpecRowHeight.Value;
|
||
|
else
|
||
|
// absolute value is stronger
|
||
|
CellObj.FSpecHt := SpecRowHeight;
|
||
|
end;
|
||
|
end;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
{----------------TfrxHtCellList.Initialize}
|
||
|
|
||
|
procedure TfrxHtCellList.Initialize;
|
||
|
var
|
||
|
I: Integer;
|
||
|
begin
|
||
|
if BkGnd then
|
||
|
for I := 0 to Count - 1 do
|
||
|
if Items[I] is TfrxHtCellObj then
|
||
|
with TfrxHtCellObj(Items[I]).Cell do
|
||
|
if not BkGnd then
|
||
|
begin
|
||
|
BkGnd := True;
|
||
|
BkColor := Self.BkColor;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
procedure TfrxHtCellList.RTLSwap;
|
||
|
var
|
||
|
i: Integer;
|
||
|
begin
|
||
|
for i := 0 to Count div 2 - 1 do
|
||
|
Exchange(i, Count - i - 1);
|
||
|
end;
|
||
|
|
||
|
{----------------TfrxHtCellList.DrawLogic1}
|
||
|
|
||
|
function TfrxHtCellList.DrawLogicA(Canvas: TCanvas; const Widths: TIntArray; Span, CellSpacingHorz,CellSpacingVert, AHeight, Rows: Integer;
|
||
|
out Desired: Integer; out Spec, More: Boolean): Integer;
|
||
|
{Find vertical size of each cell, Row height of this row. But final Y position
|
||
|
is not known at this time.
|
||
|
Rows is number rows in table.
|
||
|
AHeight is for calculating percentage heights}
|
||
|
var
|
||
|
I, Dummy: Integer;
|
||
|
DummyCurs, GuessHt: Integer;
|
||
|
begin
|
||
|
Result := 0;
|
||
|
Desired := 0;
|
||
|
Spec := False;
|
||
|
DummyCurs := 0;
|
||
|
More := False;
|
||
|
for I := 0 to Count - 1 do
|
||
|
begin
|
||
|
if Items[I] is TfrxHtCellObj then
|
||
|
with TfrxHtCellObj(Items[I]) do
|
||
|
if ColSpan > 0 then {skip the dummy cells}
|
||
|
begin
|
||
|
Wd := Sum(Widths, I, I + ColSpan - 1); {accumulate column widths}
|
||
|
if Span = RowSpan then
|
||
|
begin
|
||
|
Dummy := 0;
|
||
|
case SpecHt.VType of
|
||
|
wtAbsolute:
|
||
|
GuessHt := Trunc(SpecHt.Value);
|
||
|
|
||
|
wtPercent:
|
||
|
GuessHt := Trunc(SpecHt.Value * AHeight / 1000.0);
|
||
|
else
|
||
|
GuessHt := 0;
|
||
|
end;
|
||
|
|
||
|
if (GuessHt = 0) and (Rows = 1) then
|
||
|
GuessHt := AHeight;
|
||
|
|
||
|
VSize := Cell.DoLogic(Canvas, 0, Wd - HzSpace - CellSpacingHorz, Max(0, GuessHt - VrSpace), 0, Dummy, DummyCurs);
|
||
|
Result := Max(Result, VSize + VrSpace);
|
||
|
|
||
|
case SpecHt.VType of
|
||
|
wtAbsolute:
|
||
|
begin
|
||
|
Result := Max(Result, Max(VSize, Trunc(SpecHt.Value)));
|
||
|
Spec := True;
|
||
|
end;
|
||
|
|
||
|
wtPercent:
|
||
|
begin
|
||
|
Desired := Max(Desired, GuessHt);
|
||
|
Spec := True;
|
||
|
end;
|
||
|
end;
|
||
|
end
|
||
|
else if RowSpan > Span then
|
||
|
More := True;
|
||
|
end;
|
||
|
end;
|
||
|
Desired := Max(Result, Desired);
|
||
|
end;
|
||
|
|
||
|
{----------------TfrxHtCellList.DrawLogicB}
|
||
|
|
||
|
procedure TfrxHtCellList.DrawLogicB(Canvas: TCanvas; Y, CellSpacingHorz, CellSpacingVert: Integer; var Curs: Integer);
|
||
|
{Calc Y indents. Set up Y positions of all cells.}
|
||
|
var
|
||
|
I: Integer;
|
||
|
CellObj: TfrxHtfrcHtCellObjBase;
|
||
|
begin
|
||
|
for I := 0 to Count - 1 do
|
||
|
begin
|
||
|
CellObj := Items[I];
|
||
|
if (CellObj <> nil) and (CellObj.ColSpan > 0) and (CellObj.RowSpan > 0) then
|
||
|
CellObj.DrawLogic2(Canvas, Y, CellSpacingHorz,CellSpacingVert, Curs);
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
//-- BG ---------------------------------------------------------- 12.09.2010 --
|
||
|
function TfrxHtCellList.GetCellObj(Index: Integer): TfrxHtfrcHtCellObjBase;
|
||
|
begin
|
||
|
Result := inherited Get(Index);
|
||
|
end;
|
||
|
|
||
|
{----------------TfrxHtCellList.Draw}
|
||
|
|
||
|
function TfrxHtCellList.Draw(Canvas: TCanvas; Document: TfrxHtDocument; const ARect: TRect; const Widths: TIntArray;
|
||
|
X, Y, YOffset, CellSpacingHorz,CellSpacingVert: Integer; Border: Boolean; Light, Dark: TColor; MyRow: Integer): Integer;
|
||
|
var
|
||
|
I: Integer;
|
||
|
YO: Integer;
|
||
|
CellObj: TfrxHtfrcHtCellObjBase;
|
||
|
begin
|
||
|
YO := Y - YOffset;
|
||
|
Result := RowHeight + Y;
|
||
|
|
||
|
if (YO + RowSpanHeight >= ARect.Top) and (YO < ARect.Bottom) then
|
||
|
for I := 0 to Count - 1 do
|
||
|
begin
|
||
|
CellObj := Items[I];
|
||
|
if (CellObj <> nil) and (CellObj.ColSpan > 0) and (CellObj.RowSpan > 0) then
|
||
|
CellObj.Draw(Canvas, ARect, X, Y, CellSpacingHorz,CellSpacingVert, Border, Light, Dark);
|
||
|
X := X + Widths[I];
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
//-- BG ---------------------------------------------------------- 09.02.2013 --
|
||
|
function TryStrToTableFrame(const Str: ThtString; var Frame: TTableFrame): Boolean;
|
||
|
{$ifdef UseInline} inline; {$endif}
|
||
|
var
|
||
|
Upr: ThtString;
|
||
|
begin
|
||
|
Upr := htUpperCase(Str);
|
||
|
Result := True;
|
||
|
if htCompareStr(Upr, 'VOID') = 0 then
|
||
|
Frame := tfVoid
|
||
|
else if htCompareStr(Upr, 'ABOVE') = 0 then
|
||
|
Frame := tfAbove
|
||
|
else if htCompareStr(Upr, 'BELOW') = 0 then
|
||
|
Frame := tfBelow
|
||
|
else if htCompareStr(Upr, 'HSIDES') = 0 then
|
||
|
Frame := tfHSides
|
||
|
else if htCompareStr(Upr, 'LHS') = 0 then
|
||
|
Frame := tfLhs
|
||
|
else if htCompareStr(Upr, 'RHS') = 0 then
|
||
|
Frame := tfRhs
|
||
|
else if htCompareStr(Upr, 'VSIDES') = 0 then
|
||
|
Frame := tfVSides
|
||
|
else if htCompareStr(Upr, 'BOX') = 0 then
|
||
|
Frame := tfBox
|
||
|
else if htCompareStr(Upr, 'BORDER') = 0 then
|
||
|
Frame := tfBorder
|
||
|
else
|
||
|
Result := False;
|
||
|
end;
|
||
|
|
||
|
//-- BG ---------------------------------------------------------- 09.02.2013 --
|
||
|
function TryStrToTableRules(const Str: ThtString; var Rules: TTableRules): Boolean;
|
||
|
{$ifdef UseInline} inline; {$endif}
|
||
|
var
|
||
|
Upr: ThtString;
|
||
|
begin
|
||
|
Upr := htUpperCase(Str);
|
||
|
Result := True;
|
||
|
if htCompareStr(Upr, 'NONE') = 0 then
|
||
|
Rules := trNone
|
||
|
else if htCompareStr(Upr, 'GROUPS') = 0 then
|
||
|
Rules := trGroups
|
||
|
else if htCompareStr(Upr, 'ROWS') = 0 then
|
||
|
Rules := trRows
|
||
|
else if htCompareStr(Upr, 'COLS') = 0 then
|
||
|
Rules := trCols
|
||
|
else if htCompareStr(Upr, 'ALL') = 0 then
|
||
|
Rules := trAll
|
||
|
else
|
||
|
Result := False;
|
||
|
end;
|
||
|
|
||
|
{----------------TfrxHtmlTable.Create}
|
||
|
|
||
|
constructor TfrxHtmlTable.Create(OwnerTableBlock: TfrxHtTableBlock; Parent: TfrxHtCellBasic; Attr: TfrxHtAttributeList; Prop: TfrxHTProperties);
|
||
|
var
|
||
|
I: Integer;
|
||
|
A: TfrxHtAttribute;
|
||
|
begin
|
||
|
inherited Create(Parent, Attr, Prop);
|
||
|
FOwnerTableBlock := OwnerTableBlock;
|
||
|
if FDisplay = pdUnassigned then
|
||
|
FDisplay := pdTable;
|
||
|
Rows := TfrxHtRowList.Create;
|
||
|
|
||
|
FCellPadding := 1;
|
||
|
FCellSpacingHorz := 2;
|
||
|
FCellSpacingVert := 2;
|
||
|
BorderColor := clBtnFace;
|
||
|
BorderColorLight := clBtnHighLight;
|
||
|
BorderColorDark := clBtnShadow;
|
||
|
|
||
|
// BG, 20.01.2013: process BorderSy before FrameSy and RulesSy as it implies defaults.
|
||
|
A := nil;
|
||
|
HasBorderWidthAttr := Attr.Find(BorderSy, A);
|
||
|
if HasBorderWidthAttr then
|
||
|
begin
|
||
|
//BG, 15.10.2010: issue 5: set border width only, if style does not set any border width:
|
||
|
if A.Name = '' then
|
||
|
BorderWidth := 1
|
||
|
else
|
||
|
BorderWidth := Min(100, Max(0, A.Value)); {Border=0 is no border}
|
||
|
brdWidthAttr := BorderWidth;
|
||
|
|
||
|
if BorderWidth <> 0 then
|
||
|
begin
|
||
|
Frame := tfBorder;
|
||
|
Rules := trAll;
|
||
|
end
|
||
|
else
|
||
|
begin
|
||
|
Frame := tfVoid;
|
||
|
Rules := trNone;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
for I := 0 to Attr.Count - 1 do
|
||
|
with Attr[I] do
|
||
|
case Which of
|
||
|
FrameAttrSy:
|
||
|
TryStrToTableFrame(Name, Frame);
|
||
|
|
||
|
RulesSy:
|
||
|
TryStrToTableRules(Name, Rules);
|
||
|
|
||
|
CellSpacingSy:
|
||
|
begin
|
||
|
FCellSpacingHorz := Min(40, Max(-1, Value));
|
||
|
FCellSpacingVert := CellSpacingHorz;
|
||
|
end;
|
||
|
|
||
|
CellPaddingSy:
|
||
|
FCellPadding := Min(50, Max(0, Value));
|
||
|
|
||
|
BorderColorSy:
|
||
|
TryStrToColor(Name, False, BorderColor);
|
||
|
|
||
|
BorderColorLightSy:
|
||
|
TryStrToColor(Name, False, BorderColorLight);
|
||
|
|
||
|
BorderColorDarkSy:
|
||
|
TryStrToColor(Name, False, BorderColorDark);
|
||
|
end;
|
||
|
if Prop.Collapse then
|
||
|
begin
|
||
|
FCellSpacingHorz := -1;
|
||
|
FCellSpacingVert := -1;
|
||
|
end
|
||
|
else if Prop.HasBorderSpacing then
|
||
|
begin
|
||
|
FCellSpacingHorz := Prop.GetBorderSpacingHorz;
|
||
|
FCellSpacingVert := Prop.GetBorderSpacingVert;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
{----------------TfrxHtmlTable.CreateCopy}
|
||
|
|
||
|
constructor TfrxHtmlTable.CreateCopy(OwnerCell: TfrxHtCellBasic; Source: TfrxHtmlNode);
|
||
|
var
|
||
|
I: Integer;
|
||
|
HtmlTable: TfrxHtmlTable absolute Source;
|
||
|
begin
|
||
|
inherited CreateCopy(OwnerCell,Source);
|
||
|
FOwnerTableBlock := OwnerCell.FOwnerBlock as TfrxHtTableBlock;
|
||
|
Rows := TfrxHtRowList.Create;
|
||
|
for I := 0 to HtmlTable.Rows.Count - 1 do
|
||
|
Rows.Add(TfrxHtCellList.CreateCopy(OwnerCell.OwnerBlock, HtmlTable.Rows[I]));
|
||
|
|
||
|
Move(HtmlTable.Initialized, Initialized, PtrSub(@EndList, @Initialized));
|
||
|
Rules := HtmlTable.Rules;
|
||
|
BorderWidth := HtmlTable.BorderWidth;
|
||
|
BorderColor := HtmlTable.BorderColor;
|
||
|
|
||
|
SetLength(Widths, NumCols);
|
||
|
SetLength(MaxWidths, NumCols);
|
||
|
SetLength(MinWidths, NumCols);
|
||
|
SetLength(Percents, NumCols);
|
||
|
SetLength(Multis, NumCols);
|
||
|
SetLength(ColumnSpecs, NumCols);
|
||
|
|
||
|
if HtmlTable.FColSpecs <> nil then
|
||
|
begin
|
||
|
FColSpecs := TfrxHtColSpecList.Create;
|
||
|
for I := 0 to HtmlTable.FColSpecs.Count - 1 do
|
||
|
FColSpecs.Add(TfrxHtColSpec.CreateCopy(HtmlTable.FColSpecs[I]));
|
||
|
end;
|
||
|
|
||
|
if Document.PrintTableBackground then
|
||
|
begin
|
||
|
FBkGnd := HtmlTable.BkGnd;
|
||
|
FBkColor := HtmlTable.BkColor;
|
||
|
end
|
||
|
else
|
||
|
FBkGnd := False;
|
||
|
TablePartRec := TTablePartRec.Create;
|
||
|
TablePartRec.TablePart := Normal;
|
||
|
end;
|
||
|
|
||
|
{----------------TfrxHtmlTable.Destroy}
|
||
|
|
||
|
destructor TfrxHtmlTable.Destroy;
|
||
|
begin
|
||
|
Rows.Free;
|
||
|
TablePartRec.Free;
|
||
|
FreeAndNil(FColSpecs);
|
||
|
inherited Destroy;
|
||
|
end;
|
||
|
|
||
|
{----------------TfrxHtmlTable.DoColumns}
|
||
|
|
||
|
procedure TfrxHtmlTable.DoColumns(Count: Integer; const SpecWidth: TSpecWidth; VAlign: ThtAlignmentStyle; const Align: ThtString);
|
||
|
{add the <col> / <colgroup> info to the Cols list}
|
||
|
var
|
||
|
I: Integer;
|
||
|
begin
|
||
|
if FColSpecs = nil then
|
||
|
FColSpecs := TfrxHtColSpecList.Create;
|
||
|
Count := Min(Count, 10000);
|
||
|
for I := 0 to Count - 1 do
|
||
|
FColSpecs.Add(TfrxHtColSpec.Create(SpecWidth, Align, VAlign));
|
||
|
end;
|
||
|
|
||
|
{----------------TfrxHtmlTable.AddDummyCells}
|
||
|
|
||
|
procedure TfrxHtmlTable.Initialize;
|
||
|
|
||
|
function DummyCell(RSpan: Integer): TfrxHtfrcHtCellObjBase;
|
||
|
begin
|
||
|
Result := TfrxHtDummyCellObj.Create(RSpan);
|
||
|
// if BkGnd then {transfer bgcolor to cell if no Table image}
|
||
|
// begin
|
||
|
// Result.Cell.BkGnd := True;
|
||
|
// Result.Cell.BkColor := BkColor;
|
||
|
// end;
|
||
|
end;
|
||
|
|
||
|
procedure AddDummyCellsForColSpansAndInitializeCells;
|
||
|
var
|
||
|
Cl, Rw, RowCount, K: Integer;
|
||
|
Row: TfrxHtCellList;
|
||
|
CellObjBase: TfrxHtfrcHtCellObjBase;
|
||
|
CellObj: TfrxHtCellObj absolute CellObjBase;
|
||
|
begin
|
||
|
{initialize cells and put dummy cells in rows to make up for ColSpan > 1}
|
||
|
NumCols := 0;
|
||
|
RowCount := Rows.Count;
|
||
|
for Rw := 0 to RowCount - 1 do
|
||
|
begin
|
||
|
Row := Rows[Rw];
|
||
|
Row.Initialize;
|
||
|
for Cl := Row.Count - 1 downto 0 do
|
||
|
begin
|
||
|
CellObjBase := Row[Cl];
|
||
|
CellObj.Initialize(CellPadding, Row.BkImage, Row.APRec, Self.BorderWidth > 0);
|
||
|
if BkGnd and not CellObj.Cell.BkGnd then {transfer bgcolor to cells if no Table image}
|
||
|
begin
|
||
|
CellObj.Cell.BkGnd := True;
|
||
|
CellObj.Cell.BkColor := BkColor;
|
||
|
end;
|
||
|
CellObj.RowSpan := Min(CellObj.RowSpan, RowCount - Rw); {So can't extend beyond table}
|
||
|
for K := Cl + 1 to Cl + CellObj.ColSpan - 1 do
|
||
|
if CellObj.RowSpan > 1 then
|
||
|
Row.Insert(K, DummyCell(CellObj.RowSpan)) {these could be
|
||
|
Nil also except they're needed for expansion in the next section}
|
||
|
else
|
||
|
Row.Insert(K, DummyCell(1));
|
||
|
end;
|
||
|
NumCols := Max(NumCols, Row.Count); {temporary # cols}
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
procedure AddDummyCellsForRowSpans;
|
||
|
var
|
||
|
Cl, Rw, RowCount, K: Integer;
|
||
|
Row: TfrxHtCellList;
|
||
|
CellObj: TfrxHtfrcHtCellObjBase;
|
||
|
begin
|
||
|
RowCount := Rows.Count;
|
||
|
for Cl := 0 to NumCols - 1 do
|
||
|
for Rw := 0 to RowCount - 1 do
|
||
|
begin
|
||
|
Row := Rows[Rw];
|
||
|
if Row.Count > Cl then
|
||
|
begin
|
||
|
CellObj := Row[Cl];
|
||
|
if CellObj <> nil then
|
||
|
begin
|
||
|
CellObj.RowSpan := Min(CellObj.RowSpan, RowCount - Rw); {practical limit}
|
||
|
if CellObj.RowSpan > 1 then
|
||
|
for K := Rw + 1 to Rw + CellObj.RowSpan - 1 do
|
||
|
begin {insert dummy cells in following rows if RowSpan > 1}
|
||
|
while Rows[K].Count < Cl do {add padding if row is short}
|
||
|
Rows[K].Add(DummyCell(0));
|
||
|
if Rows[K].Count < NumCols then // in an invalid table definition spanned cells may overlap and thus required dummies could be present, yet.
|
||
|
Rows[K].Insert(Cl, DummyCell(0));
|
||
|
end;
|
||
|
end;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
NumCols := 0;
|
||
|
for Rw := 0 to Rows.Count - 1 do
|
||
|
NumCols := Max(NumCols, Rows[Rw].Count);
|
||
|
end;
|
||
|
|
||
|
procedure AddDummyCellsForUnequalRowLengths;
|
||
|
var
|
||
|
Cl: Integer;
|
||
|
CellObj: TfrxHtfrcHtCellObjBase;
|
||
|
Row: TfrxHtCellList;
|
||
|
|
||
|
function IsLastCellOfRow(): Boolean;
|
||
|
begin
|
||
|
// Is Row[Cl] resp. CellObj a cell in this row? (Cl >= 0)
|
||
|
// With respect to rowspans from previous rows is it the last one? (Cl + CellObj.ColSpan >= NumCols)
|
||
|
Result := (Cl >= 0) and (Cl + CellObj.ColSpan >= Row.Count);
|
||
|
end;
|
||
|
|
||
|
var
|
||
|
Rw, I: Integer;
|
||
|
begin
|
||
|
Rw := 0;
|
||
|
while Rw < Rows.Count do
|
||
|
begin
|
||
|
Row := Rows[Rw];
|
||
|
Cl := -1;
|
||
|
if Row.Count < NumCols then
|
||
|
begin
|
||
|
// this row is too short
|
||
|
|
||
|
// find the spanning column
|
||
|
Cl := Row.Count - 1;
|
||
|
while Cl >= 0 do
|
||
|
begin
|
||
|
CellObj := Row[Cl];
|
||
|
if CellObj.ColSpan > 0 then
|
||
|
break;
|
||
|
Dec(Cl);
|
||
|
end;
|
||
|
|
||
|
if IsLastCellOfRow then
|
||
|
// add missing cells
|
||
|
for I := Row.Count to NumCols - 1 do
|
||
|
Row.Add(DummyCell(1));
|
||
|
end;
|
||
|
|
||
|
// continue with next row not spanned by this cell.
|
||
|
if (Cl >= 0) and (CellObj.RowSpan > 0) then
|
||
|
Inc(Rw, CellObj.RowSpan)
|
||
|
else
|
||
|
Inc(Rw);
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
var
|
||
|
Cl, Rw, MaxColSpan, MaxRowSpan: Integer;
|
||
|
Row: TfrxHtCellList;
|
||
|
CellObj: TfrxHtfrcHtCellObjBase;
|
||
|
begin
|
||
|
if not Initialized then
|
||
|
begin
|
||
|
AddDummyCellsForColSpansAndInitializeCells;
|
||
|
AddDummyCellsForRowSpans;
|
||
|
AddDummyCellsForUnequalRowLengths;
|
||
|
|
||
|
for Rw := 0 to Rows.Count - 1 do
|
||
|
begin
|
||
|
MaxRowSpan := Rows.Count - Rw;
|
||
|
Row := Rows[Rw];
|
||
|
for Cl := 0 to Row.Count - 1 do
|
||
|
begin
|
||
|
MaxColSpan := NumCols - Cl;
|
||
|
CellObj := Row[Cl];
|
||
|
|
||
|
// Reduce excessive colspans.
|
||
|
if CellObj.ColSpan > MaxColSpan then
|
||
|
CellObj.ColSpan := MaxColSpan;
|
||
|
|
||
|
// Reduce excessive rowspans.
|
||
|
if CellObj.RowSpan > MaxRowSpan then
|
||
|
CellObj.RowSpan := MaxRowSpan;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
SetLength(Widths, NumCols);
|
||
|
SetLength(MaxWidths, NumCols);
|
||
|
SetLength(MinWidths, NumCols);
|
||
|
SetLength(Percents, NumCols);
|
||
|
SetLength(Multis, NumCols);
|
||
|
SetLength(ColumnSpecs, NumCols);
|
||
|
|
||
|
Initialized := True;
|
||
|
end; {if not ListsProcessed}
|
||
|
end;
|
||
|
|
||
|
procedure TfrxHtmlTable.IncreaseWidthsByWidth(WidthType: TWidthType; var Widths: TIntArray;
|
||
|
StartIndex, EndIndex, Required, Spanned, Count: Integer);
|
||
|
// Increases width of spanned columns relative to given widths.
|
||
|
var
|
||
|
I, OldWidth, NewWidth: Integer;
|
||
|
begin
|
||
|
OldWidth := 0;
|
||
|
NewWidth := 0;
|
||
|
for I := EndIndex downto StartIndex do
|
||
|
if ColumnSpecs[I] = WidthType then
|
||
|
if Count > 1 then
|
||
|
begin
|
||
|
// building sum of all processed columns avoids rounding errors.
|
||
|
Inc(OldWidth, Widths[I]);
|
||
|
Widths[I] := MulDiv(OldWidth, Required, Spanned) - NewWidth;
|
||
|
Inc(NewWidth, Widths[I]);
|
||
|
Dec(Count);
|
||
|
end
|
||
|
else
|
||
|
begin
|
||
|
// The remaining pixels are the new first column's width.
|
||
|
Widths[I] := Required - NewWidth;
|
||
|
break;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
procedure TfrxHtmlTable.IncreaseWidthsByPercentage(var Widths: TIntArray;
|
||
|
StartIndex, EndIndex, Required, Spanned, Percent, Count: Integer);
|
||
|
// Increases width of spanned columns relative to given percentage.
|
||
|
var
|
||
|
Excess, AddedExcess, AddedPercent, I, Add: Integer;
|
||
|
begin
|
||
|
Excess := Required - Spanned;
|
||
|
AddedExcess := 0;
|
||
|
AddedPercent := 0;
|
||
|
for I := EndIndex downto StartIndex do
|
||
|
if ColumnSpecs[I] = wtPercent then
|
||
|
if Count > 1 then
|
||
|
begin
|
||
|
Inc(AddedPercent, Percents[I]);
|
||
|
Add := MulDiv(Excess, AddedPercent, Percent) - AddedExcess;
|
||
|
Inc(Widths[I], Add);
|
||
|
Inc(AddedExcess, Add);
|
||
|
Dec(Count);
|
||
|
end
|
||
|
else
|
||
|
begin
|
||
|
// add the remaining pixels to the first column's width.
|
||
|
Inc(Widths[I], Excess - AddedExcess);
|
||
|
break;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
procedure TfrxHtmlTable.IncreaseWidthsByMinMaxDelta(WidthType: TWidthType; var Widths: TIntArray;
|
||
|
StartIndex, EndIndex, Excess, DeltaWidth, Count: Integer; const Deltas: TIntArray);
|
||
|
// Increases width of spanned columns relative to difference between min and max widths.
|
||
|
var
|
||
|
AddedExcess, AddedDelta, I, Add: Integer;
|
||
|
WidthSum, K, Remaining: Integer;
|
||
|
SameWidthFix: TSameWidthFix;
|
||
|
begin
|
||
|
SameWidthFix := TSameWidthFix.Create(Widths, MinWidths, MaxWidths, ColumnSpecs);
|
||
|
AddedExcess := 0;
|
||
|
AddedDelta := 0;
|
||
|
for I := EndIndex downto StartIndex do
|
||
|
if ColumnSpecs[I] = WidthType then
|
||
|
if Count > 1 then
|
||
|
begin
|
||
|
Inc(AddedDelta, Deltas[I]);
|
||
|
Add := MulDiv(Excess, AddedDelta, DeltaWidth) - AddedExcess;
|
||
|
Inc(Widths[I], Add);
|
||
|
Inc(AddedExcess, Add);
|
||
|
Dec(Count);
|
||
|
end
|
||
|
else
|
||
|
begin
|
||
|
// BG, 16.11.2013: thanks to Andreas Hausladen for spreading Excess:
|
||
|
if WidthType = wtNone then
|
||
|
begin
|
||
|
WidthSum := 0;
|
||
|
for K := EndIndex downto StartIndex do
|
||
|
if ColumnSpecs[K] = WidthType then
|
||
|
Inc(WidthSum, Widths[K] + Deltas[K]);
|
||
|
|
||
|
// spread the remaining pixels to all columns by their width percentage
|
||
|
Remaining := (Excess - AddedExcess) - DeltaWidth;
|
||
|
if (Remaining > 0) and (WidthSum > 0) then // wrong display is better than crash
|
||
|
begin
|
||
|
for K := EndIndex downto StartIndex + 1 do
|
||
|
begin
|
||
|
if ColumnSpecs[K] = WidthType then
|
||
|
begin
|
||
|
Add := ((Widths[K] + Deltas[K]) * Remaining) div WidthSum;
|
||
|
Inc(Widths[K], Add);
|
||
|
Inc(AddedExcess, Add);
|
||
|
end;
|
||
|
end;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
// add the remaining pixels to the first column's width.
|
||
|
Inc(Widths[I], Excess - AddedExcess);
|
||
|
break;
|
||
|
end;
|
||
|
SameWidthFix.Fix(Widths);
|
||
|
SameWidthFix.Free;
|
||
|
end;
|
||
|
|
||
|
procedure TfrxHtmlTable.IncreaseWidthsRelatively(
|
||
|
var Widths: TIntArray;
|
||
|
StartIndex, EndIndex, Required, SpannedMultis: Integer; ExactRelation: Boolean);
|
||
|
// Increases width of spanned columns according to relative columns specification.
|
||
|
// Does not touch columns specified by percentage or absolutely.
|
||
|
var
|
||
|
RequiredWidthFactor: Double;
|
||
|
Count, I, AddedWidth, AddedMulti: Integer;
|
||
|
begin
|
||
|
// Some columns might have Multi=0. Don't widen these. Thus remove their width from Required.
|
||
|
// Some columns might be wider than required. Widen all columns to preserve the relations.
|
||
|
RequiredWidthFactor := 0;
|
||
|
Count := 0;
|
||
|
for I := EndIndex downto StartIndex do
|
||
|
if ColumnSpecs[I] = wtRelative then
|
||
|
if Multis[I] > 0 then
|
||
|
begin
|
||
|
Inc(Count);
|
||
|
if ExactRelation then
|
||
|
RequiredWidthFactor := Max(RequiredWidthFactor, Widths[I] / Multis[I]);
|
||
|
end
|
||
|
else
|
||
|
begin
|
||
|
Dec(Required, Widths[I]);
|
||
|
end;
|
||
|
|
||
|
RequiredWidthFactor := Max(RequiredWidthFactor, Required / SpannedMultis); // 100 times width of 1*.
|
||
|
Required := Min(Required, Trunc(RequiredWidthFactor * SpannedMultis)); // don't exceed given requirement.
|
||
|
// building sum of all processed columns to reduce rounding errors.
|
||
|
AddedWidth := 0;
|
||
|
AddedMulti := 0;
|
||
|
for I := EndIndex downto StartIndex do
|
||
|
if (ColumnSpecs[I] = wtRelative) and (Multis[I] > 0) then
|
||
|
if Count > 1 then
|
||
|
begin
|
||
|
Inc(AddedMulti, Multis[I]);
|
||
|
Widths[I] := Trunc(AddedMulti * RequiredWidthFactor) - AddedWidth;
|
||
|
Inc(AddedWidth, Widths[I]);
|
||
|
Dec(Count);
|
||
|
end
|
||
|
else
|
||
|
begin
|
||
|
// The remaining pixels are the new first column's width.
|
||
|
Widths[I] := Required - AddedWidth;
|
||
|
break;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
procedure TfrxHtmlTable.IncreaseWidthsEvenly(WidthType: TWidthType; var Widths: TIntArray;
|
||
|
StartIndex, EndIndex, Required, Spanned, Count: Integer);
|
||
|
// Increases width of spanned columns of given type evenly.
|
||
|
var
|
||
|
RemainingWidth, I: Integer;
|
||
|
begin
|
||
|
RemainingWidth := Required;
|
||
|
for I := EndIndex downto StartIndex do
|
||
|
if ColumnSpecs[I] = WidthType then
|
||
|
if Count > 1 then
|
||
|
begin
|
||
|
Dec(Count);
|
||
|
// MulDiv for each column instead of 1 precalculated width for all columns avoids round off errors.
|
||
|
Widths[I] := MulDiv(Widths[I], Required, Spanned);
|
||
|
Dec(RemainingWidth, Widths[I]);
|
||
|
end
|
||
|
else
|
||
|
begin
|
||
|
// add the remaining pixels to the first column's width.
|
||
|
Widths[I] := RemainingWidth;
|
||
|
break;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
{----------------TfrxHtmlTable.GetWidths}
|
||
|
|
||
|
procedure TfrxHtmlTable.GetMinMaxWidths(Canvas: TCanvas; AvailableWidth, AvailableHeight: Integer);
|
||
|
// calculate MaxWidths and MinWidths of all columns.
|
||
|
|
||
|
procedure UpdateColumnSpec(var Counts: TIntegerPerWidthType; var OldType: TWidthType; NewType: TWidthType);
|
||
|
begin
|
||
|
// update to stonger spec only:
|
||
|
case NewType of
|
||
|
wtAbsolute: if OldType in [wtAbsolute] then Exit;
|
||
|
wtPercent: if OldType in [wtAbsolute, wtPercent] then Exit;
|
||
|
wtRelative: if OldType in [wtAbsolute, wtPercent, wtRelative] then Exit;
|
||
|
else
|
||
|
// wtNone:
|
||
|
Exit;
|
||
|
end;
|
||
|
|
||
|
// at this point: NewType is stronger than OldType
|
||
|
Dec(Counts[OldType]);
|
||
|
Inc(Counts[NewType]);
|
||
|
OldType := NewType;
|
||
|
end;
|
||
|
|
||
|
procedure UpdateRelativeWidths(var Widths: TIntArray; const ColumnSpecs: TWidthTypeArray; StartIndex, EndIndex: Integer);
|
||
|
// Increases width of spanned columns according to relative columns specification.
|
||
|
// Does not touch columns specified by percentage or absolutely.
|
||
|
var
|
||
|
RequiredWidthFactor, Count, Multi, I, Required, AddedWidth, AddedMulti: Integer;
|
||
|
begin
|
||
|
// Some columns might be wider than required. Widen all columns to preserve the relations.
|
||
|
RequiredWidthFactor := 100;
|
||
|
Count := 0;
|
||
|
Multi := 0;
|
||
|
for I := EndIndex downto StartIndex do
|
||
|
if (ColumnSpecs[I] = wtRelative) and (Multis[I] > 0) then
|
||
|
begin
|
||
|
Inc(Count);
|
||
|
Inc(Multi, Multis[I]);
|
||
|
RequiredWidthFactor := Max(RequiredWidthFactor, MulDiv(Widths[I], 100, Multis[I]));
|
||
|
end;
|
||
|
|
||
|
Required := MulDiv(RequiredWidthFactor, Multi, 100);
|
||
|
// building sum of all processed columns to reduce rounding errors.
|
||
|
AddedWidth := 0;
|
||
|
AddedMulti := 0;
|
||
|
for I := EndIndex downto StartIndex do
|
||
|
if (ColumnSpecs[I] = wtRelative) and (Multis[I] > 0) then
|
||
|
if Count > 1 then
|
||
|
begin
|
||
|
Inc(AddedMulti, Multis[I]);
|
||
|
Widths[I] := MulDiv(AddedMulti, RequiredWidthFactor, 100) - AddedWidth;
|
||
|
Inc(AddedWidth, Widths[I]);
|
||
|
Dec(Count);
|
||
|
end
|
||
|
else
|
||
|
begin
|
||
|
// add the remaining pixels to the first column's width.
|
||
|
Widths[I] := Required - AddedWidth;
|
||
|
break;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
var
|
||
|
// calculated values:
|
||
|
CellSpec: TWidthType;
|
||
|
CellMin, CellMax, CellPercent, CellRel: Integer;
|
||
|
SpannedMin, SpannedMax, SpannedMultis, SpannedPercents: Integer;
|
||
|
SpannedCounts: TIntegerPerWidthType;
|
||
|
|
||
|
procedure IncreaseMinMaxWidthsEvenly(WidthType: TWidthType; StartIndex, EndIndex: Integer);
|
||
|
var
|
||
|
Untouched, I: Integer;
|
||
|
begin
|
||
|
if CellMin > SpannedMin then
|
||
|
begin
|
||
|
Untouched := SumOfNotType(WidthType, ColumnSpecs, MinWidths, StartIndex, EndIndex);
|
||
|
IncreaseWidthsEvenly(WidthType, MinWidths, StartIndex, EndIndex, CellMin - Untouched, SpannedMin - Untouched, SpannedCounts[WidthType]);
|
||
|
end;
|
||
|
if CellMax > SpannedMax then
|
||
|
begin
|
||
|
Untouched := SumOfNotType(WidthType, ColumnSpecs, MinWidths, StartIndex, EndIndex);
|
||
|
IncreaseWidthsEvenly(WidthType, MaxWidths, StartIndex, EndIndex, CellMax - Untouched, SpannedMax - Untouched, SpannedCounts[WidthType]);
|
||
|
end;
|
||
|
|
||
|
// Prevent MinWidths from getting larger than MaxWidths, otherwise the calculation goes crazy
|
||
|
for I := StartIndex to EndIndex do
|
||
|
if MinWidths[I] > MaxWidths[I] then
|
||
|
MaxWidths[I] := MinWidths[I];
|
||
|
end;
|
||
|
|
||
|
procedure IncreaseMinMaxWidthsByMinMaxDelta(WidthType: TWidthType; StartIndex, EndIndex: Integer);
|
||
|
var
|
||
|
Deltas: TIntArray;
|
||
|
I: Integer;
|
||
|
begin
|
||
|
Deltas := SubArray(MaxWidths, MinWidths);
|
||
|
if CellMin > SpannedMin then
|
||
|
IncreaseWidthsByMinMaxDelta(WidthType, MinWidths, StartIndex, EndIndex, CellMin - SpannedMin, SpannedMax - SpannedMin, SpannedCounts[WidthType], Deltas);
|
||
|
if CellMax > SpannedMax then
|
||
|
IncreaseWidthsByMinMaxDelta(WidthType, MaxWidths, StartIndex, EndIndex, CellMax - SpannedMax, SpannedMax - SpannedMin, SpannedCounts[WidthType], Deltas);
|
||
|
|
||
|
// Prevent MinWidths from getting larger than MaxWidths, otherwise the calculation goes crazy
|
||
|
for I := StartIndex to EndIndex do
|
||
|
if MinWidths[I] > MaxWidths[I] then
|
||
|
MaxWidths[I] := MinWidths[I];
|
||
|
end;
|
||
|
|
||
|
var
|
||
|
//
|
||
|
I, J, K, Span, EndIndex: Integer;
|
||
|
Cells: TfrxHtCellList;
|
||
|
CellObj: TfrxHtfrcHtCellObjBase;
|
||
|
MaxSpans: TIntArray;
|
||
|
MaxSpan: Integer;
|
||
|
MultiCount: Integer;
|
||
|
begin
|
||
|
// initialize default widths
|
||
|
SetArray(ColumnCounts, 0);
|
||
|
if FColSpecs <> nil then
|
||
|
J := FColSpecs.Count
|
||
|
else
|
||
|
J := 0;
|
||
|
MultiCount := 0;
|
||
|
for I := 0 to NumCols - 1 do
|
||
|
begin
|
||
|
MinWidths[I] := 0;
|
||
|
MaxWidths[I] := 0;
|
||
|
Percents[I] := 0;
|
||
|
Multis[I] := 0;
|
||
|
ColumnSpecs[I] := wtNone;
|
||
|
if I < J then
|
||
|
with FColSpecs[I].FWidth do
|
||
|
begin
|
||
|
ColumnSpecs[I] := VType;
|
||
|
Inc(ColumnCounts[VType]);
|
||
|
case VType of
|
||
|
wtAbsolute:
|
||
|
begin
|
||
|
MinWidths[I] := Value;
|
||
|
MaxWidths[I] := Value;
|
||
|
end;
|
||
|
|
||
|
wtPercent:
|
||
|
Percents[I] := Value;
|
||
|
|
||
|
wtRelative:
|
||
|
begin
|
||
|
Multis[I] := Value;
|
||
|
if Value > 0 then
|
||
|
Inc(MultiCount);
|
||
|
end;
|
||
|
end;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
if FOwnerTableBlock.RTL then
|
||
|
begin
|
||
|
Reverse(MinWidths);
|
||
|
Reverse(MaxWidths);
|
||
|
Reverse(Percents);
|
||
|
Reverse(Multis);
|
||
|
Reverse(ColumnSpecs);
|
||
|
end;
|
||
|
|
||
|
//SetLength(Heights, 0);
|
||
|
Span := 1;
|
||
|
|
||
|
//BG, 29.01.2011: data for loop termination and to speed up looping through
|
||
|
// very large tables with large spans.
|
||
|
// A table with 77 rows and 265 columns and a MaxSpan of 265 in 2 rows
|
||
|
// was processed in 3 seconds before the tuning and 80ms afterwards.
|
||
|
MaxSpan := 1;
|
||
|
SetLength(MaxSpans, Rows.Count);
|
||
|
SetArray(MaxSpans, MaxSpan);
|
||
|
repeat
|
||
|
for J := 0 to Rows.Count - 1 do
|
||
|
begin
|
||
|
//BG, 29.01.2011: tuning: process rows only, if there is at least 1 cell to process left.
|
||
|
if Span > MaxSpans[J] then
|
||
|
continue;
|
||
|
|
||
|
Cells := Rows[J];
|
||
|
//BG, 29.01.2011: tuning: process up to cells only, if there is at least 1 cell to process left.
|
||
|
for I := 0 to Cells.Count - Span do
|
||
|
begin
|
||
|
CellObj := Cells[I];
|
||
|
if CellObj = nil then
|
||
|
continue;
|
||
|
|
||
|
if CellObj.ColSpan = Span then
|
||
|
begin
|
||
|
// get min and max width of this cell:
|
||
|
CellObj.Cell.MinMaxWidth(Canvas, CellMin, CellMax, 0, 0);
|
||
|
CellPercent := 0;
|
||
|
CellRel := 0;
|
||
|
with CellObj.SpecWd do
|
||
|
begin
|
||
|
CellSpec := VType;
|
||
|
case VType of
|
||
|
wtPercent:
|
||
|
CellPercent := Value;
|
||
|
|
||
|
wtAbsolute:
|
||
|
begin
|
||
|
// BG, 07.10.2012: issue 55: wrong CellMax calculation
|
||
|
//CellMin := Max(CellMin, Value); // CellMin should be at least the given absolute value
|
||
|
//CellMax := Min(CellMax, Value); // CellMax should be at most the given absolute value
|
||
|
CellMax := Value; // CellMax should be at most the given absolute value
|
||
|
CellMax := Max(CellMax, CellMin); // CellMax should be at least CellMin
|
||
|
end;
|
||
|
|
||
|
wtRelative:
|
||
|
CellRel := Value;
|
||
|
end;
|
||
|
end;
|
||
|
Inc(CellMin, CellSpacingHorz + CellObj.HzSpace);
|
||
|
Inc(CellMax, CellSpacingHorz + CellObj.HzSpace);
|
||
|
|
||
|
if Span = 1 then
|
||
|
begin
|
||
|
MinWidths[I] := Max(MinWidths[I], CellMin);
|
||
|
MaxWidths[I] := Max(MaxWidths[I], CellMax);
|
||
|
Percents[I] := Max(Percents[I], CellPercent); {collect percents}
|
||
|
Multis[I] := Max(Multis[I], CellRel);
|
||
|
UpdateColumnSpec(ColumnCounts, ColumnSpecs[I], CellSpec);
|
||
|
end
|
||
|
else
|
||
|
begin
|
||
|
EndIndex := I + Span - 1;
|
||
|
|
||
|
// Get current min and max width of spanned columns.
|
||
|
SpannedMin := Sum(MinWidths, I, EndIndex);
|
||
|
SpannedMax := Sum(MaxWidths, I, EndIndex);
|
||
|
|
||
|
if (CellMin > SpannedMin) or (CellMax > SpannedMax) then
|
||
|
begin
|
||
|
{ As spanning cell is wider than sum of spanned columns, we must widen the spanned columns.
|
||
|
|
||
|
How to add the excessive width:
|
||
|
a) If cell spans columns without any width specifications, then spread excessive width evenly to these columns.
|
||
|
b) If cell spans columns with relative specifications, then spread excessive width according
|
||
|
to relative width values to these columns.
|
||
|
c) If cell spans columns with precentage specifications, then spread excessive width relative
|
||
|
to percentages to these columns.
|
||
|
d) If cell spans columns with absolute specifications only, then spread excessive width relative
|
||
|
to difference between MinWidth and MaxWidth to all columns.
|
||
|
|
||
|
see also:
|
||
|
- http://www.w3.org/TR/html401/struct/tables.html
|
||
|
- http://www.w3.org/TR/html401/appendix/notes.html#h-B.5.2
|
||
|
Notice:
|
||
|
- Fixed Layout: experiments showed that IExplore and Firefox *do* respect width attributes of <td> and <th>
|
||
|
even if there was a <colgroup> definition although W3C specified differently.
|
||
|
}
|
||
|
CountsPerType(SpannedCounts, ColumnSpecs, I, EndIndex);
|
||
|
|
||
|
if CellPercent > 0 then
|
||
|
begin
|
||
|
SpannedPercents := SumOfType(wtPercent, ColumnSpecs, Percents, I, EndIndex);
|
||
|
if SpannedPercents > CellPercent then
|
||
|
continue;
|
||
|
|
||
|
// BG, 05.02.2012: spread excessive percentage over unspecified columns:
|
||
|
if SpannedCounts[wtNone] > 0 then
|
||
|
begin
|
||
|
// a) There is at least 1 column without any width constraint: Widen this/these.
|
||
|
IncreaseWidthsEvenly(wtNone, Percents, I, EndIndex, CellPercent - SpannedPercents, 0, SpannedCounts[wtNone]);
|
||
|
for K := I to EndIndex do
|
||
|
ColumnSpecs[K] := wtPercent;
|
||
|
continue;
|
||
|
end
|
||
|
end;
|
||
|
|
||
|
if SpannedCounts[wtNone] > 0 then
|
||
|
begin
|
||
|
// a) There is at least 1 column without any width constraint: Widen this/these.
|
||
|
IncreaseMinMaxWidthsEvenly(wtNone, I, EndIndex);
|
||
|
end
|
||
|
else if SpannedCounts[wtRelative] > 0 then
|
||
|
begin
|
||
|
// b) There is at least 1 column with relative width: Widen this/these.
|
||
|
SpannedMultis := SumOfType(wtRelative, ColumnSpecs, Multis, I, EndIndex);
|
||
|
if SpannedMultis > 0 then
|
||
|
begin
|
||
|
if CellMin > SpannedMin then
|
||
|
IncreaseWidthsRelatively(MinWidths, I, EndIndex, CellMin, SpannedMultis, True);
|
||
|
if CellMax > SpannedMax then
|
||
|
IncreaseWidthsRelatively(MaxWidths, I, EndIndex, CellMax, SpannedMultis, True);
|
||
|
end
|
||
|
else if SpannedMax > SpannedMin then
|
||
|
begin
|
||
|
// All spanned columns are at 0*.
|
||
|
// Widen columns proportional to difference between yet evaluated min and max width.
|
||
|
// This ought to fill the table with least height requirements.
|
||
|
IncreaseMinMaxWidthsByMinMaxDelta(wtRelative, I, EndIndex);
|
||
|
end
|
||
|
else
|
||
|
begin
|
||
|
// All spanned columns are at 0* and minimum = maximum. Spread excess evenly.
|
||
|
IncreaseMinMaxWidthsEvenly(wtRelative, I, EndIndex);
|
||
|
end;
|
||
|
end
|
||
|
else if SpannedCounts[wtPercent] > 0 then
|
||
|
begin
|
||
|
// c) There is at least 1 column with percentage width: Widen this/these.
|
||
|
if SpannedMax > SpannedMin then
|
||
|
begin
|
||
|
// Widen columns proportional to difference between yet evaluated min and max width.
|
||
|
// This ought to fill the table with least height requirements.
|
||
|
IncreaseMinMaxWidthsByMinMaxDelta(wtPercent, I, EndIndex);
|
||
|
end
|
||
|
else
|
||
|
begin
|
||
|
SpannedPercents := SumOfType(wtPercent, ColumnSpecs, Percents, I, EndIndex);
|
||
|
if SpannedPercents > 0 then
|
||
|
begin
|
||
|
// Spread excess to columns proportionally to their percentages.
|
||
|
// This ought to keep smaller columns small.
|
||
|
if CellMin > SpannedMin then
|
||
|
IncreaseWidthsByPercentage(MinWidths, I, EndIndex, CellMin, SpannedMin, SpannedPercents, SpannedCounts[wtPercent]);
|
||
|
if CellMax > SpannedMax then
|
||
|
IncreaseWidthsByPercentage(MaxWidths, I, EndIndex, CellMax, SpannedMax, SpannedPercents, SpannedCounts[wtPercent]);
|
||
|
end
|
||
|
else
|
||
|
begin
|
||
|
// All spanned columns are at 0% and minimum = maximum. Spread excess evenly.
|
||
|
IncreaseMinMaxWidthsEvenly(wtPercent, I, EndIndex);
|
||
|
end;
|
||
|
end;
|
||
|
end
|
||
|
else
|
||
|
begin
|
||
|
// d) All columns have absolute widths: Widen these.
|
||
|
IncreaseMinMaxWidthsEvenly(wtAbsolute, I, EndIndex);
|
||
|
end;
|
||
|
end;
|
||
|
end;
|
||
|
end
|
||
|
else
|
||
|
begin
|
||
|
//BG, 29.01.2011: at this point: CellObj.ColSpan <> Span
|
||
|
if Span = 1 then
|
||
|
begin
|
||
|
//BG, 29.01.2011: at this point: in the first loop with a CellObj.ColSpan > 1.
|
||
|
|
||
|
// Collect data for termination and tuning.
|
||
|
if MaxSpans[J] < CellObj.ColSpan then
|
||
|
begin
|
||
|
MaxSpans[J] := CellObj.ColSpan; // data for tuning
|
||
|
if MaxSpan < MaxSpans[J] then
|
||
|
MaxSpan := MaxSpans[J]; // data for termination
|
||
|
end;
|
||
|
end;
|
||
|
end;
|
||
|
end;
|
||
|
end;
|
||
|
Inc(Span);
|
||
|
until Span > MaxSpan;
|
||
|
|
||
|
if MultiCount > 0 then
|
||
|
begin
|
||
|
UpdateRelativeWidths(MinWidths, ColumnSpecs, 0, NumCols - 1);
|
||
|
UpdateRelativeWidths(MaxWidths, ColumnSpecs, 0, NumCols - 1);
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
{----------------TfrxHtmlTable.MinMaxWidth}
|
||
|
|
||
|
procedure TfrxHtmlTable.MinMaxWidth(Canvas: TCanvas; out Min, Max: Integer; AvailableWidth, AvailableHeight: Integer);
|
||
|
begin
|
||
|
Initialize; {in case it hasn't been done}
|
||
|
GetMinMaxWidths(Canvas, AvailableWidth, AvailableHeight);
|
||
|
Min := Math.Max(Sum(MinWidths) + CellSpacingHorz, tblWidthAttr);
|
||
|
Max := Math.Max(Sum(MaxWidths) + CellSpacingHorz, tblWidthAttr);
|
||
|
|
||
|
if FOwnerTableBlock.MargArray[piMinWidth] > 0 then
|
||
|
begin
|
||
|
Min := Math.Max(Min, FOwnerTableBlock.MargArray[piMinWidth]);
|
||
|
Max := Math.Max(Max, FOwnerTableBlock.MargArray[piMinWidth]);
|
||
|
end;
|
||
|
|
||
|
if FOwnerTableBlock.MargArray[piMaxWidth] > 0 then
|
||
|
begin
|
||
|
Min := Math.Min(Min, FOwnerTableBlock.MargArray[piMaxWidth]);
|
||
|
Max := Math.Min(Max, FOwnerTableBlock.MargArray[piMaxWidth]);
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
procedure TfrxHtmlTable.Reverse(A: TWidthTypeArray);
|
||
|
var
|
||
|
i, j: Integer;
|
||
|
t: TWidthType;
|
||
|
begin
|
||
|
for i := 0 to Length(A) div 2 - 1 do
|
||
|
begin
|
||
|
j := Length(A) - i - 1;
|
||
|
t := A[i];
|
||
|
A[i] := A[j];
|
||
|
A[j] := t;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
procedure TfrxHtmlTable.Reverse(A: TIntArray);
|
||
|
var
|
||
|
i, j: Integer;
|
||
|
t: Integer;
|
||
|
begin
|
||
|
for i := 0 to Length(A) div 2 - 1 do
|
||
|
begin
|
||
|
j := Length(A) - i - 1;
|
||
|
t := A[i];
|
||
|
A[i] := A[j];
|
||
|
A[j] := t;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
{----------------TfrxHtmlTable.DrawLogic}
|
||
|
|
||
|
function TfrxHtmlTable.DrawLogic1(Canvas: TCanvas; X, Y, XRef, YRef, AWidth, AHeight, BlHt: Integer; IMgr: TfrxHtIndentManager;
|
||
|
var MaxWidth, Curs: Integer; ARemainHeight: Integer): Integer;
|
||
|
|
||
|
function FindTableWidth: Integer;
|
||
|
|
||
|
procedure IncreaseWidths(WidthType: TWidthType; MinWidth, NewWidth, Count: Integer);
|
||
|
var
|
||
|
Deltas: TIntArray;
|
||
|
D, W: Integer;
|
||
|
begin
|
||
|
Deltas := SubArray(MaxWidths, MinWidths);
|
||
|
D := SumOfType(WidthType, ColumnSpecs, Deltas, 0, NumCols - 1);
|
||
|
if D <> 0 then
|
||
|
IncreaseWidthsByMinMaxDelta(WidthType, Widths, 0, NumCols - 1, NewWidth - MinWidth, D, Count, Deltas)
|
||
|
else
|
||
|
begin
|
||
|
W := SumOfType(WidthType, ColumnSpecs, Widths, 0, NumCols -1);
|
||
|
IncreaseWidthsByWidth(WidthType, Widths, 0, NumCols - 1, NewWidth - MinWidth + W, W, Count);
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
procedure CalcPercentDeltas(var PercentDeltas: TIntArray; NewWidth: Integer);
|
||
|
var
|
||
|
I: Integer;
|
||
|
Percent, PercentDelta: Integer;
|
||
|
begin
|
||
|
Percent := Max(1000, Sum(Percents));
|
||
|
for I := NumCols - 1 downto 0 do
|
||
|
if ColumnSpecs[I] = wtPercent then
|
||
|
begin
|
||
|
PercentDelta := Trunc(1000 * (Percents[I] / Percent - MinWidths[I] / NewWidth));
|
||
|
if PercentDelta > 0 then
|
||
|
PercentDeltas[I] := PercentDelta;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
procedure IncreaseWidthsByPercentage(var Widths: TIntArray;
|
||
|
const PercentDeltas: TIntArray;
|
||
|
StartIndex, EndIndex, Required, Spanned, Percent, Count: Integer);
|
||
|
// Increases width of columns relative to given percentages.
|
||
|
var
|
||
|
Excess, AddedExcess, AddedPercent, I, Add, MaxColWidth, SpecPercent: Integer;
|
||
|
begin
|
||
|
SpecPercent := Max(1000, Sum(Percents));
|
||
|
Excess := Required - Spanned;
|
||
|
AddedExcess := 0;
|
||
|
AddedPercent := 0;
|
||
|
for I := EndIndex downto StartIndex do
|
||
|
if (ColumnSpecs[I] = wtPercent) and (PercentDeltas[I] > 0) then
|
||
|
if Count > 1 then
|
||
|
begin
|
||
|
Inc(AddedPercent, PercentDeltas[I]);
|
||
|
Add := MulDiv(Excess, AddedPercent, Percent) - AddedExcess;
|
||
|
MaxColWidth := MulDiv(Required, Percents[I], SpecPercent);
|
||
|
Widths[I] := Min(Widths[I] + Add, MaxColWidth);
|
||
|
Inc(AddedExcess, Add);
|
||
|
Dec(Count);
|
||
|
end
|
||
|
else
|
||
|
begin
|
||
|
// add the remaining pixels to the first column's width.
|
||
|
Add := Excess - AddedExcess;
|
||
|
MaxColWidth := MulDiv(Required, Percents[I], SpecPercent);
|
||
|
Widths[I] := Min(Widths[I] + Add, MaxColWidth);
|
||
|
break;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
var
|
||
|
Specified: Boolean;
|
||
|
NewWidth, MaxWidth, MinWidth, D, W, I: Integer;
|
||
|
Counts: TIntegerPerWidthType;
|
||
|
PercentDeltas: TIntArray;
|
||
|
PercentAbove0Count: Integer;
|
||
|
PercentDeltaAbove0Count: Integer;
|
||
|
begin
|
||
|
Specified := tblWidthAttr > 0;
|
||
|
if Specified then
|
||
|
NewWidth := tblWidthAttr
|
||
|
else
|
||
|
NewWidth := IMgr.RightSide(Y) - IMgr.LeftIndent(Y);
|
||
|
Dec(NewWidth, CellSpacingHorz);
|
||
|
|
||
|
Initialize;
|
||
|
|
||
|
{Figure the width of each column}
|
||
|
GetMinMaxWidths(Canvas, AWidth, AHeight);
|
||
|
|
||
|
MinWidth := Sum(MinWidths);
|
||
|
if FOwnerTableBlock.MargArray[piMinWidth] > 0 then
|
||
|
MinWidth := Max(MinWidth, FOwnerTableBlock.MargArray[piMinWidth]);
|
||
|
|
||
|
MaxWidth := Sum(MaxWidths);
|
||
|
if FOwnerTableBlock.MargArray[piMaxWidth] > 0 then
|
||
|
MaxWidth := Min(MaxWidth, FOwnerTableBlock.MargArray[piMaxWidth]);
|
||
|
|
||
|
{fill in the Widths array}
|
||
|
if MinWidth > NewWidth then
|
||
|
// The minimum table width is too wide. Thus use minimum widths, table might expand.
|
||
|
Widths := Copy(MinWidths)
|
||
|
else
|
||
|
begin
|
||
|
// Table fits into NewWidth.
|
||
|
|
||
|
Counts[wtPercent] := 0;
|
||
|
PercentAbove0Count := 0;
|
||
|
for I := 0 to NumCols - 1 do
|
||
|
if ColumnSpecs[I] = wtPercent then
|
||
|
begin
|
||
|
Inc(Counts[wtPercent]);
|
||
|
if Percents[I] > 0 then
|
||
|
Inc(PercentAbove0Count);
|
||
|
end;
|
||
|
|
||
|
Widths := Copy(MinWidths);
|
||
|
|
||
|
// As minimum widths fit into table try to preserve given absolute widths:
|
||
|
Counts[wtAbsolute] := 0;
|
||
|
W := 0;
|
||
|
for I := 0 to NumCols - 1 do
|
||
|
begin
|
||
|
case ColumnSpecs[I] of
|
||
|
wtAbsolute:
|
||
|
begin
|
||
|
Widths[i] := MaxWidths[i];
|
||
|
Inc(Counts[wtAbsolute]);
|
||
|
end;
|
||
|
end;
|
||
|
Inc(W, Widths[i]);
|
||
|
end;
|
||
|
|
||
|
if W > NewWidth then
|
||
|
begin
|
||
|
// Given absolute widths plus minimum widths of other columns do not fit into table!
|
||
|
// Thus reduce the absolute widths as less as possible:
|
||
|
|
||
|
IncreaseWidths(wtAbsolute, W, NewWidth, Counts[wtAbsolute]);
|
||
|
end
|
||
|
else
|
||
|
begin
|
||
|
if (PercentAbove0Count > 0) and (NewWidth > 0) then
|
||
|
begin
|
||
|
// Calculate widths with respect to percentage specifications.
|
||
|
// Don't shrink Column i below MinWidth[i]! Therefor spread exessive space
|
||
|
// trying to fit the percentage demands.
|
||
|
// If there are more than 100% percent reduce linearly to 100% (including
|
||
|
// the corresponding percentages of the MinWidth of all other columns).
|
||
|
SetLength(PercentDeltas, NumCols);
|
||
|
CalcPercentDeltas(PercentDeltas, NewWidth);
|
||
|
|
||
|
PercentDeltaAbove0Count := 0;
|
||
|
for I := 0 to NumCols - 1 do
|
||
|
if PercentDeltas[I] > 0 then
|
||
|
Inc(PercentDeltaAbove0Count);
|
||
|
|
||
|
IncreaseWidthsByPercentage(Widths, PercentDeltas, 0, NumCols - 1, NewWidth, MinWidth, Sum(PercentDeltas), PercentDeltaAbove0Count);
|
||
|
end;
|
||
|
MinWidth := Sum(Widths);
|
||
|
|
||
|
if MinWidth > NewWidth then
|
||
|
// Table (NewWidth) is too small for given percentage specifications.
|
||
|
// Shrink percentage columns to fit exactly into NewWidth. All other columns are at minimum.
|
||
|
IncreaseWidths(wtPercent, MinWidth, NewWidth, Counts[wtPercent])
|
||
|
else if not Specified and (MaxWidth <= NewWidth) then
|
||
|
// Table width not specified and maximum widths fits into available width, table might be smaller than NewWidth
|
||
|
Widths := Copy(MaxWidths)
|
||
|
else if MinWidth < NewWidth then
|
||
|
begin
|
||
|
// Expand columns to fit exactly into NewWidth.
|
||
|
// Prefer widening columns without or with relative specification.
|
||
|
CountsPerType(Counts, ColumnSpecs, 0, NumCols - 1);
|
||
|
|
||
|
if Counts[wtNone] > 0 then
|
||
|
begin
|
||
|
// a) There is at least 1 column without any width constraint: modify this/these.
|
||
|
IncreaseWidths(wtNone, MinWidth, NewWidth, Counts[wtNone]);
|
||
|
end
|
||
|
else if Counts[wtRelative] > 0 then
|
||
|
begin
|
||
|
// b) There is at least 1 column with relative width: modify this/these.
|
||
|
W := NewWidth - MinWidth;
|
||
|
D := SumOfType(wtRelative, ColumnSpecs, Widths, 0, NumCols - 1);
|
||
|
IncreaseWidthsRelatively(Widths, 0, NumCols - 1, D + W, Sum(Multis), False);
|
||
|
end
|
||
|
else if Counts[wtPercent] > 0 then
|
||
|
begin
|
||
|
// c) There is at least 1 column with percentage width: modify this/these.
|
||
|
IncreaseWidths(wtPercent, MinWidth, NewWidth, Counts[wtPercent]);
|
||
|
end
|
||
|
else
|
||
|
begin
|
||
|
// d) All columns have absolute widths: modify relative to current width.
|
||
|
IncreaseWidths(wtAbsolute, MinWidth, NewWidth, Counts[wtAbsolute]);
|
||
|
end;
|
||
|
end;
|
||
|
end;
|
||
|
end;
|
||
|
{Return Table Width}
|
||
|
Result := CellSpacingHorz + Sum(Widths);
|
||
|
end;
|
||
|
|
||
|
function FindTableHeight: Integer;
|
||
|
|
||
|
procedure FindRowHeights(Canvas: TCanvas; AHeight: Integer);
|
||
|
var
|
||
|
I, J, K, H, Span, TotalMinHt, TotalDesHt, AvailHt, AddOn, Sum, AddedOn, Desired, UnSpec: Integer;
|
||
|
More, Mr, IsSpeced: Boolean;
|
||
|
MinHts, DesiredHts: TIntArray;
|
||
|
SpecHts: array of Boolean;
|
||
|
F: double;
|
||
|
begin
|
||
|
if Rows.Count = 0 then
|
||
|
Exit;
|
||
|
|
||
|
Dec(AHeight, CellSpacingVert); {calculated heights will include one cellspacing each,
|
||
|
this removes that last odd cellspacing}
|
||
|
SetLength(Heights, Rows.Count);
|
||
|
SetLength(DesiredHts, Rows.Count);
|
||
|
SetLength(MinHts, Rows.Count);
|
||
|
SetLength(SpecHts, Rows.Count);
|
||
|
for I := 0 to Rows.Count - 1 do
|
||
|
begin
|
||
|
Heights[I] := 0;
|
||
|
DesiredHts[I] := 0;
|
||
|
MinHts[I] := 0;
|
||
|
SpecHts[I] := False;
|
||
|
end;
|
||
|
{Find the height of each row allowing for RowSpans}
|
||
|
Span := 1;
|
||
|
More := True;
|
||
|
AvailHt := Max(0, AHeight - Rows.Count * CellSpacingVert);
|
||
|
while More do
|
||
|
begin
|
||
|
More := False;
|
||
|
for J := 0 to Rows.Count - 1 do
|
||
|
with Rows[J] do
|
||
|
begin
|
||
|
if J + Span > Rows.Count then
|
||
|
Break; {otherwise will overlap}
|
||
|
H := DrawLogicA(Canvas, Widths, Span, CellSpacingHorz, CellSpacingVert, AvailHt, Rows.Count, Desired, IsSpeced, Mr) + CellSpacingVert;
|
||
|
Inc(Desired, CellspacingVert);
|
||
|
More := More or Mr;
|
||
|
if Span = 1 then
|
||
|
begin
|
||
|
MinHts[J] := H;
|
||
|
DesiredHts[J] := Desired;
|
||
|
SpecHts[J] := SpecHts[J] or IsSpeced;
|
||
|
end
|
||
|
else if H > CellspacingVert then {if H=Cellspacing then no rowspan for this span}
|
||
|
begin
|
||
|
TotalMinHt := 0; {sum up the heights so far for the rows involved}
|
||
|
TotalDesHt := 0;
|
||
|
for K := J to J + Span - 1 do
|
||
|
begin
|
||
|
Inc(TotalMinHt, MinHts[K]);
|
||
|
Inc(TotalDesHt, DesiredHts[K]);
|
||
|
SpecHts[K] := SpecHts[K] or IsSpeced;
|
||
|
end;
|
||
|
if H > TotalMinHt then {apportion the excess over the rows}
|
||
|
begin
|
||
|
Addon := ((H - TotalMinHt) div Span);
|
||
|
AddedOn := 0;
|
||
|
for K := J to J + Span - 1 do
|
||
|
begin
|
||
|
Inc(MinHts[K], Addon);
|
||
|
Inc(AddedOn, Addon);
|
||
|
end;
|
||
|
Inc(MinHts[J + Span - 1], (H - TotalMinHt) - AddedOn); {make up for round off error}
|
||
|
end;
|
||
|
if Desired > TotalDesHt then {apportion the excess over the rows}
|
||
|
begin
|
||
|
Addon := ((Desired - TotalDesHt) div Span);
|
||
|
AddedOn := 0;
|
||
|
for K := J to J + Span - 1 do
|
||
|
begin
|
||
|
Inc(DesiredHts[K], Addon);
|
||
|
Inc(AddedOn, Addon);
|
||
|
end;
|
||
|
Inc(DesiredHts[J + Span - 1], (Desired - TotalDesHt) - AddedOn); {make up for round off error}
|
||
|
end;
|
||
|
end;
|
||
|
end;
|
||
|
Inc(Span);
|
||
|
end;
|
||
|
|
||
|
TotalMinHt := 0;
|
||
|
TotalDesHt := 0;
|
||
|
UnSpec := 0;
|
||
|
for I := 0 to Rows.Count - 1 do
|
||
|
begin
|
||
|
Inc(TotalMinHt, MinHts[I]);
|
||
|
Inc(TotalDesHt, DesiredHts[I]);
|
||
|
if not SpecHts[I] then
|
||
|
Inc(UnSpec);
|
||
|
end;
|
||
|
|
||
|
if TotalMinHt >= AHeight then
|
||
|
Heights := Copy(MinHts)
|
||
|
else if TotalDesHt < AHeight then
|
||
|
begin
|
||
|
if UnSpec > 0 then
|
||
|
begin {expand the unspeced rows to fit}
|
||
|
Heights := Copy(DesiredHts);
|
||
|
Addon := (AHeight - TotalDesHt) div UnSpec;
|
||
|
Sum := 0;
|
||
|
for I := 0 to Rows.Count - 1 do
|
||
|
if not SpecHts[I] then
|
||
|
begin
|
||
|
Dec(UnSpec);
|
||
|
if UnSpec > 0 then
|
||
|
begin
|
||
|
Inc(Heights[I], AddOn);
|
||
|
Inc(Sum, Addon);
|
||
|
end
|
||
|
else
|
||
|
begin {last item, complete everything}
|
||
|
Inc(Heights[I], AHeight - TotalDesHt - Sum);
|
||
|
Break;
|
||
|
end;
|
||
|
end;
|
||
|
end
|
||
|
else if TotalDesHt > 0 then
|
||
|
begin {expand desired hts to fit}
|
||
|
Sum := 0;
|
||
|
F := AHeight / TotalDesHt;
|
||
|
for I := 0 to Rows.Count - 2 do
|
||
|
begin
|
||
|
Heights[I] := Round(F * DesiredHts[I]);
|
||
|
Inc(Sum, Heights[I]);
|
||
|
end;
|
||
|
Heights[Rows.Count - 1] := AHeight - Sum; {last row is the difference}
|
||
|
end
|
||
|
end
|
||
|
else if TotalDesHt - TotalMinHt <> 0 then
|
||
|
begin
|
||
|
Sum := 0;
|
||
|
F := (AHeight - TotalMinHt) / (TotalDesHt - TotalMinHt);
|
||
|
for I := 0 to Rows.Count - 2 do
|
||
|
begin
|
||
|
Heights[I] := MinHts[I] + Round(F * (DesiredHts[I] - MinHts[I]));
|
||
|
Inc(Sum, Heights[I]);
|
||
|
end;
|
||
|
Heights[Rows.Count - 1] := AHeight - Sum;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
var
|
||
|
I, J, K: Integer;
|
||
|
CellObj: TfrxHtCellObj;
|
||
|
HasBody: Boolean;
|
||
|
begin
|
||
|
// Find Row Heights
|
||
|
if (CycleNumber <> Document.CycleNumber) or (Length(Heights) = 0) then
|
||
|
FindRowHeights(Canvas, AHeight)
|
||
|
//else if Document.InLogic2 and (Document.TableNestLevel <= 10) then
|
||
|
// FindRowHeights(Canvas, AHeight)
|
||
|
;
|
||
|
|
||
|
Result := 0;
|
||
|
HeaderHeight := 0;
|
||
|
HeaderRowCount := 0;
|
||
|
FootHeight := 0;
|
||
|
FootStartRow := -1;
|
||
|
HasBody := False;
|
||
|
for J := 0 to Rows.Count - 1 do
|
||
|
with Rows[J] do
|
||
|
begin
|
||
|
RowHeight := Heights[J];
|
||
|
case RowType of
|
||
|
THead:
|
||
|
begin
|
||
|
Inc(HeaderRowCount);
|
||
|
Inc(HeaderHeight, RowHeight);
|
||
|
end;
|
||
|
|
||
|
TFoot:
|
||
|
begin
|
||
|
if FootStartRow = -1 then
|
||
|
begin
|
||
|
FootStartRow := J;
|
||
|
FootOffset := Result;
|
||
|
end;
|
||
|
Inc(FootHeight, RowHeight);
|
||
|
end;
|
||
|
|
||
|
TBody:
|
||
|
HasBody := True;
|
||
|
end;
|
||
|
RowSpanHeight := 0;
|
||
|
Inc(Result, RowHeight);
|
||
|
for I := 0 to Count - 1 do
|
||
|
if Items[I] is TfrxHtCellObj then
|
||
|
begin
|
||
|
CellObj := TfrxHtCellObj(Items[I]);
|
||
|
with CellObj do
|
||
|
begin {find the actual height, Ht, of each cell}
|
||
|
FHt := 0;
|
||
|
for K := J to Min(J + RowSpan - 1, Rows.Count - 1) do
|
||
|
Inc(FHt, Heights[K]);
|
||
|
if RowSpanHeight < FHt then
|
||
|
RowSpanHeight := FHt;
|
||
|
end;
|
||
|
end;
|
||
|
{DrawLogicB is only called in nested tables if the outer table is calling DrawLogic2}
|
||
|
if Document.TableNestLevel = 1 then
|
||
|
Document.InLogic2 := True;
|
||
|
try
|
||
|
if Document.InLogic2 then
|
||
|
DrawLogicB(Canvas, Y, CellSpacingHorz,CellSpacingVert, Curs);
|
||
|
finally
|
||
|
if Document.TableNestLevel = 1 then
|
||
|
Document.InLogic2 := False;
|
||
|
end;
|
||
|
Inc(Y, RowHeight);
|
||
|
end;
|
||
|
HeadOrFoot := ((HeaderHeight > 0) or (FootHeight > 0)) and HasBody;
|
||
|
Inc(Result, CellSpacingVert);
|
||
|
end;
|
||
|
|
||
|
procedure DrawLogicYIndent;
|
||
|
var
|
||
|
J: Integer;
|
||
|
begin
|
||
|
for J := 0 to Rows.Count - 1 do
|
||
|
with Rows[J] do
|
||
|
begin
|
||
|
RowHeight := Heights[J];
|
||
|
{DrawLogicB is only called in nested tables if the outer table is calling DrawLogic2}
|
||
|
DrawLogicB(Canvas, Y, CellSpacingHorz,CellSpacingVert, Curs);
|
||
|
Inc(Y, RowHeight);
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
var
|
||
|
TopY: Integer;
|
||
|
FirstLinePtr: PInteger;
|
||
|
begin {TfrxHtmlTable.DrawLogic}
|
||
|
Inc(Document.TableNestLevel);
|
||
|
try
|
||
|
if (CycleNumber <> Document.CycleNumber) or (YDraw <> Y) or (ContentTop <> Y) or (DrawTop <> Y) or (StartCurs <> Curs) or (Length(Heights) = 0)
|
||
|
then
|
||
|
begin
|
||
|
YDraw := Y;
|
||
|
TopY := Y;
|
||
|
ContentTop := Y;
|
||
|
DrawTop := Y;
|
||
|
StartCurs := Curs;
|
||
|
if Assigned(Document.FirstLineHtPtr) and {used for List items}
|
||
|
(Document.FirstLineHtPtr^ = 0) then
|
||
|
FirstLinePtr := Document.FirstLineHtPtr {save for later}
|
||
|
else
|
||
|
FirstLinePtr := nil;
|
||
|
|
||
|
TableWidth := FindTableWidth;
|
||
|
TableHeight := FindTableHeight;
|
||
|
// Notice: SectionHeight = TableHeight
|
||
|
Len := Curs - StartCurs;
|
||
|
DrawHeight := TableHeight;
|
||
|
ContentBot := TopY + TableHeight;
|
||
|
DrawBot := TopY + DrawHeight;
|
||
|
|
||
|
try
|
||
|
if Assigned(FirstLinePtr) then
|
||
|
FirstLinePtr^ := YDraw + SectionHeight;
|
||
|
except
|
||
|
end;
|
||
|
|
||
|
CycleNumber := Document.CycleNumber;
|
||
|
end
|
||
|
else
|
||
|
begin
|
||
|
if Document.TableNestLevel = 1 then
|
||
|
Document.InLogic2 := True;
|
||
|
try
|
||
|
if Document.InLogic2 then
|
||
|
DrawLogicYIndent
|
||
|
else
|
||
|
Curs := StartCurs + Len;
|
||
|
finally
|
||
|
if Document.TableNestLevel = 1 then
|
||
|
Document.InLogic2 := False;
|
||
|
end;
|
||
|
end;
|
||
|
finally
|
||
|
MaxWidth := TableWidth;
|
||
|
Result := TableHeight;
|
||
|
Dec(Document.TableNestLevel);
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
{----------------TfrxHtmlTable.Draw}
|
||
|
|
||
|
function TfrxHtmlTable.Draw1(Canvas: TCanvas; const ARect: TRect; IMgr: TfrxHtIndentManager; X, XRef, YRef: Integer): Integer;
|
||
|
|
||
|
procedure DrawTable(XX, YY, YOffset: Integer);
|
||
|
var
|
||
|
I: Integer;
|
||
|
begin
|
||
|
for I := 0 to Rows.Count - 1 do
|
||
|
YY := Rows[I].Draw(Canvas, Document, ARect, Widths,
|
||
|
XX, YY, YOffset, CellSpacingHorz,CellSpacingVert, BorderWidth > 0, BorderColorLight,
|
||
|
BorderColorDark, I);
|
||
|
end;
|
||
|
|
||
|
procedure DrawTableP(XX, YY, YOffset: Integer);
|
||
|
{Printing table with thead and/or tfoot}
|
||
|
var
|
||
|
TopBorder, BottomBorder: Integer;
|
||
|
SavePageBottom: Integer;
|
||
|
Spacing, HeightNeeded: Integer;
|
||
|
|
||
|
procedure DrawNormal;
|
||
|
var
|
||
|
Y, I: Integer;
|
||
|
begin
|
||
|
Y := YY;
|
||
|
Document.PrintingTable := Self;
|
||
|
if Document.PageBottom - Y >= TableHeight + BottomBorder then
|
||
|
begin
|
||
|
for I := 0 to Rows.Count - 1 do {do whole table now}
|
||
|
YY := Rows[I].Draw(Canvas, Document, ARect, Widths,
|
||
|
XX, YY, YOffset, CellSpacingHorz,CellSpacingVert, BorderWidth > 0, BorderColorLight,
|
||
|
BorderColorDark, I);
|
||
|
Document.PrintingTable := nil;
|
||
|
end
|
||
|
else
|
||
|
begin {see if enough room on this page for header, 1 row, footer}
|
||
|
if HeadOrFoot then
|
||
|
begin
|
||
|
Spacing := CellSpacingVert div 2;
|
||
|
HeightNeeded := HeaderHeight + FootHeight + Rows[HeaderRowCount].RowHeight;
|
||
|
if (Y - YOffset > ARect.Top) and (Y + HeightNeeded > Document.PageBottom) and
|
||
|
(HeightNeeded < ARect.Bottom - ARect.Top) then
|
||
|
begin {not enough room, start table on next page}
|
||
|
if YY + Spacing < Document.PageBottom then
|
||
|
begin
|
||
|
Document.PageShortened := True;
|
||
|
Document.PageBottom := YY + Spacing;
|
||
|
end;
|
||
|
exit;
|
||
|
end;
|
||
|
end;
|
||
|
{start table. it will not be complete and will go to next page}
|
||
|
SavePageBottom := Document.PageBottom;
|
||
|
Document.PageBottom := SavePageBottom - FootHeight - CellspacingVert - BottomBorder - 5; {a little to spare}
|
||
|
for I := 0 to Rows.Count - 1 do {do part of table}
|
||
|
YY := Rows[I].Draw(Canvas, Document, ARect, Widths,
|
||
|
XX, YY, YOffset, CellSpacingHorz, CellSpacingVert, BorderWidth > 0, BorderColorLight,
|
||
|
BorderColorDark, I);
|
||
|
BodyBreak := Document.PageBottom;
|
||
|
if FootStartRow >= 0 then
|
||
|
begin
|
||
|
TablePartRec.TablePart := DoFoot;
|
||
|
TablePartRec.PartStart := Y + FootOffset;
|
||
|
TablePartRec.PartHeight := FootHeight + Max(2 * CellspacingVert, CellspacingVert + 1) + BottomBorder;
|
||
|
Document.TheOwner.TablePartRec := TablePartRec;
|
||
|
end
|
||
|
else if HeaderHeight > 0 then
|
||
|
begin {will do header next}
|
||
|
//Document.PageBottom := SavePageBottom;
|
||
|
TablePartRec.TablePart := DoHead;
|
||
|
TablePartRec.PartStart := Y - TopBorder;
|
||
|
TablePartRec.PartHeight := HeaderHeight + TopBorder;
|
||
|
Document.TheOwner.TablePartRec := TablePartRec;
|
||
|
end;
|
||
|
Document.TheOwner.TablePartRec := TablePartRec;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
procedure DrawBody1;
|
||
|
var
|
||
|
Y, I: Integer;
|
||
|
begin
|
||
|
Y := YY;
|
||
|
if Document.PageBottom > Y + TableHeight + BottomBorder then
|
||
|
begin {can complete table now}
|
||
|
for I := 0 to Rows.Count - 1 do {do remainder of table now}
|
||
|
YY := Rows[I].Draw(Canvas, Document, ARect, Widths,
|
||
|
XX, YY, YOffset, CellSpacingHorz, CellSpacingVert, BorderWidth > 0, BorderColorLight,
|
||
|
BorderColorDark, I);
|
||
|
Document.TheOwner.TablePartRec.TablePart := Normal;
|
||
|
end
|
||
|
else
|
||
|
begin {will do part of the table now}
|
||
|
{Leave room for foot later}
|
||
|
Document.PageBottom := Document.PageBottom - FootHeight + Max(CellspacingVert, 1) - BottomBorder;
|
||
|
for I := 0 to Rows.Count - 1 do
|
||
|
YY := Rows[I].Draw(Canvas, Document, ARect, Widths,
|
||
|
XX, YY, YOffset, CellSpacingHorz, CellSpacingVert, BorderWidth > 0, BorderColorLight,
|
||
|
BorderColorDark, I);
|
||
|
BodyBreak := Document.PageBottom;
|
||
|
if FootStartRow >= 0 then
|
||
|
begin
|
||
|
TablePartRec.TablePart := DoFoot;
|
||
|
TablePartRec.PartStart := Y + FootOffset;
|
||
|
TablePartRec.PartHeight := FootHeight + Max(2 * CellspacingVert, CellspacingVert + 1) + BottomBorder;
|
||
|
Document.TheOwner.TablePartRec := TablePartRec;
|
||
|
end
|
||
|
else if HeaderHeight > 0 then
|
||
|
begin
|
||
|
TablePartRec.TablePart := DoHead;
|
||
|
TablePartRec.PartStart := Y - TopBorder;
|
||
|
TablePartRec.PartHeight := HeaderHeight + TopBorder;
|
||
|
Document.TheOwner.TablePartRec := TablePartRec;
|
||
|
end;
|
||
|
Document.TheOwner.TablePartRec := TablePartRec;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
procedure DrawBody2;
|
||
|
var
|
||
|
Y, I: Integer;
|
||
|
begin
|
||
|
Y := YY;
|
||
|
if Document.PageBottom > Y + TableHeight + BottomBorder then
|
||
|
begin
|
||
|
for I := 0 to Rows.Count - 1 do {do remainder of table now}
|
||
|
YY := Rows[I].Draw(Canvas, Document, ARect, Widths,
|
||
|
XX, YY, YOffset, CellSpacingHorz,CellSpacingVert, BorderWidth > 0, BorderColorLight,
|
||
|
BorderColorDark, I);
|
||
|
Document.TheOwner.TablePartRec.TablePart := Normal;
|
||
|
Document.PrintingTable := nil;
|
||
|
end
|
||
|
else
|
||
|
begin
|
||
|
SavePageBottom := Document.PageBottom;
|
||
|
for I := 0 to Rows.Count - 1 do {do part of table}
|
||
|
YY := Rows[I].Draw(Canvas, Document, ARect, Widths,
|
||
|
XX, YY, YOffset, CellSpacingHorz,CellSpacingVert, BorderWidth > 0, BorderColorLight,
|
||
|
BorderColorDark, I);
|
||
|
BodyBreak := Document.PageBottom;
|
||
|
if FootStartRow >= 0 then
|
||
|
begin
|
||
|
TablePartRec.TablePart := DoFoot;
|
||
|
TablePartRec.PartStart := Y + FootOffset;
|
||
|
TablePartRec.PartHeight := FootHeight + Max(2 * CellspacingVert, CellspacingVert + 1) + BottomBorder;
|
||
|
Document.TheOwner.TablePartRec := TablePartRec;
|
||
|
end
|
||
|
else if HeaderHeight > 0 then
|
||
|
begin
|
||
|
Document.PageBottom := SavePageBottom;
|
||
|
TablePartRec.TablePart := DoHead;
|
||
|
TablePartRec.PartStart := Y - TopBorder;
|
||
|
TablePartRec.PartHeight := HeaderHeight + TopBorder;
|
||
|
Document.TheOwner.TablePartRec := TablePartRec;
|
||
|
end;
|
||
|
Document.TheOwner.TablePartRec := TablePartRec;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
procedure DrawFoot;
|
||
|
var
|
||
|
Y, I: Integer;
|
||
|
begin
|
||
|
Y := YY;
|
||
|
YY := TablePartRec.PartStart;
|
||
|
if FootStartRow >= 0 then
|
||
|
for I := FootStartRow to Rows.Count - 1 do
|
||
|
YY := Rows[I].Draw(Canvas, Document, ARect, Widths,
|
||
|
XX, YY, YOffset, CellSpacingHorz, CellSpacingVert, BorderWidth > 0, BorderColorLight,
|
||
|
BorderColorDark, I);
|
||
|
if HeaderHeight > 0 then
|
||
|
begin
|
||
|
TablePartRec.TablePart := DoHead;
|
||
|
TablePartRec.PartStart := Y - TopBorder;
|
||
|
TablePartRec.PartHeight := HeaderHeight + TopBorder;
|
||
|
end
|
||
|
else
|
||
|
begin {No THead}
|
||
|
TablePartRec.TablePart := DoBody3;
|
||
|
TablePartRec.PartStart := BodyBreak - 1;
|
||
|
TablePartRec.FootHeight := FootHeight + Max(CellspacingVert, 1);
|
||
|
end;
|
||
|
Document.TheOwner.TablePartRec := TablePartRec;
|
||
|
end;
|
||
|
|
||
|
procedure DrawHead;
|
||
|
var
|
||
|
I: Integer;
|
||
|
begin
|
||
|
for I := 0 to HeaderRowCount - 1 do
|
||
|
YY := Rows[I].Draw(Canvas, Document, ARect, Widths,
|
||
|
XX, YY, YOffset, CellSpacingHorz,CellSpacingVert, BorderWidth > 0, BorderColorLight,
|
||
|
BorderColorDark, I);
|
||
|
TablePartRec.TablePart := DoBody1;
|
||
|
TablePartRec.PartStart := BodyBreak - 1;
|
||
|
TablePartRec.FootHeight := FootHeight + Max(CellspacingVert, 1) + BottomBorder;
|
||
|
Document.TheOwner.TablePartRec := TablePartRec;
|
||
|
end;
|
||
|
|
||
|
begin
|
||
|
if TfrxHtTableBlock(OwnerBlock).TableBorder then
|
||
|
begin
|
||
|
TopBorder := BorderWidth;
|
||
|
BottomBorder := BorderWidth;
|
||
|
end
|
||
|
else
|
||
|
begin
|
||
|
TopBorder := OwnerBlock.MargArray[BorderTopWidth];
|
||
|
BottomBorder := OwnerBlock.MargArray[BorderBottomWidth];
|
||
|
end;
|
||
|
|
||
|
case TablePartRec.TablePart of
|
||
|
Normal: DrawNormal;
|
||
|
DoBody1: DrawBody1;
|
||
|
DoBody2: DrawBody2;
|
||
|
DoFoot: DrawFoot;
|
||
|
DoHead: DrawHead;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
var
|
||
|
Y, YO, YOffset: Integer;
|
||
|
begin
|
||
|
Inc(Document.TableNestLevel);
|
||
|
try
|
||
|
Y := YDraw;
|
||
|
Result := Y + SectionHeight;
|
||
|
YOffset := Document.YOff;
|
||
|
YO := Y - YOffset;
|
||
|
|
||
|
DrawX := X;
|
||
|
//DrawY := Y;
|
||
|
|
||
|
if (YO + DrawHeight >= ARect.Top) and (YO < ARect.Bottom) then
|
||
|
DrawTable(X, Y, YOffset);
|
||
|
finally
|
||
|
Dec(Document.TableNestLevel);
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
{----------------TfrxHtmlTable.GetChAtPos}
|
||
|
|
||
|
function TfrxHtmlTable.GetChAtPos(Pos: Integer; out Ch: WideChar; out Obj: TfrxHtSectionBase): Boolean;
|
||
|
var
|
||
|
I, J: Integer;
|
||
|
Row: TfrxHtCellList;
|
||
|
begin
|
||
|
Obj := nil;
|
||
|
if (len > 0) and (Pos >= StartCurs) and (Pos < StartCurs + Len) then
|
||
|
for J := 0 to Rows.Count - 1 do
|
||
|
begin
|
||
|
Row := Rows[J];
|
||
|
for I := 0 to Row.Count - 1 do
|
||
|
begin
|
||
|
if Row[I] is TfrxHtCellObj then
|
||
|
begin
|
||
|
Result := TfrxHtCellObj(Row[I]).Cell.GetChAtPos(Pos, Ch, Obj);
|
||
|
if Result then
|
||
|
Exit;
|
||
|
end;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
Result := False;
|
||
|
end;
|
||
|
|
||
|
{----------------TfrxHtmlTable.FindString}
|
||
|
|
||
|
function TfrxHtmlTable.FindString(From: Integer; const ToFind: UnicodeString; MatchCase: Boolean): Integer;
|
||
|
var
|
||
|
I, J: Integer;
|
||
|
Row: TfrxHtCellList;
|
||
|
begin
|
||
|
for J := 0 to Rows.Count - 1 do
|
||
|
begin
|
||
|
Row := Rows[J];
|
||
|
for I := 0 to Row.Count - 1 do
|
||
|
begin
|
||
|
if Row[I] is TfrxHtCellObj then
|
||
|
begin
|
||
|
Result := TfrxHtCellObj(Row[I]).Cell.FindString(From, ToFind, MatchCase);
|
||
|
if Result >= 0 then
|
||
|
Exit;
|
||
|
end;
|
||
|
end;
|
||
|
end;
|
||
|
Result := -1;
|
||
|
end;
|
||
|
|
||
|
{----------------TfrxHtmlTable.FindStringR}
|
||
|
|
||
|
function TfrxHtmlTable.FindStringR(From: Integer; const ToFind: UnicodeString; MatchCase: Boolean): Integer;
|
||
|
var
|
||
|
I, J: Integer;
|
||
|
Row: TfrxHtCellList;
|
||
|
begin
|
||
|
for J := Rows.Count - 1 downto 0 do
|
||
|
begin
|
||
|
Row := Rows[J];
|
||
|
for I := Row.Count - 1 downto 0 do
|
||
|
begin
|
||
|
if Row[I] is TfrxHtCellObj then
|
||
|
begin
|
||
|
Result := TfrxHtCellObj(Row[I]).Cell.FindStringR(From, ToFind, MatchCase);
|
||
|
if Result >= 0 then
|
||
|
Exit;
|
||
|
end;
|
||
|
end;
|
||
|
end;
|
||
|
Result := -1;
|
||
|
end;
|
||
|
|
||
|
{----------------TfrxHtmlTable.FindSourcePos}
|
||
|
|
||
|
function TfrxHtmlTable.FindSourcePos(DocPos: Integer): Integer;
|
||
|
var
|
||
|
I, J: Integer;
|
||
|
Row: TfrxHtCellList;
|
||
|
begin
|
||
|
for J := 0 to Rows.Count - 1 do
|
||
|
begin
|
||
|
Row := Rows[J];
|
||
|
for I := 0 to Row.Count - 1 do
|
||
|
begin
|
||
|
if Row[I] is TfrxHtCellObj then
|
||
|
begin
|
||
|
Result := TfrxHtCellObj(Row[I]).Cell.FindSourcePos(DocPos);
|
||
|
if Result >= 0 then
|
||
|
Exit;
|
||
|
end;
|
||
|
end;
|
||
|
end;
|
||
|
Result := -1;
|
||
|
end;
|
||
|
|
||
|
{----------------TfrxHtmlTable.FindDocPos}
|
||
|
|
||
|
function TfrxHtmlTable.FindDocPos(SourcePos: Integer; Prev: Boolean): Integer;
|
||
|
var
|
||
|
I, J: Integer;
|
||
|
Row: TfrxHtCellList;
|
||
|
begin
|
||
|
if not Prev then
|
||
|
for J := 0 to Rows.Count - 1 do
|
||
|
begin
|
||
|
Row := Rows[J];
|
||
|
if Row <> nil then
|
||
|
for I := 0 to Row.Count - 1 do
|
||
|
begin
|
||
|
if Row[I] is TfrxHtCellObj then
|
||
|
begin
|
||
|
Result := TfrxHtCellObj(Row[I]).Cell.FindDocPos(SourcePos, Prev);
|
||
|
if Result >= 0 then
|
||
|
Exit;
|
||
|
end;
|
||
|
end;
|
||
|
end
|
||
|
else {Prev , iterate in reverse}
|
||
|
for J := Rows.Count - 1 downto 0 do
|
||
|
begin
|
||
|
Row := Rows[J];
|
||
|
if Row <> nil then
|
||
|
for I := Row.Count - 1 downto 0 do
|
||
|
begin
|
||
|
if Row[I] is TfrxHtCellObj then
|
||
|
begin
|
||
|
Result := TfrxHtCellObj(Row[I]).Cell.FindDocPos(SourcePos, Prev);
|
||
|
if Result >= 0 then
|
||
|
Exit;
|
||
|
end;
|
||
|
end;
|
||
|
end;
|
||
|
Result := -1;
|
||
|
end;
|
||
|
|
||
|
|
||
|
//-- BG ---------------------------------------------------------- 01.12.2013 --
|
||
|
constructor TfrxHtSection.Create(Parent: TfrxHtCellBasic);
|
||
|
begin
|
||
|
inherited Create(Parent, nil, nil);
|
||
|
FDisplay := pdInline; // A section is always inline as the section is intended to handle consecutive inline elements.
|
||
|
FBuff := PWideChar(BuffS);
|
||
|
Fonts := TfrxHtFontList.Create;
|
||
|
Images := TfrxHtSizeableObjList.Create;
|
||
|
Lines := TfrxHtLineRecList.Create;
|
||
|
end;
|
||
|
|
||
|
{----------------TfrxHtSection.Create}
|
||
|
|
||
|
constructor TfrxHtSection.Create(Parent: TfrxHtCellBasic; Attr: TfrxHtAttributeList; Prop: TfrxHTProperties; AnURL: TfrxHtUrlTarget; FirstItem: Boolean);
|
||
|
var
|
||
|
FO: TfrxHtFontObj;
|
||
|
// T: TfrxHtAttribute;
|
||
|
S, C: ThtString;
|
||
|
// Clr: ThtClearStyle;
|
||
|
Percent: Boolean;
|
||
|
begin
|
||
|
if Attr <> nil then
|
||
|
begin
|
||
|
S := Attr.TheID;
|
||
|
C := Attr.TheClass;
|
||
|
end;
|
||
|
inherited Create(Parent, Attr, Prop, S, C);
|
||
|
if FDisplay = pdUnassigned then
|
||
|
FDisplay := pdInline;
|
||
|
FBuff := PWideChar(BuffS);
|
||
|
Fonts := TfrxHtFontList.Create;
|
||
|
Images := TfrxHtSizeableObjList.Create;
|
||
|
Lines := TfrxHtLineRecList.Create;
|
||
|
|
||
|
FO := TfrxHtFontObj.Create(Self, Prop.Font, 0);
|
||
|
FO.Title := Prop.PropTitle;
|
||
|
if Assigned(AnURL) and (Length(AnURL.Url) > 0) then
|
||
|
begin
|
||
|
FO.CreateFIArray;
|
||
|
Prop.GetFontInfo(FO.FIArray);
|
||
|
FO.ConvertFont(FO.FIArray.Info);
|
||
|
FO.UrlTarget.Assign(AnUrl);
|
||
|
Document.LinkList.Add(FO);
|
||
|
end;
|
||
|
Fonts.Add(FO);
|
||
|
|
||
|
LineHeight := Prop.GetLineHeight(Abs(FO.TheFont.Height));
|
||
|
if FirstItem then
|
||
|
begin
|
||
|
FirstLineIndent := Prop.GetTextIndent(Percent);
|
||
|
if Percent then
|
||
|
FLPercent := Min(FirstLineIndent, 90);
|
||
|
end;
|
||
|
|
||
|
if VarIsEmpty(Prop.Props[TextDirection]) then
|
||
|
Direction := diLTR
|
||
|
else if Prop.Props[TextDirection] = 'rtl' then
|
||
|
Direction := diRTL
|
||
|
else if Prop.Props[TextDirection] = 'auto' then
|
||
|
Direction := diAuto
|
||
|
else
|
||
|
Direction := diLTR;
|
||
|
|
||
|
if VarIsEmpty(Prop.Props[TextAlign]) then // check for unassigned
|
||
|
SetJustifyByDirection
|
||
|
else if Prop.Props[TextAlign] = 'right' then
|
||
|
Justify := Right
|
||
|
else if Prop.Props[TextAlign] = 'center' then
|
||
|
Justify := Centered
|
||
|
else if Prop.Props[TextAlign] = 'justify' then
|
||
|
Justify := FullJustify
|
||
|
else
|
||
|
Justify := Left;
|
||
|
|
||
|
BreakWord := Prop.Props[WordWrap] = 'break-word';
|
||
|
|
||
|
if Self is TfrxHtPreFormated then
|
||
|
WhiteSpaceStyle := wsPre
|
||
|
else if Document.NoBreak then
|
||
|
WhiteSpaceStyle := wsNoWrap
|
||
|
else
|
||
|
WhiteSpaceStyle := wsNormal;
|
||
|
if VarIsOrdinal(Prop.Props[piWhiteSpace]) then
|
||
|
WhiteSpaceStyle := ThtWhiteSpaceStyle(Prop.Props[piWhiteSpace])
|
||
|
else if VarIsStr(Prop.Props[piWhiteSpace]) then
|
||
|
begin
|
||
|
if not TryStrToWhiteSpace(Prop.Props[piWhiteSpace],WhiteSpaceStyle) then
|
||
|
begin
|
||
|
end;
|
||
|
// if Prop.Props[piWhiteSpace] = 'pre' then
|
||
|
// WhiteSpaceStyle := wsPre
|
||
|
// else if Prop.Props[piWhiteSpace] = 'nowrap' then
|
||
|
// WhiteSpaceStyle := wsNoWrap
|
||
|
// else if Prop.Props[piWhiteSpace] = 'pre-wrap' then
|
||
|
// WhiteSpaceStyle := wsPreWrap
|
||
|
// else if Prop.Props[piWhiteSpace] = 'pre-line' then
|
||
|
// WhiteSpaceStyle := wsPreLine
|
||
|
// else if Prop.Props[piWhiteSpace] = 'normal' then
|
||
|
// WhiteSpaceStyle := wsNormal;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
{----------------TfrxHtSection.CreateCopy}
|
||
|
|
||
|
constructor TfrxHtSection.CreateCopy(Parent: TfrxHtCellBasic; Source: TfrxHtmlNode);
|
||
|
var
|
||
|
T: TfrxHtSection absolute Source;
|
||
|
begin
|
||
|
inherited CreateCopy(Parent,Source);
|
||
|
Len := T.Len;
|
||
|
BuffS := T.BuffS;
|
||
|
SetLength(BuffS, Length(BuffS));
|
||
|
FBuff := PWideChar(BuffS);
|
||
|
Brk := T.Brk;
|
||
|
Fonts := TfrxHtFontList.CreateCopy(Self, T.Fonts);
|
||
|
//TODO -oBG, 24.03.2011: TfrxHtSection has no Cell, but owns images. Thus Parent must be a TfrxHtmlNode.
|
||
|
// and TfrxHtDocument should become a TfrxHtBodyBlock instead of a SectionList.
|
||
|
Images := TfrxHtSizeableObjList.CreateCopy(Parent {must be Self}, T.Images);
|
||
|
Lines := TfrxHtLineRecList.Create;
|
||
|
Justify := T.Justify;
|
||
|
JustifyByDirection := T.JustifyByDirection;
|
||
|
Direction := T.Direction;
|
||
|
LineHeight := T.LineHeight;
|
||
|
FirstLineIndent := T.FirstLineIndent;
|
||
|
FLPercent := T.FLPercent;
|
||
|
BreakWord := T.BreakWord;
|
||
|
WhiteSpaceStyle := T.WhiteSpaceStyle;
|
||
|
end;
|
||
|
|
||
|
{----------------TfrxHtSection.Destroy}
|
||
|
|
||
|
destructor TfrxHtSection.Destroy;
|
||
|
var
|
||
|
i: Integer;
|
||
|
begin
|
||
|
{ Yunqa.de: Do not leave references to deleted font objects in the
|
||
|
HtmlViewer's link list. Otherwise TfrxHtUrlTarget.SetLast might see an access
|
||
|
violation. }
|
||
|
if Document <> nil then
|
||
|
if Document.LinkList <> nil then
|
||
|
for i := 0 to Fonts.Count - 1 do
|
||
|
Document.LinkList.Remove(Fonts[i]);
|
||
|
|
||
|
SIndexList.Free;
|
||
|
Lines.Free;
|
||
|
Images.Free;
|
||
|
Fonts.Free;
|
||
|
inherited Destroy;
|
||
|
end;
|
||
|
|
||
|
procedure TfrxHtSection.CheckFree;
|
||
|
var
|
||
|
I, J: Integer;
|
||
|
begin
|
||
|
if not Assigned(Self) then
|
||
|
Exit;
|
||
|
if Assigned(Document) then
|
||
|
begin
|
||
|
{Check to see that there isn't a TfrxHtFontObj in LinkList}
|
||
|
if Assigned(Document.LinkList) then
|
||
|
for I := 0 to Fonts.Count - 1 do
|
||
|
begin
|
||
|
J := Document.LinkList.IndexOf(Fonts[I]);
|
||
|
if J >= 0 then
|
||
|
Document.LinkList.Delete(J);
|
||
|
end;
|
||
|
{Remove Self from IDNameList if there}
|
||
|
if Assigned(Document.IDNameList) then
|
||
|
with Document.IDNameList do
|
||
|
begin
|
||
|
I := IndexOfObject(Self);
|
||
|
if I > -1 then
|
||
|
Delete(I);
|
||
|
end;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
{----------------TfrxHtSection.AddChar}
|
||
|
|
||
|
procedure TfrxHtSection.AddChar(C: WideChar; Index: Integer);
|
||
|
var
|
||
|
Tok: TfrxHtTokenObj;
|
||
|
begin
|
||
|
Tok := TfrxHtTokenObj.Create;
|
||
|
Tok.AddUnicodeChar(C, Index);
|
||
|
AddTokenObj(Tok);
|
||
|
Tok.Free;
|
||
|
end;
|
||
|
|
||
|
function TfrxHtSection.GetIndexObj(I: Integer): TfrxHtIndexObj;
|
||
|
begin
|
||
|
Result := SIndexList[I];
|
||
|
end;
|
||
|
|
||
|
function TfrxHtSection.GetXPLen: Integer;
|
||
|
begin
|
||
|
Result := Length(XP);
|
||
|
end;
|
||
|
|
||
|
procedure TfrxHtSection.AddOpBrk;
|
||
|
var
|
||
|
L: Integer;
|
||
|
begin
|
||
|
L := Length(Brk);
|
||
|
if L > 0 then
|
||
|
Brk[L - 1] := twOptional;
|
||
|
end;
|
||
|
|
||
|
{----------------TfrxHtSection.AddTokenObj}
|
||
|
|
||
|
procedure TfrxHtSection.AddTokenObj(T: TfrxHtTokenObj);
|
||
|
var
|
||
|
L, I, J: Integer;
|
||
|
C: ThtTextWrap;
|
||
|
St, StU: ThtString;
|
||
|
Small: Boolean;
|
||
|
LastProps: TfrxHTProperties;
|
||
|
begin
|
||
|
if T.Count = 0 then
|
||
|
Exit;
|
||
|
|
||
|
{ Yunqa.de: Simple hack to support <span style="display:none"> }
|
||
|
LastProps := Document.PropStack.Last;
|
||
|
if (LastProps.Display = pdNone) and (LastProps.PropSym in [
|
||
|
SpanSy, NoBrSy, WbrSy, FontSy, BSy, ISy, SSy, StrikeSy, USy, SubSy, SupSy, BigSy, SmallSy, TTSy,
|
||
|
EmSy, StrongSy, CodeSy, KbdSy, SampSy, DelSy, InsSy, CiteSy, VarSy, MarkSy, TimeSy, ASy])
|
||
|
then
|
||
|
Exit;
|
||
|
|
||
|
case LastProps.GetTextTransform of
|
||
|
txUpper:
|
||
|
St := htUpperCase(T.S);
|
||
|
txLower:
|
||
|
St := htLowerCase(T.S);
|
||
|
else
|
||
|
St := T.S;
|
||
|
end;
|
||
|
|
||
|
L := Len + T.Count;
|
||
|
if Length(XP) < L + 3 then
|
||
|
Allocate(L + 500); {L+3 to permit additions later}
|
||
|
|
||
|
// add positions in source
|
||
|
Move(T.I[1], XP[Len], T.Count * Sizeof(Integer));
|
||
|
|
||
|
// BG, 31.08.2011: added: WhiteSpaceStyle
|
||
|
if Document.NoBreak or (WhiteSpaceStyle in [wsPre, wsPreLine, wsNoWrap]) then
|
||
|
C := twNo
|
||
|
else
|
||
|
C := twYes;
|
||
|
|
||
|
J := Length(Brk);
|
||
|
SetLength(Brk, J + T.Count);
|
||
|
for I := J to J + T.Count - 1 do
|
||
|
Brk[I] := C;
|
||
|
|
||
|
if LastProps.GetFontVariant = 'small-caps' then
|
||
|
begin
|
||
|
StU := htUpperCase(St);
|
||
|
BuffS := BuffS + StU;
|
||
|
Small := False;
|
||
|
for I := 1 to Length(St) do
|
||
|
begin
|
||
|
case St[I] of
|
||
|
WideChar(' '), WideChar('0')..WideChar('9'):
|
||
|
{no font changes for these chars}
|
||
|
;
|
||
|
else
|
||
|
if not Small then
|
||
|
begin
|
||
|
if StU[I] <> St[I] then
|
||
|
begin {St[I] was lower case}
|
||
|
Document.PropStack.PushNewProp(SmallSy, nil, nil); {change to smaller font}
|
||
|
ChangeFont(Document.PropStack.Last);
|
||
|
Small := True;
|
||
|
end;
|
||
|
end
|
||
|
else if StU[I] = St[I] then
|
||
|
begin {St[I] was uppercase and Small is set}
|
||
|
Document.PropStack.PopAProp(SmallSy);
|
||
|
ChangeFont(Document.PropStack.Last);
|
||
|
Small := False;
|
||
|
end;
|
||
|
end;
|
||
|
Inc(Len);
|
||
|
end;
|
||
|
if Small then {change back to regular font}
|
||
|
begin
|
||
|
Document.PropStack.PopAProp(SmallSy);
|
||
|
ChangeFont(Document.PropStack.Last);
|
||
|
end;
|
||
|
end
|
||
|
else
|
||
|
begin
|
||
|
BuffS := BuffS + St;
|
||
|
Len := L;
|
||
|
end;
|
||
|
FBuff := PWideChar(BuffS);
|
||
|
SureDirection(FBuff, Len);
|
||
|
end;
|
||
|
|
||
|
{----------------TfrxHtSection.ProcessText}
|
||
|
|
||
|
procedure TfrxHtSection.ProcessText(TagIndex: Integer);
|
||
|
const
|
||
|
Shy = #173; {soft hyphen}
|
||
|
var
|
||
|
I: Integer;
|
||
|
FO: TfrxHtFontObj;
|
||
|
|
||
|
procedure Remove(I: Integer);
|
||
|
var L: Integer;
|
||
|
begin
|
||
|
L := Length(BuffS) - I;
|
||
|
if L > 0 then
|
||
|
Move(XP[I], XP[I - 1], L * Sizeof(Integer));
|
||
|
L := Length(Brk) - I;
|
||
|
if L > 0 then
|
||
|
Move(Brk[I], Brk[I - 1], L * Sizeof(ThtTextWrap));
|
||
|
SetLength(Brk, Length(Brk) - 1);
|
||
|
System.Delete(BuffS, I, 1);
|
||
|
Fonts.Decrement(I - 1, Document);
|
||
|
Images.Decrement(I - 1);
|
||
|
end;
|
||
|
|
||
|
begin
|
||
|
if WhiteSpaceStyle in [wsPre] then
|
||
|
begin
|
||
|
FO := TfrxHtFontObj(Fonts.Items[Fonts.Count - 1]); {keep font the same for inserted space}
|
||
|
if FO.Pos = Length(BuffS) then
|
||
|
Inc(FO.Pos);
|
||
|
BuffS := BuffS + ' ';
|
||
|
Allocate(Length(BuffS) + 500);
|
||
|
XP[Length(BuffS) - 1] := XP[Length(BuffS) - 2] + 1;
|
||
|
end
|
||
|
else
|
||
|
begin
|
||
|
while (Length(BuffS) > 0) and (BuffS[1] = ' ') do
|
||
|
Remove(1);
|
||
|
|
||
|
I := WidePos(Shy, BuffS);
|
||
|
while I > 0 do
|
||
|
begin
|
||
|
Remove(I);
|
||
|
if (I > 1) and (Brk[I - 2] <> twNo) then
|
||
|
Brk[I - 2] := twSoft;
|
||
|
I := WidePos(Shy, BuffS);
|
||
|
end;
|
||
|
|
||
|
if WhiteSpaceStyle in [wsNormal, wsNoWrap, wsPreLine] then
|
||
|
begin
|
||
|
while (Length(BuffS) > 0) and (BuffS[1] = ' ') do
|
||
|
Remove(1);
|
||
|
|
||
|
I := WidePos(' ', BuffS);
|
||
|
while I > 0 do
|
||
|
begin
|
||
|
if Brk[I - 1] = twNo then
|
||
|
Remove(I)
|
||
|
else
|
||
|
Remove(I + 1);
|
||
|
I := WidePos(' ', BuffS);
|
||
|
end;
|
||
|
|
||
|
{After floating images at start, delete an annoying space}
|
||
|
for I := Length(BuffS) - 1 downto 1 do
|
||
|
if (BuffS[I] = ImgPan) and (Images.FindObject(I - 1).Floating in [ALeft, ARight])
|
||
|
and (BuffS[I + 1] = ' ') then
|
||
|
Remove(I + 1);
|
||
|
|
||
|
I := WidePos(UnicodeString(' '#8), BuffS); {#8 is break char}
|
||
|
while I > 0 do
|
||
|
begin
|
||
|
Remove(I);
|
||
|
I := WidePos(UnicodeString(' '#8), BuffS);
|
||
|
end;
|
||
|
|
||
|
I := WidePos(UnicodeString(#8' '), BuffS);
|
||
|
while I > 0 do
|
||
|
begin
|
||
|
Remove(I + 1);
|
||
|
I := WidePos(UnicodeString(#8' '), BuffS);
|
||
|
end;
|
||
|
|
||
|
if (Length(BuffS) > 1) and (BuffS[Length(BuffS)] = #8) then
|
||
|
Remove(Length(BuffS));
|
||
|
|
||
|
if (Length(BuffS) > 1) and (BuffS[Length(BuffS)] = ' ') then
|
||
|
Remove(Length(BuffS));
|
||
|
|
||
|
if (BuffS <> #8) and (Length(BuffS) > 0) and (BuffS[Length(BuffS)] <> ' ') then
|
||
|
begin
|
||
|
FO := TfrxHtFontObj(Fonts.Items[Fonts.Count - 1]); {keep font the same for inserted space}
|
||
|
if FO.Pos = Length(BuffS) then
|
||
|
Inc(FO.Pos);
|
||
|
BuffS := BuffS + ' ';
|
||
|
//XP[Length(BuffS) - 1] := TagIndex;
|
||
|
end;
|
||
|
end;
|
||
|
end;
|
||
|
Finish;
|
||
|
end;
|
||
|
|
||
|
procedure TfrxHtSection.SetJustifyByDirection;
|
||
|
begin
|
||
|
JustifyByDirection := True;
|
||
|
if Direction = diRTL then
|
||
|
Justify := Right
|
||
|
else if Direction = diLTR then
|
||
|
Justify := Left;
|
||
|
end;
|
||
|
|
||
|
procedure TfrxHtSection.SureDirection(WC: PWideChar; Len: Integer);
|
||
|
begin
|
||
|
if Direction = diAuto then
|
||
|
begin
|
||
|
Direction := DirectionByText(WC, Len);
|
||
|
|
||
|
if JustifyByDirection then
|
||
|
SetJustifyByDirection;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
{----------------TfrxHtSection.Finish}
|
||
|
|
||
|
procedure TfrxHtSection.Finish;
|
||
|
{complete some things after all information added}
|
||
|
var
|
||
|
Last, I: Integer;
|
||
|
IO: TfrxHtIndexObj;
|
||
|
begin
|
||
|
FBuff := PWideChar(BuffS);
|
||
|
Len := Length(BuffS);
|
||
|
if Len > 0 then
|
||
|
begin
|
||
|
SetLength(Brk, Length(Brk) + 1);
|
||
|
Brk[Length(Brk) - 1] := twYes;
|
||
|
|
||
|
if not IsCopy then
|
||
|
begin
|
||
|
Last := 0; {to prevent warning msg}
|
||
|
SIndexList := TfrxHtIndexObjList.Create;
|
||
|
for I := 0 to Len - 1 do
|
||
|
begin
|
||
|
if (I = 0) or (XP[I] <> Last + 1) then
|
||
|
begin
|
||
|
IO := TfrxHtIndexObj.Create;
|
||
|
IO.Pos := I;
|
||
|
IO.Index := XP[I];
|
||
|
SIndexList.Add(IO);
|
||
|
end;
|
||
|
Last := XP[I];
|
||
|
end;
|
||
|
SetLength(XP, 0);
|
||
|
end;
|
||
|
|
||
|
Inc(Document.SectionCount);
|
||
|
SectionNumber := Document.SectionCount;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
{----------------TfrxHtSection.Allocate}
|
||
|
|
||
|
procedure TfrxHtSection.Allocate(N: Integer);
|
||
|
begin
|
||
|
if Length(XP) < N then
|
||
|
SetLength(XP, N);
|
||
|
end;
|
||
|
|
||
|
{----------------TfrxHtSection.ChangeFont}
|
||
|
|
||
|
procedure TfrxHtSection.ChangeFont(Prop: TfrxHTProperties);
|
||
|
var
|
||
|
FO: TfrxHtFontObj;
|
||
|
LastUrl: TfrxHtUrlTarget;
|
||
|
Align: ThtAlignmentStyle;
|
||
|
begin
|
||
|
FO := Fonts[Fonts.Count - 1];
|
||
|
LastUrl := FO.UrlTarget;
|
||
|
if FO.Pos = Len then
|
||
|
FO.ReplaceFont(Prop.Font) {fontobj already at this position, modify it}
|
||
|
else
|
||
|
begin
|
||
|
FO := TfrxHtFontObj.Create(Self, Prop.Font, Len);
|
||
|
FO.URLTarget.Assign(LastUrl);
|
||
|
Fonts.Add(FO);
|
||
|
end;
|
||
|
FO.Title := Prop.PropTitle;
|
||
|
if LastUrl.Url <> '' then
|
||
|
begin
|
||
|
FO.CreateFIArray;
|
||
|
Prop.GetFontInfo(FO.FIArray);
|
||
|
FO.ConvertFont(FO.FIArray.Info);
|
||
|
if Document.LinkList.IndexOf(FO) = -1 then
|
||
|
Document.LinkList.Add(FO);
|
||
|
end;
|
||
|
if Prop.GetVertAlign(Align) and (Align in [ASub, ASuper]) then
|
||
|
FO.SScript := Align
|
||
|
else
|
||
|
FO.SScript := ANone;
|
||
|
end;
|
||
|
|
||
|
{----------------------TfrxHtSection.HRef}
|
||
|
|
||
|
procedure TfrxHtSection.HRef(IsHRef: Boolean; List: TfrxHtDocument; AnURL: TfrxHtUrlTarget;
|
||
|
Attributes: TfrxHtAttributeList; Prop: TfrxHTProperties);
|
||
|
var
|
||
|
FO: TfrxHtFontObj;
|
||
|
Align: ThtAlignmentStyle;
|
||
|
begin
|
||
|
FO := Fonts[Fonts.Count - 1];
|
||
|
if FO.Pos = Len then
|
||
|
FO.ReplaceFont(Prop.Font) {fontobj already at this position, modify it}
|
||
|
else
|
||
|
begin
|
||
|
FO := TfrxHtFontObj.Create(Self, Prop.Font, Len);
|
||
|
Fonts.Add(FO);
|
||
|
end;
|
||
|
|
||
|
if IsHRef then
|
||
|
begin
|
||
|
FO.CreateFIArray;
|
||
|
Prop.GetFontInfo(FO.FIArray);
|
||
|
FO.ConvertFont(FO.FIArray.Info);
|
||
|
if Document.LinkList.IndexOf(FO) = -1 then
|
||
|
Document.LinkList.Add(FO);
|
||
|
end
|
||
|
else if Assigned(FO.FIArray) then
|
||
|
begin
|
||
|
FO.FIArray.Free;
|
||
|
FO.FIArray := nil;
|
||
|
end;
|
||
|
FO.UrlTarget.Assign(AnUrl);
|
||
|
if Prop.GetVertAlign(Align) and (Align in [ASub, ASuper]) then
|
||
|
FO.SScript := Align
|
||
|
else
|
||
|
FO.SScript := ANone;
|
||
|
end;
|
||
|
|
||
|
function TfrxHtSection.AddImage(L: TfrxHtAttributeList; ACell: TfrxHtCellBasic; Index: Integer; Prop: TfrxHTProperties): TfrxFrHtImageObj;
|
||
|
begin
|
||
|
Result := TfrxFrHtImageObj.Create(ACell, Len, L, Prop);
|
||
|
Images.Add(Result);
|
||
|
AddChar(ImgPan, Index); {marker for image}
|
||
|
end;
|
||
|
|
||
|
{----------------TfrxHtSection.FindCountThatFits}
|
||
|
|
||
|
function TfrxHtSection.FindCountThatFits(Canvas: TCanvas; Width: Integer; Start: PWideChar; Max: Integer): Integer;
|
||
|
{Given a width, find the count of chars (<= Max) which will fit allowing for
|
||
|
font changes. Line wrapping will be done later}
|
||
|
//BG, 06.02.2011: Why are there 2 methods and why can't GetURL and FindCursor use the formatting results of DrawLogic?
|
||
|
// TfrxHtSection.FindCountThatFits1() is used in TfrxHtSection.DrawLogic().
|
||
|
// TfrxHtSection.FindCountThatFits() is used in TfrxHtSection.GetURL() and TfrxHtSection.FindCursor().
|
||
|
var
|
||
|
Cnt, XX, YY, I, J, J1, J2: Integer;
|
||
|
Picture: Boolean;
|
||
|
FlObj: TfrxHtFloatingObj; //TfrxHtSizeableObj;
|
||
|
FO: TfrxHtFontObj;
|
||
|
Extent: TSize;
|
||
|
const
|
||
|
OldStart: PWideChar = nil;
|
||
|
OldResult: Integer = 0;
|
||
|
OldWidth: Integer = 0;
|
||
|
|
||
|
begin
|
||
|
if (Width = OldWidth) and (Start = OldStart) then
|
||
|
begin
|
||
|
Result := OldResult;
|
||
|
Exit;
|
||
|
end;
|
||
|
OldStart := Start;
|
||
|
OldWidth := Width;
|
||
|
Cnt := 0;
|
||
|
XX := 0;
|
||
|
YY := 0;
|
||
|
while True do
|
||
|
begin
|
||
|
//Fonts.GetFontAt(Start - Buff, OHang).AssignToCanvas(Canvas);
|
||
|
J1 := Fonts.GetFontObjAt(Start - Buff, Len, FO);
|
||
|
FO.TheFont.AssignToCanvas(Canvas);
|
||
|
J2 := Images.GetObjectAt(Start - Buff, FlObj);
|
||
|
if (J2 = 0) then
|
||
|
begin
|
||
|
I := 1; J := 1;
|
||
|
Picture := True;
|
||
|
if FlObj.IsInFlow then
|
||
|
begin
|
||
|
Inc(XX, FlObj.TotalWidth);
|
||
|
if XX > Width then
|
||
|
break;
|
||
|
end;
|
||
|
end
|
||
|
else
|
||
|
begin
|
||
|
Picture := False;
|
||
|
J := Min(J1, J2);
|
||
|
I := FitText(Canvas.Handle, Start, J, Width - XX, Extent);
|
||
|
end;
|
||
|
|
||
|
if Cnt + I >= Max then {I has been initialized}
|
||
|
begin
|
||
|
Cnt := Max;
|
||
|
Break;
|
||
|
end
|
||
|
else
|
||
|
Inc(Cnt, I);
|
||
|
|
||
|
if not Picture then
|
||
|
begin
|
||
|
if (I < J) or (I = 0) then
|
||
|
Break;
|
||
|
XX := XX + Extent.cx;
|
||
|
YY := Math.Max(YY, Extent.cy);
|
||
|
end;
|
||
|
|
||
|
Inc(Start, I);
|
||
|
end;
|
||
|
Result := Cnt;
|
||
|
OldResult := Result;
|
||
|
end;
|
||
|
|
||
|
function WrapChar(C: WideChar): Boolean;
|
||
|
{$ifdef UseInline} inline; {$endif}
|
||
|
begin
|
||
|
Result := Ord(C) >= $3000;
|
||
|
end;
|
||
|
|
||
|
//-- BG ---------------------------------------------------------- 27.01.2012 --
|
||
|
function CanWrapAfter(PC: PWideChar): Boolean;
|
||
|
{$ifdef UseInline} inline; {$endif}
|
||
|
begin
|
||
|
case PC^ of
|
||
|
WideChar('-'):
|
||
|
case (PC+1)^ of
|
||
|
WideChar('0')..WideChar('9'):
|
||
|
Result := False;
|
||
|
else
|
||
|
Result := True;
|
||
|
end;
|
||
|
|
||
|
WideChar('/'), WideChar('?'):
|
||
|
Result := True
|
||
|
else
|
||
|
Result := False;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
//-- BG ---------------------------------------------------------- 20.09.2010 --
|
||
|
function CanWrap(PC: PWideChar): Boolean;
|
||
|
{$ifdef UseInline} inline; {$endif}
|
||
|
begin
|
||
|
case PC^ of
|
||
|
WideChar('-'):
|
||
|
case (PC+1)^ of
|
||
|
WideChar('0')..WideChar('9'):
|
||
|
Result := False;
|
||
|
else
|
||
|
Result := True;
|
||
|
end;
|
||
|
|
||
|
WideChar(' '), WideChar('/'), WideChar('?'), ImgPan, FmCtl, BrkCh:
|
||
|
Result := True
|
||
|
else
|
||
|
Result := WrapChar(PC^);
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
{----------------TfrxHtSection.MinMaxWidth}
|
||
|
|
||
|
procedure TfrxHtSection.MinMaxWidth(Canvas: TCanvas; out Min, Max: Integer; AvailableWidth, AvailableHeight: Integer);
|
||
|
{Min is the width the section would occupy when wrapped as tightly as possible.
|
||
|
Max, the width if no wrapping were used.}
|
||
|
|
||
|
procedure MinMaxWidthOfBlocks(Objects: TFloatingObjList);
|
||
|
var
|
||
|
I: Integer;
|
||
|
Obj: TfrxHtFloatingObj;
|
||
|
begin
|
||
|
for I := 0 to Objects.Count - 1 do {call drawlogic for all the objects}
|
||
|
begin
|
||
|
Obj := Objects[I];
|
||
|
Obj.DrawLogicInline(Canvas, Fonts.GetFontObjAt(Obj.StartCurs), AvailableWidth, AvailableHeight);
|
||
|
if not Obj.PercentWidth then
|
||
|
begin
|
||
|
if Obj.Positioning in [posAbsolute, posFixed] then
|
||
|
begin
|
||
|
// does not affect the block width
|
||
|
Brk[Obj.StartCurs] := twYes; {allow break after positioned object}
|
||
|
end
|
||
|
else if Obj.Floating in [ALeft, ARight] then
|
||
|
begin
|
||
|
Inc(Max, Obj.TotalWidth);
|
||
|
Brk[Obj.StartCurs] := twYes; {allow break after floating object}
|
||
|
Min := Math.Max(Min, Obj.TotalWidth);
|
||
|
end
|
||
|
else
|
||
|
Min := Math.Max(Min, Obj.ClientWidth);
|
||
|
end;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
var
|
||
|
SoftHyphen: Boolean;
|
||
|
|
||
|
function FindTextWidthB(Canvas: TCanvas; Start: PWideChar; N: Integer; RemoveSpaces: Boolean): TSize;
|
||
|
begin
|
||
|
Result := FindTextSize(Canvas, Start, N, RemoveSpaces);
|
||
|
if Start = Buff then
|
||
|
if FLPercent = 0 then {not a percent}
|
||
|
Inc(Result.cx, FirstLineIndent)
|
||
|
else
|
||
|
Result.cx := (100 * Result.cx) div (100 - FLPercent);
|
||
|
if SoftHyphen then
|
||
|
Inc(Result.cx, Canvas.TextWidth('-'));
|
||
|
end;
|
||
|
|
||
|
var
|
||
|
I, FloatMin: Integer;
|
||
|
P, P1: PWideChar;
|
||
|
begin
|
||
|
Min := 0;
|
||
|
Max := 0;
|
||
|
if Len = 0 then
|
||
|
Exit;
|
||
|
|
||
|
if not BreakWord and (WhiteSpaceStyle in [wsPre, wsNoWrap]) then
|
||
|
begin
|
||
|
if StoredMax.cx = 0 then
|
||
|
begin
|
||
|
StoredMax := FindTextSize(Canvas, Buff, Len - 1, False);
|
||
|
Max := StoredMax.cx;
|
||
|
end
|
||
|
else
|
||
|
Max := StoredMax.cx;
|
||
|
Min := Math.Min(MaxHScroll, Max);
|
||
|
Exit;
|
||
|
end;
|
||
|
|
||
|
if (StoredMin.cx > 0) and (Images.Count = 0) then
|
||
|
begin
|
||
|
Min := StoredMin.cx;
|
||
|
Max := StoredMax.cx;
|
||
|
Exit;
|
||
|
end;
|
||
|
|
||
|
MinMaxWidthOfBlocks(Images);
|
||
|
FloatMin := Min;
|
||
|
|
||
|
SoftHyphen := False;
|
||
|
P := Buff;
|
||
|
P1 := StrScanW(P, BrkCh); {look for break char}
|
||
|
while Assigned(P1) do
|
||
|
begin
|
||
|
Max := Math.Max(Max, FindTextWidthB(Canvas, P, P1 - P, False).cx);
|
||
|
P := P1 + 1;
|
||
|
P1 := StrScanW(P, BrkCh);
|
||
|
end;
|
||
|
P1 := StrScanW(P, #0); {look for the end}
|
||
|
Inc(Max, FindTextWidthB(Canvas, P, P1 - P, True).cx); // + FloatMin;
|
||
|
|
||
|
P := Buff;
|
||
|
if not BreakWord then
|
||
|
begin
|
||
|
while P^ = ' ' do
|
||
|
Inc(P);
|
||
|
P1 := P;
|
||
|
I := P1 - Buff + 1;
|
||
|
while P^ <> #0 do
|
||
|
{find the next string of chars that can't be wrapped}
|
||
|
begin
|
||
|
SoftHyphen := False;
|
||
|
if CanWrap(P1) and (Brk[I - 1] = twYes) then
|
||
|
begin
|
||
|
Inc(P1);
|
||
|
Inc(I);
|
||
|
end
|
||
|
else
|
||
|
begin
|
||
|
repeat
|
||
|
Inc(P1);
|
||
|
Inc(I);
|
||
|
case Brk[I - 2] of
|
||
|
twSoft, twOptional:
|
||
|
break;
|
||
|
end;
|
||
|
until (P1^ = #0) or (CanWrap(P1) and (Brk[I - 1] = twYes));
|
||
|
SoftHyphen := Brk[I - 2] = twSoft;
|
||
|
if CanWrapAfter(P1) then
|
||
|
begin
|
||
|
Inc(P1);
|
||
|
Inc(I);
|
||
|
end;
|
||
|
end;
|
||
|
Min := Math.Max(Min, FindTextWidthB(Canvas, P, P1 - P, True).cx);
|
||
|
while True do
|
||
|
case P1^ of
|
||
|
WideChar(' '), ImgPan, FmCtl, BrkCh:
|
||
|
begin
|
||
|
Inc(P1);
|
||
|
Inc(I);
|
||
|
end;
|
||
|
else
|
||
|
break;
|
||
|
end;
|
||
|
P := P1;
|
||
|
end;
|
||
|
end
|
||
|
else
|
||
|
while P^ <> #0 do
|
||
|
begin
|
||
|
Min := Math.Max(Min, FindTextWidthB(Canvas, P, 1, True).cx);
|
||
|
Inc(P);
|
||
|
end;
|
||
|
|
||
|
Min := Math.Max(FloatMin, Min);
|
||
|
StoredMin.cx := Min;
|
||
|
StoredMax.cx := Max;
|
||
|
StoredMin.cy := 0;
|
||
|
StoredMax.cy := 0;
|
||
|
end;
|
||
|
|
||
|
{----------------TfrxHtSection.FindTextWidth}
|
||
|
|
||
|
function TfrxHtSection.FindTextSize(Canvas: TCanvas; Start: PWideChar; N: Integer; RemoveSpaces: Boolean): TSize;
|
||
|
{find actual line width of N chars starting at Start. If RemoveSpaces set,
|
||
|
don't count spaces on right end}
|
||
|
var
|
||
|
I, J: Integer;
|
||
|
FlObj: TfrxHtFloatingObj; //TfrxHtSizeableObj;
|
||
|
FO: TfrxHtFontObj;
|
||
|
begin
|
||
|
Result.cx := 0;
|
||
|
Result.cy := 0;
|
||
|
if RemoveSpaces then
|
||
|
while True do
|
||
|
case (Start + N - 1)^ of
|
||
|
SpcChar,
|
||
|
BrkCh:
|
||
|
Dec(N); {remove spaces on end}
|
||
|
else
|
||
|
break;
|
||
|
end;
|
||
|
while N > 0 do
|
||
|
begin
|
||
|
J := Images.GetObjectAt(Start - Buff, FlObj);
|
||
|
if (J = 0) then {it's an image or a form control}
|
||
|
begin
|
||
|
{Here we count floating images as 1 ThtChar but do not include their width,
|
||
|
This is required for the call in FindCursor}
|
||
|
if FlObj.IsInFlow then
|
||
|
begin
|
||
|
Inc(Result.cx, FlObj.TotalWidth);
|
||
|
Result.cy := Max(Result.cy, FlObj.TotalHeight);
|
||
|
end;
|
||
|
Dec(N); {image counts as one ThtChar}
|
||
|
Inc(Start);
|
||
|
end
|
||
|
else
|
||
|
begin
|
||
|
//Fonts.GetFontAt(Start - Buff, OHang).AssignToCanvas(Canvas);
|
||
|
I := Min(J, Min(Fonts.GetFontObjAt(Start - Buff, Len, FO), N));
|
||
|
FO.TheFont.AssignToCanvas(Canvas);
|
||
|
//Assert(I > 0, 'I less than or = 0 in FindTextWidth');
|
||
|
with GetTextExtent(Canvas.Handle, Start, I) do
|
||
|
begin
|
||
|
Inc(Result.cx, cx + FO.Overhang);
|
||
|
Result.cy := Max(Result.cy, cy);
|
||
|
end;
|
||
|
if I = 0 then
|
||
|
Break;
|
||
|
Dec(N, I);
|
||
|
Inc(Start, I);
|
||
|
end;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
{----------------TfrxHtSection.FindTextWidthA}
|
||
|
|
||
|
function TfrxHtSection.FindTextWidthA(Canvas: TCanvas; Start: PWideChar; N: Integer): Integer;
|
||
|
{find actual line width of N chars starting at Start.
|
||
|
BG: The only difference to FindTextWidth is the '- OHang' when incrementing the result.}
|
||
|
var
|
||
|
I, J: Integer;
|
||
|
FlObj: TfrxHtFloatingObj; //TfrxHtSizeableObj;
|
||
|
FO: TfrxHtFontObj;
|
||
|
begin
|
||
|
Result := 0;
|
||
|
while N > 0 do
|
||
|
begin
|
||
|
J := Images.GetObjectAt(Start - Buff, FlObj);
|
||
|
if (J = 0) then {it's an image or a form control}
|
||
|
begin
|
||
|
{Here we count floating images as 1 ThtChar but do not include their width,
|
||
|
This is required for the call in FindCursor}
|
||
|
if FlObj.IsInFlow then
|
||
|
Inc(Result, FlObj.TotalWidth);
|
||
|
Dec(N); {image counts as one ThtChar}
|
||
|
Inc(Start);
|
||
|
end
|
||
|
else
|
||
|
begin
|
||
|
I := Min(J, Min(Fonts.GetFontObjAt(Start - Buff, Len, FO), N));
|
||
|
FO.TheFont.AssignToCanvas(Canvas);
|
||
|
Assert(I > 0, 'I less than or = 0 in FindTextWidthA');
|
||
|
Inc(Result, GetTextExtent(Canvas.Handle, Start, I).cx - FO.Overhang);
|
||
|
if I = 0 then
|
||
|
Break;
|
||
|
Dec(N, I);
|
||
|
Inc(Start, I);
|
||
|
end;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
{----------------TfrxHtSection.DrawLogic}
|
||
|
|
||
|
function TfrxHtSection.DrawLogic1(Canvas: TCanvas; X, Y, XRef, YRef, AWidth, AHeight, BlHt: Integer; IMgr: TfrxHtIndentManager;
|
||
|
var MaxWidth, Curs: Integer; ARemainHeight: Integer): Integer;
|
||
|
{returns height of the section}
|
||
|
|
||
|
function FindCountThatFits1(Canvas: TCanvas; Start: PWideChar; MaxChars, X, Y: Integer;
|
||
|
IMgr: TfrxHtIndentManager; var ImgY, ImgHt: Integer; var DoneFlObjPos: PWideChar): Integer;
|
||
|
{Given a width, find the count of chars (<= Max) which will fit allowing for font changes.
|
||
|
Line wrapping will be done later}
|
||
|
//BG, 06.02.2011: Why are there 2 methods and why can't GetURL and FindCursor use the formatting results of DrawLogic?
|
||
|
// FindCountThatFits1() is part of TfrxHtSection.DrawLogic() and fills IMgr with the embedded floating objects.
|
||
|
// TfrxHtSection.FindCountThatFits() is used in TfrxHtSection.GetURL() and TfrxHtSection.FindCursor().
|
||
|
|
||
|
|
||
|
type
|
||
|
TResultCode = (rsOk, rsContinue, rsBreak);
|
||
|
|
||
|
function DrawLogicOfObject(FlObj: TfrxHtFloatingObj; var XX, YY, Width, Cnt, FloatingImageCount: Integer): TResultCode;
|
||
|
var
|
||
|
X1, X2, W, H: Integer;
|
||
|
begin
|
||
|
Result := rsOk;
|
||
|
if FlObj.Floating in [ALeft, ARight] then
|
||
|
begin
|
||
|
if Start > DoneFlObjPos then
|
||
|
begin
|
||
|
ImgY := Max(Y, ImgY);
|
||
|
W := FlObj.TotalWidth;
|
||
|
H := FlObj.TotalHeight;
|
||
|
case FlObj.Floating of
|
||
|
ALeft:
|
||
|
begin
|
||
|
FlObj.FIndent := IMgr.AlignLeft(ImgY, W) + FlObj.HSpaceL;
|
||
|
IMgr.AddLeft(ImgY, ImgY + H, W);
|
||
|
end;
|
||
|
|
||
|
ARight:
|
||
|
begin
|
||
|
FlObj.FIndent := IMgr.AlignRight(ImgY, W) + FlObj.HSpaceL;
|
||
|
IMgr.AddRight(ImgY, ImgY + H, W);
|
||
|
end;
|
||
|
end;
|
||
|
FlObj.DrawXX := FlObj.FIndent;
|
||
|
FlObj.DrawYY := ImgY + FlObj.VSpaceT;
|
||
|
ImgHt := Max(ImgHt, H);
|
||
|
DoneFlObjPos := Start;
|
||
|
|
||
|
// go on with the line:
|
||
|
X1 := IMgr.LeftIndent(Y);
|
||
|
X2 := IMgr.RightSide(Y);
|
||
|
Width := X2 - X1;
|
||
|
Inc(FloatingImageCount);
|
||
|
if Cnt >= FloatingImageCount then
|
||
|
Result := rsContinue;
|
||
|
end;
|
||
|
end
|
||
|
else if not (FlObj.Positioning in [posAbsolute, posFixed]) then
|
||
|
begin
|
||
|
ImgHt := Max(ImgHt, FlObj.TotalHeight);
|
||
|
Inc(XX, FlObj.TotalWidth);
|
||
|
if XX > Width then
|
||
|
Result := rsBreak;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
var
|
||
|
Cnt,
|
||
|
I, // number of fitting chars
|
||
|
J, // number of chars up to next font change or object
|
||
|
J1, // number of chars up to next font change
|
||
|
J2, // number of chars up to next image
|
||
|
// J3, // number of chars up to next form control
|
||
|
X1, X2, Width, D, H: Integer;
|
||
|
XX: Integer; // current width of row in pixels (== current horizontal position).
|
||
|
YY: Integer; // current height of row in pixels.
|
||
|
Picture: Boolean;
|
||
|
FlObj: TfrxHtFloatingObj; //TfrxHtSizeableObj;
|
||
|
FO: TfrxHtFontObj;
|
||
|
BrChr, TheStart: PWideChar;
|
||
|
//Font,
|
||
|
LastFont: TfrxHtFont;
|
||
|
Save: TSize;
|
||
|
FoundBreak: Boolean;
|
||
|
HyphenWidth: Integer;
|
||
|
FloatingImageCount: Integer;
|
||
|
InitialFloatingLeftCount: Integer;
|
||
|
InitialFloatingRightCount: Integer;
|
||
|
begin
|
||
|
LastFont := nil;
|
||
|
TheStart := Start;
|
||
|
ImgHt := 0;
|
||
|
InitialFloatingLeftCount := IMgr.L.Count;
|
||
|
InitialFloatingRightCount := IMgr.R.Count;
|
||
|
|
||
|
BrChr := StrScanW(TheStart, BrkCh); {see if a break char}
|
||
|
FoundBreak := Assigned(BrChr) and (BrChr - TheStart < MaxChars);
|
||
|
if FoundBreak then
|
||
|
begin
|
||
|
MaxChars := BrChr - TheStart;
|
||
|
if MaxChars = 0 then
|
||
|
begin
|
||
|
Result := 1;
|
||
|
Exit; {single character fits}
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
X1 := IMgr.LeftIndent(Y);
|
||
|
if Start = Buff then
|
||
|
Inc(X1, FirstLineIndent);
|
||
|
X2 := IMgr.RightSide(Y);
|
||
|
Width := X2 - X1;
|
||
|
|
||
|
if (Start = Buff) and (Images.Count = 0) then
|
||
|
if Fonts.GetFontObjAt(0, Len, FO) = Len then
|
||
|
if MaxChars * Fonts[0].tmMaxCharWidth <= Width then {try a shortcut}
|
||
|
begin {it will all fit}
|
||
|
Result := MaxChars;
|
||
|
if FoundBreak then
|
||
|
Inc(Result);
|
||
|
Exit;
|
||
|
end;
|
||
|
|
||
|
FloatingImageCount := -1;
|
||
|
Cnt := 0;
|
||
|
XX := 0;
|
||
|
YY := 0;
|
||
|
while True do
|
||
|
begin
|
||
|
J1 := Min(Fonts.GetFontObjAt(Start - Buff, Len, FO), MaxChars - Cnt);
|
||
|
if FO.TheFont <> LastFont then {may not have to load font}
|
||
|
begin
|
||
|
LastFont := FO.TheFont;
|
||
|
LastFont.AssignToCanvas(Canvas);
|
||
|
end;
|
||
|
J2 := Images.GetObjectAt(Start - Buff, FlObj);
|
||
|
if (J2 = 0) then
|
||
|
begin {next is an object}
|
||
|
I := 1;
|
||
|
J := 1;
|
||
|
Picture := True;
|
||
|
case DrawLogicOfObject(FlObj, XX, YY, Width, Cnt, FloatingImageCount) of
|
||
|
rsContinue:
|
||
|
begin
|
||
|
// after an object floating to the left or right, we must retry to
|
||
|
// fit the remaining space between the floating objects.
|
||
|
Start := TheStart;
|
||
|
Cnt := 0;
|
||
|
XX := 0;
|
||
|
continue;
|
||
|
end;
|
||
|
|
||
|
rsBreak:
|
||
|
break;
|
||
|
end;
|
||
|
end
|
||
|
else
|
||
|
begin
|
||
|
Picture := False;
|
||
|
J := Min(J1, J2);
|
||
|
I := FitText(Canvas.Handle, Start, J, Width - XX, Save);
|
||
|
if (I > 0) and (Brk[TheStart - Buff + Cnt + I - 1] = twSoft) then
|
||
|
begin {a hyphen could go here}
|
||
|
HyphenWidth := Canvas.TextWidth('-');
|
||
|
if XX + Save.cx + HyphenWidth > Width then
|
||
|
Dec(I);
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
if Cnt + I >= MaxChars then
|
||
|
begin
|
||
|
Cnt := MaxChars;
|
||
|
Break;
|
||
|
end
|
||
|
else
|
||
|
Inc(Cnt, I);
|
||
|
|
||
|
if not Picture then {it's a text block}
|
||
|
begin
|
||
|
if I < J then
|
||
|
Break;
|
||
|
XX := XX + Save.cx;
|
||
|
YY := Math.Max(YY, Save.cy);
|
||
|
end;
|
||
|
|
||
|
Inc(Start, I);
|
||
|
end;
|
||
|
Result := Cnt;
|
||
|
|
||
|
if FoundBreak and (Cnt = MaxChars) then
|
||
|
Inc(Result);
|
||
|
|
||
|
// adjust floating objects top position, in case they have been moved down and line height has been changed.
|
||
|
H := YY; //Max(YY, ImgHt);
|
||
|
IMgr.AdjustY(InitialFloatingLeftCount, InitialFloatingRightCount, Y, H);
|
||
|
|
||
|
D := 0;
|
||
|
for I := 0 to Images.Count - 1 do
|
||
|
with Images[I] do
|
||
|
if Floating in [ALeft, ARight] then
|
||
|
if DrawYY > Y + VSpaceT then
|
||
|
begin
|
||
|
if DrawYY < Y + H + VSpaceT then
|
||
|
D := Y + H + VSpaceT - DrawYY;
|
||
|
Inc(DrawYY, D);
|
||
|
end;
|
||
|
|
||
|
end;
|
||
|
|
||
|
procedure DoDrawLogic;
|
||
|
|
||
|
procedure DrawLogicOfObjects(Objects: TFloatingObjList; Width: Integer);
|
||
|
var
|
||
|
I: Integer;
|
||
|
Obj: TfrxHtFloatingObj;
|
||
|
begin
|
||
|
for I := 0 to Objects.Count - 1 do {call drawlogic for all the objects}
|
||
|
begin
|
||
|
Obj := Objects[I];
|
||
|
Obj.DrawLogicInline(Canvas, Fonts.GetFontObjAt(Obj.StartCurs), 0, 0);
|
||
|
// BG, 28.08.2011:
|
||
|
if OwnerBlock.HideOverflow then
|
||
|
begin
|
||
|
if Obj.ClientWidth > Width then
|
||
|
Obj.ClientWidth := Width;
|
||
|
end
|
||
|
else
|
||
|
MaxWidth := Max(MaxWidth, Obj.ClientWidth); {HScrollBar for wide images}
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
var
|
||
|
PStart, Last: PWideChar;
|
||
|
ImgHt: Integer;
|
||
|
Finished: Boolean;
|
||
|
LR: TfrxHtLineRec;
|
||
|
AccumImgBot: Integer;
|
||
|
|
||
|
procedure LineComplete(NN: Integer);
|
||
|
var
|
||
|
I, J, DHt, Desc, Tmp, TmpRt, Cnt, H, SB, SA: Integer;
|
||
|
FO: TfrxHtFontObj;
|
||
|
Align: ThtAlignmentStyle;
|
||
|
NoChar: Boolean;
|
||
|
P: PWideChar;
|
||
|
FlObj: TfrxHtFloatingObj; //TfrxHtSizeableObj;
|
||
|
LRTextWidth: Integer;
|
||
|
OHang: Integer;
|
||
|
|
||
|
function FindSpaces: Integer;
|
||
|
var
|
||
|
I: Integer;
|
||
|
begin
|
||
|
Result := 0;
|
||
|
for I := 0 to NN - 2 do {-2 so as not to count end spaces}
|
||
|
if ((PStart + I)^ = ' ') or ((PStart + I)^ = #160) then
|
||
|
Inc(Result);
|
||
|
end;
|
||
|
|
||
|
begin
|
||
|
DHt := 0; {for the fonts on this line get the maximum height}
|
||
|
Cnt := 0;
|
||
|
Desc := 0;
|
||
|
P := PStart;
|
||
|
if (NN = 1) and (P^ = BrkCh) then
|
||
|
NoChar := False
|
||
|
else
|
||
|
begin
|
||
|
NoChar := True;
|
||
|
for I := 0 to NN - 1 do
|
||
|
begin
|
||
|
case P^ of
|
||
|
FmCtl, ImgPan, BrkCh:;
|
||
|
else
|
||
|
if not ((P = Last) and (Last^ = ' ')) then
|
||
|
begin {check for the no character case}
|
||
|
NoChar := False;
|
||
|
Break;
|
||
|
end;
|
||
|
end;
|
||
|
Inc(P);
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
Align := ANone;
|
||
|
if not NoChar then
|
||
|
begin
|
||
|
repeat
|
||
|
J := Fonts.GetFontObjAt(PStart - Buff + Cnt, Len, FO);
|
||
|
Tmp := FO.GetHeight(Desc);
|
||
|
DHt := Max(DHt, Tmp);
|
||
|
LR.Descent := Max(LR.Descent, Desc);
|
||
|
Inc(Cnt, J);
|
||
|
until Cnt >= NN;
|
||
|
Align := FO.SScript;
|
||
|
end;
|
||
|
|
||
|
{if there are images or line-height, then maybe they add extra space}
|
||
|
SB := 0; // vertical space before DHt / Text
|
||
|
SA := 0; // vertical space after DHt / Text
|
||
|
if not NoChar then
|
||
|
begin
|
||
|
if LineHeight > DHt then
|
||
|
begin
|
||
|
// BG, 28.08.2011: too much space below an image: SA and SB depend on Align:
|
||
|
case Align of
|
||
|
aTop:
|
||
|
SA := LineHeight - DHt;
|
||
|
|
||
|
aMiddle:
|
||
|
begin
|
||
|
SB := (LineHeight - DHt) div 2;
|
||
|
SA := (LineHeight - DHt) - SB;
|
||
|
end;
|
||
|
else
|
||
|
// aNone,
|
||
|
// aBaseline,
|
||
|
// aBottom:
|
||
|
SB := LineHeight - DHt;
|
||
|
end;
|
||
|
end
|
||
|
else if LineHeight >= 0 then
|
||
|
begin
|
||
|
SB := (LineHeight - DHt) div 2;
|
||
|
SA := (LineHeight - DHt) - SB;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
Cnt := 0;
|
||
|
repeat
|
||
|
Inc(Cnt, Images.GetObjectAt(PStart - Buff + Cnt, FlObj));
|
||
|
if Cnt < NN then
|
||
|
begin
|
||
|
H := FlObj.TotalHeight;
|
||
|
if FlObj.Floating = ANone then
|
||
|
begin
|
||
|
FlObj.DrawYY := Y; {approx y dimension}
|
||
|
if not (FlObj.Positioning in [posAbsolute, posFixed]) then
|
||
|
begin
|
||
|
case FlObj.VertAlign of
|
||
|
aTop:
|
||
|
SA := Max(SA, H - DHt);
|
||
|
|
||
|
aMiddle:
|
||
|
begin
|
||
|
if DHt = 0 then
|
||
|
begin
|
||
|
DHt := Fonts.GetFontObjAt(PStart - Buff).GetHeight(Desc);
|
||
|
LR.Descent := Desc;
|
||
|
end;
|
||
|
Tmp := (H - DHt) div 2;
|
||
|
SA := Max(SA, Tmp);
|
||
|
SB := Max(SB, (H - DHt - Tmp));
|
||
|
end;
|
||
|
aBaseline,
|
||
|
aBottom:
|
||
|
SB := Max(SB, H - (DHt - LR.Descent));
|
||
|
end;
|
||
|
end;
|
||
|
end;
|
||
|
end;
|
||
|
Inc(Cnt); {to skip by the image}
|
||
|
until Cnt >= NN;
|
||
|
|
||
|
LR.Start := PStart;
|
||
|
LR.LineHt := DHt;
|
||
|
LR.Ln := NN;
|
||
|
if Brk[PStart - Buff + NN - 1] = twSoft then {see if there is a soft hyphen on the end}
|
||
|
LR.Shy := True;
|
||
|
TmpRt := IMgr.RightSide(Y);
|
||
|
Tmp := IMgr.LeftIndent(Y);
|
||
|
if PStart = Buff then
|
||
|
Inc(Tmp, FirstLineIndent);
|
||
|
|
||
|
LRTextWidth := FindTextSize(Canvas, PStart, NN, True).cx;
|
||
|
if LR.Shy then
|
||
|
begin {take into account the width of the hyphen}
|
||
|
Fonts.GetFontAt(PStart - Buff + NN - 1, OHang).AssignToCanvas(Canvas);
|
||
|
Inc(LRTextWidth, Canvas.TextWidth('-'));
|
||
|
end;
|
||
|
TextWidth := Max(TextWidth, LRTextWidth);
|
||
|
case Justify of
|
||
|
Left: LR.LineIndent := Tmp - X;
|
||
|
Centered: LR.LineIndent := (TmpRt + Tmp - LRTextWidth) div 2 - X;
|
||
|
Right: LR.LineIndent := TmpRt - X - LRTextWidth;
|
||
|
else
|
||
|
{Justify = FullJustify}
|
||
|
LR.LineIndent := Tmp - X;
|
||
|
if not Finished then
|
||
|
begin
|
||
|
LR.Extra := TmpRt - Tmp - LRTextWidth;
|
||
|
LR.Spaces := FindSpaces;
|
||
|
end;
|
||
|
end;
|
||
|
LR.DrawWidth := TmpRt - Tmp;
|
||
|
LR.SpaceBefore := LR.SpaceBefore + SB;
|
||
|
LR.SpaceAfter := SA;
|
||
|
Lines.Add(LR);
|
||
|
Inc(PStart, NN);
|
||
|
SectionHeight := SectionHeight + DHt + SA + LR.SpaceBefore;
|
||
|
Tmp := DHt + SA + SB;
|
||
|
Inc(Y, Tmp);
|
||
|
LR.LineImgHt := Max(Tmp, ImgHt);
|
||
|
end;
|
||
|
|
||
|
var
|
||
|
P: PWideChar;
|
||
|
MaxChars: Integer;
|
||
|
N, NN, Width, I: Integer;
|
||
|
Tmp: Integer;
|
||
|
Obj: TfrxHtFloatingObj;
|
||
|
TopY, HtRef: Integer;
|
||
|
//Ctrl: TFormControlObj;
|
||
|
//BG, 06.02.2011: floating objects:
|
||
|
PDoneFlObj: PWideChar;
|
||
|
YDoneFlObj: Integer;
|
||
|
begin {DoDrawLogic}
|
||
|
SectionHeight := 0;
|
||
|
AccumImgBot := 0;
|
||
|
TopY := Y;
|
||
|
PStart := Buff;
|
||
|
Last := Buff + Len - 1;
|
||
|
if Len = 0 then
|
||
|
begin
|
||
|
Result := GetClearSpace(IMgr, Y);
|
||
|
DrawHeight := Result;
|
||
|
SectionHeight := Result;
|
||
|
ContentBot := Y + Result;
|
||
|
DrawBot := ContentBot;
|
||
|
MaxWidth := 0;
|
||
|
DrawWidth := 0;
|
||
|
Exit;
|
||
|
end;
|
||
|
if FLPercent <> 0 then
|
||
|
FirstLineIndent := (FLPercent * AWidth) div 100; {percentage calculated}
|
||
|
Finished := False;
|
||
|
DrawWidth := IMgr.RightSide(Y) - X;
|
||
|
Width := Min(IMgr.RightSide(Y) - IMgr.LeftIndent(Y), AWidth);
|
||
|
MaxWidth := Width;
|
||
|
if AHeight = 0 then
|
||
|
HtRef := BlHt
|
||
|
else
|
||
|
HtRef := AHeight;
|
||
|
|
||
|
for I := 0 to Images.Count - 1 do {call drawlogic for all the images}
|
||
|
begin
|
||
|
Obj := Images[I];
|
||
|
Obj.DrawLogicInline(Canvas, Fonts.GetFontObjAt(Obj.StartCurs), Width, HtRef);
|
||
|
// BG, 28.08.2011:
|
||
|
if OwnerBlock.HideOverflow then
|
||
|
begin
|
||
|
if Obj.ClientWidth > Width then
|
||
|
Obj.ClientWidth := Width;
|
||
|
end
|
||
|
else
|
||
|
MaxWidth := Max(MaxWidth, Obj.ClientWidth); {HScrollBar for wide images}
|
||
|
end;
|
||
|
|
||
|
YDoneFlObj := Y;
|
||
|
PDoneFlObj := PStart - 1;
|
||
|
while not Finished do
|
||
|
begin
|
||
|
MaxChars := Last - PStart + 1;
|
||
|
if MaxChars <= 0 then
|
||
|
Break;
|
||
|
LR := TfrxHtLineRec.Create(Document); {a new line}
|
||
|
if Lines.Count = 0 then
|
||
|
begin {may need to move down past floating image}
|
||
|
Tmp := GetClearSpace(IMgr, Y);
|
||
|
if Tmp > 0 then
|
||
|
begin
|
||
|
LR.LineHt := Tmp;
|
||
|
Inc(SectionHeight, Tmp);
|
||
|
LR.Ln := 0;
|
||
|
LR.Start := PStart;
|
||
|
Inc(Y, Tmp);
|
||
|
Lines.Add(LR);
|
||
|
LR := TfrxHtLineRec.Create(Document);
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
ImgHt := 0;
|
||
|
NN := 0;
|
||
|
if (WhiteSpaceStyle in [wsPre, wsPreLine, wsNoWrap]) and not BreakWord then
|
||
|
N := MaxChars
|
||
|
else
|
||
|
begin
|
||
|
NN := FindCountThatFits1(Canvas, PStart, MaxChars, X, Y, IMgr, YDoneFlObj, ImgHt, PDoneFlObj);
|
||
|
N := Max(NN, 1); {N = at least 1}
|
||
|
end;
|
||
|
|
||
|
AccumImgBot := Max(AccumImgBot, Y + ImgHt);
|
||
|
if NN = 0 then {if nothing fits, see if we can move down}
|
||
|
Tmp := IMgr.GetNextWiderY(Y) - Y
|
||
|
else
|
||
|
Tmp := 0;
|
||
|
if Tmp > 0 then
|
||
|
begin
|
||
|
//BG, 24.01.2010: do not move down images or trailing spaces.
|
||
|
P := PStart + N - 1; {the last ThtChar that fits}
|
||
|
if ((P^ = SpcChar) {or (P^ = FmCtl,} or (P^ = ImgPan) or WrapChar(P^)) and (Brk[P - Buff] <> twNo) or (P^ = BrkCh) then
|
||
|
begin {move past spaces so as not to print any on next line}
|
||
|
while (N < MaxChars) and ((P + 1)^ = ' ') do
|
||
|
begin
|
||
|
Inc(P);
|
||
|
Inc(N);
|
||
|
end;
|
||
|
Finished := N >= MaxChars;
|
||
|
LineComplete(N);
|
||
|
end
|
||
|
else
|
||
|
begin {move down to where it's wider}
|
||
|
LR.LineHt := Tmp;
|
||
|
Inc(SectionHeight, Tmp);
|
||
|
LR.Ln := 0;
|
||
|
LR.Start := PStart;
|
||
|
Inc(Y, Tmp);
|
||
|
Lines.Add(LR);
|
||
|
end
|
||
|
end {else can't move down or don't have to}
|
||
|
else if N = MaxChars then
|
||
|
begin {Do the remainder}
|
||
|
Finished := True;
|
||
|
LineComplete(N);
|
||
|
end
|
||
|
else
|
||
|
begin
|
||
|
P := PStart + N - 1; {the last ThtChar that fits}
|
||
|
if ((P^ = SpcChar) or (P^ = FmCtl) or (p^ = ImgPan) or WrapChar(P^)) and (Brk[P - Buff] <> twNo) or (P^ = BrkCh) then
|
||
|
begin {move past spaces so as not to print any on next line}
|
||
|
while (N < MaxChars) and ((P + 1)^ = ' ') do
|
||
|
begin
|
||
|
Inc(P);
|
||
|
Inc(N);
|
||
|
end;
|
||
|
Finished := N >= MaxChars;
|
||
|
LineComplete(N);
|
||
|
end
|
||
|
else if (N < MaxChars) and ((P + 1)^ = ' ') and (Brk[P - Buff + 1] <> twNo) then
|
||
|
begin
|
||
|
repeat
|
||
|
Inc(P);
|
||
|
Inc(N); {pass the space}
|
||
|
until (N >= MaxChars) or ((P + 1)^ <> ' ');
|
||
|
Finished := N >= MaxChars;
|
||
|
LineComplete(N);
|
||
|
end
|
||
|
else if (N < MaxChars) and (((P + 1)^ = FmCtl) or ((P + 1)^ = ImgPan)) and (Brk[PStart - Buff + N - 1] <> twNo) then {an image or control}
|
||
|
begin
|
||
|
Finished := False;
|
||
|
LineComplete(N);
|
||
|
end
|
||
|
else
|
||
|
begin
|
||
|
{non space, wrap it by backing off to previous wrappable char}
|
||
|
while P > PStart do
|
||
|
begin
|
||
|
case Brk[P - Buff] of
|
||
|
twNo: ;
|
||
|
|
||
|
twSoft,
|
||
|
twOptional:
|
||
|
break;
|
||
|
|
||
|
else
|
||
|
if CanWrap(P) or WrapChar((P + 1)^) then
|
||
|
break; // can wrap after this or before next char.
|
||
|
end;
|
||
|
Dec(P);
|
||
|
end;
|
||
|
|
||
|
if (P = PStart) and ((not ((P^ = FmCtl) or (P^ = ImgPan))) or (Brk[PStart - Buff] = twNo)) then
|
||
|
begin
|
||
|
{no space found, forget the wrap, write the whole word and any spaces found after it}
|
||
|
if BreakWord then
|
||
|
LineComplete(N)
|
||
|
else
|
||
|
begin
|
||
|
P := PStart + N - 1;
|
||
|
|
||
|
while (P <> Last) and not CanWrapAfter(P) and not (Brk[P - Buff] in [twSoft, twOptional])
|
||
|
do
|
||
|
begin
|
||
|
case Brk[P - Buff + 1] of
|
||
|
twNo: ; // must not wrap after this char.
|
||
|
else
|
||
|
case (P + 1)^ of
|
||
|
' ', FmCtl, ImgPan, BrkCh:
|
||
|
break; // can wrap before this char.
|
||
|
else
|
||
|
if WrapChar((P + 1)^) then
|
||
|
break; // can wrap before this char.
|
||
|
end;
|
||
|
end;
|
||
|
Inc(P);
|
||
|
end;
|
||
|
|
||
|
while (P <> Last) and ((P + 1)^ = ' ') do
|
||
|
begin
|
||
|
Inc(P);
|
||
|
end;
|
||
|
if (P <> Last) and ((P + 1)^ = BrkCh) then
|
||
|
Inc(P);
|
||
|
{Line is too long, add spacer line to where it's clear}
|
||
|
Tmp := IMgr.GetNextWiderY(Y) - Y;
|
||
|
if Tmp > 0 then
|
||
|
begin
|
||
|
LR.LineHt := Tmp;
|
||
|
Inc(SectionHeight, Tmp);
|
||
|
LR.Ln := 0;
|
||
|
LR.Start := PStart;
|
||
|
Inc(Y, Tmp);
|
||
|
Lines.Add(LR);
|
||
|
end
|
||
|
else
|
||
|
begin {line is too long but do it anyway}
|
||
|
MaxWidth := Max(MaxWidth, FindTextSize(Canvas, PStart, P - PStart + 1, True).cx);
|
||
|
Finished := P = Last;
|
||
|
LineComplete(P - PStart + 1);
|
||
|
end;
|
||
|
end
|
||
|
end
|
||
|
else
|
||
|
begin {found space}
|
||
|
while (P + 1)^ = ' ' do
|
||
|
begin
|
||
|
if P = Last then
|
||
|
begin
|
||
|
Inc(P);
|
||
|
Dec(P);
|
||
|
end;
|
||
|
Inc(P);
|
||
|
end;
|
||
|
LineComplete(P - PStart + 1);
|
||
|
end;
|
||
|
end;
|
||
|
end;
|
||
|
end;
|
||
|
Curs := StartCurs + Len;
|
||
|
|
||
|
if Assigned(Document.FirstLineHtPtr) and (Lines.Count > 0) then {used for List items}
|
||
|
with Lines[0] do
|
||
|
if (Document.FirstLineHtPtr^ = 0) then
|
||
|
Document.FirstLineHtPtr^ := YDraw + LineHt - Descent + SpaceBefore;
|
||
|
|
||
|
DrawHeight := AccumImgBot - TopY; {in case image overhangs}
|
||
|
if DrawHeight < SectionHeight then
|
||
|
DrawHeight := SectionHeight;
|
||
|
Result := SectionHeight;
|
||
|
ContentBot := TopY + SectionHeight;
|
||
|
DrawBot := TopY + DrawHeight;
|
||
|
with Document do
|
||
|
begin
|
||
|
ThisCycle := CycleNumber; {only once per cycle}
|
||
|
end;
|
||
|
|
||
|
// BG, 28.08.2011:
|
||
|
if OwnerBlock.HideOverflow then
|
||
|
if MaxWidth > Width then
|
||
|
MaxWidth := Width;
|
||
|
end; { DoDrawLogic}
|
||
|
|
||
|
var
|
||
|
Dummy: Integer;
|
||
|
Save: Integer;
|
||
|
begin {TfrxHtSection.DrawLogic}
|
||
|
YDraw := Y;
|
||
|
DrawTop := Y;
|
||
|
ContentTop := Y;
|
||
|
StartCurs := Curs;
|
||
|
Lines.Clear;
|
||
|
TextWidth := 0;
|
||
|
|
||
|
if WhiteSpaceStyle in [wsPre, wsNoWrap] then
|
||
|
begin
|
||
|
if Len = 0 then
|
||
|
begin
|
||
|
Result := Fonts.GetFontObjAt(0).FontHeight;
|
||
|
SectionHeight := Result;
|
||
|
MaxWidth := 0;
|
||
|
DrawHeight := Result;
|
||
|
ContentBot := Y + Result;
|
||
|
DrawBot := ContentBot;
|
||
|
exit;
|
||
|
end;
|
||
|
|
||
|
if not BreakWord then
|
||
|
begin
|
||
|
{call with large width to prevent wrapping}
|
||
|
Save := IMgr.Width;
|
||
|
IMgr.Width := 32000;
|
||
|
DoDrawLogic;
|
||
|
IMgr.Width := Save;
|
||
|
MinMaxWidth(Canvas, Dummy, MaxWidth, AWidth, AHeight); {return MaxWidth}
|
||
|
exit;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
DoDrawLogic;
|
||
|
|
||
|
end;
|
||
|
|
||
|
{----------------TfrxHtSection.CheckForInlines}
|
||
|
|
||
|
procedure TfrxHtSection.CheckForInlines(LR: TfrxHtLineRec);
|
||
|
{called before each line is drawn the first time to check if there are any
|
||
|
inline borders in the line}
|
||
|
var
|
||
|
I: Integer;
|
||
|
BR: TfrxHtBorderRec;
|
||
|
StartBI, EndBI, LineStart: Integer;
|
||
|
begin
|
||
|
with LR do
|
||
|
begin
|
||
|
FirstDraw := False; {this will turn it off if there is no inline border action in this line}
|
||
|
with TInlineList(Document.InlineList) do
|
||
|
for I := 0 to Count - 1 do {look thru the inlinelist}
|
||
|
begin
|
||
|
StartBI := StartB[I];
|
||
|
EndBI := EndB[I];
|
||
|
LineStart := StartCurs + (Start - Buff); {offset from Section start to Line start}
|
||
|
if (EndBI > LineStart) and (StartBI < LineStart + Ln) then
|
||
|
begin {it's in this line}
|
||
|
if not Assigned(BorderList) then
|
||
|
begin
|
||
|
BorderList := TfrxHtBorderRecList.Create;
|
||
|
FirstDraw := True; {there will be more processing needed}
|
||
|
end;
|
||
|
BR := TfrxHtBorderRec.Create;
|
||
|
BorderList.Add(BR);
|
||
|
with BR do
|
||
|
begin
|
||
|
BR.MargArray := Items[I].MargArray; {get border data}
|
||
|
if StartBI < LineStart then
|
||
|
begin
|
||
|
OpenStart := True; {continuation of border on line above, end is open}
|
||
|
BStart := Start - Buff; {start of this line}
|
||
|
end
|
||
|
else
|
||
|
begin
|
||
|
OpenStart := False;
|
||
|
BStart := StartBI - StartCurs; {start is in this line}
|
||
|
end;
|
||
|
if EndBI > LineStart + Ln then
|
||
|
begin
|
||
|
OpenEnd := True; {will continue on next line, end is open}
|
||
|
BEnd := Start - Buff + Ln;
|
||
|
end
|
||
|
else
|
||
|
begin
|
||
|
OpenEnd := False;
|
||
|
BEnd := EndBI - StartCurs; {end is in this line}
|
||
|
end;
|
||
|
end;
|
||
|
end;
|
||
|
end;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
{----------------TfrxHtSection.Draw}
|
||
|
|
||
|
function TfrxHtSection.Draw1(Canvas: TCanvas; const ARect: TRect;
|
||
|
IMgr: TfrxHtIndentManager; X, XRef, YRef: Integer): Integer;
|
||
|
var
|
||
|
YOffset, Y, Desc: Integer;
|
||
|
|
||
|
procedure DrawTheText(LineNo: Integer);
|
||
|
var
|
||
|
I, J, J1, J2, J3,
|
||
|
Addon, TopP, BottomP, Tmp, OutX, K: Integer;
|
||
|
FlObj: TfrxHtFloatingObj;
|
||
|
FO: TfrxHtFontObj;
|
||
|
ARect: TRect;
|
||
|
Inverted, NewCP: Boolean;
|
||
|
ForeColor, BackColor: TColor;
|
||
|
BkMode: Integer;
|
||
|
CPx, CPy, CP1x: Integer;
|
||
|
BR: TfrxHtBorderRec;
|
||
|
LR: TfrxHtLineRec;
|
||
|
Start, OutStart: PWideChar;
|
||
|
Cnt, Descent: Integer;
|
||
|
St: ThtString;
|
||
|
|
||
|
function AddHyphen(P: PWideChar; N: Integer): ThtString;
|
||
|
var
|
||
|
I: Integer;
|
||
|
begin
|
||
|
SetLength(Result, N + 1);
|
||
|
for I := 1 to N do
|
||
|
Result[I] := P[I - 1];
|
||
|
Result[N + 1] := ThtChar('-');
|
||
|
end;
|
||
|
|
||
|
function ChkInversion(Start: PWideChar; out Count: Integer): Boolean;
|
||
|
var
|
||
|
LongCount: Integer;
|
||
|
begin
|
||
|
Result := False;
|
||
|
Count := 32000;
|
||
|
if IsCopy then
|
||
|
Exit;
|
||
|
LongCount := 32000;
|
||
|
if LongCount > 32000 then
|
||
|
Count := 32000
|
||
|
else
|
||
|
Count := LongCount;
|
||
|
end;
|
||
|
|
||
|
begin {Y is at bottom of line here}
|
||
|
LR := Lines[LineNo];
|
||
|
Start := LR.Start;
|
||
|
Cnt := LR.Ln;
|
||
|
Descent := LR.Descent;
|
||
|
|
||
|
NewCP := True;
|
||
|
CPy := Y + LR.DrawY; //Todo: Someone needs to find a sensible default value.
|
||
|
CPx := X + LR.LineIndent;
|
||
|
|
||
|
// {$IFDEF DELPHI12}
|
||
|
// {$IFNDEF Compiler32_Plus}CP1x := CPx;{$ENDIF}
|
||
|
// {$ENDIF}
|
||
|
LR.DrawY := Y - LR.LineHt;
|
||
|
LR.DrawXX := CPx;
|
||
|
while Cnt > 0 do
|
||
|
begin
|
||
|
I := 1;
|
||
|
J1 := Fonts.GetFontObjAt(Start - Buff, Len, FO) - 1;
|
||
|
J2 := Images.GetObjectAt(Start - Buff, FlObj) - 1;
|
||
|
|
||
|
{if an inline border, find it's boundaries}
|
||
|
if LR.FirstDraw and Assigned(LR.BorderList) then
|
||
|
for K := 0 to LR.BorderList.Count - 1 do {may be several inline borders}
|
||
|
begin
|
||
|
BR := LR.BorderList[K];
|
||
|
if (Start - Buff = BR.BStart) then
|
||
|
begin {this is it's start}
|
||
|
BR.bRect.Top := Y - FO.GetHeight(Desc) - Descent + Desc + 1;
|
||
|
BR.bRect.Left := CPx;
|
||
|
BR.bRect.Bottom := Y - Descent + Desc;
|
||
|
end
|
||
|
else if (Start - Buff = BR.BEnd) and (BR.bRect.Right = 0) then
|
||
|
BR.bRect.Right := CPx {this is it's end}
|
||
|
else if (Start - Buff > BR.BStart) and (Start - Buff < BR.BEnd) then
|
||
|
begin {this is position within boundary, it's top or bottom may enlarge}
|
||
|
BR.bRect.Top := Min(BR.bRect.Top, Y - FO.GetHeight(Desc) - Descent + Desc + 1);
|
||
|
BR.bRect.Bottom := Max(BR.bRect.Bottom, Y - Descent + Desc);
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
FO.TheFont.AssignToCanvas(Canvas);
|
||
|
ForeColor := Canvas.Font.Color;
|
||
|
BackColor := FO.TheFont.bgColor;
|
||
|
if ForeColor <> clNone then
|
||
|
ForeColor := ThemedColor(ForeColor);
|
||
|
if BackColor <> clNone then
|
||
|
BackColor := ThemedColor(BackColor);
|
||
|
Canvas.Font.Color := ForeColor;
|
||
|
if J2 = -1 then
|
||
|
begin {it's an image or panel}
|
||
|
if FlObj is TfrxFrHtImageObj then
|
||
|
begin
|
||
|
if FlObj.Floating in [ALeft, ARight] then
|
||
|
begin
|
||
|
//BG, 02.03.2011: Document is the Document, thus we must
|
||
|
// feed it with document coordinates: X,Y is in document coordinates,
|
||
|
// but might not be the coordinates of the upper left corner of the
|
||
|
// containing block, the origin of the Obj's coordinates. If each block
|
||
|
// had its own IMgr and nested blocks had nested IMgrs with coordinates
|
||
|
// relative to the containing block, the document coordinates of an inner
|
||
|
// block were the sum of all LfEdges of the containing blocks.
|
||
|
//
|
||
|
// correct x-position for floating images: IMgr.LfEdge + Obj.Indent
|
||
|
if not LR.FirstDraw then
|
||
|
Document.DrawList.AddImage(TfrxFrHtImageObj(FlObj), Canvas,
|
||
|
IMgr.LfEdge + FlObj.FIndent, FlObj.DrawYY, Y - Descent, FO)
|
||
|
else if Assigned(LR.BorderList) then
|
||
|
{if a boundary is on a floating image, remove it}
|
||
|
for K := LR.BorderList.Count - 1 downto 0 do
|
||
|
begin
|
||
|
BR := LR.BorderList[K];
|
||
|
if (Start - Buff = BR.BStart) and (BR.BEnd = BR.BStart + 1) then
|
||
|
LR.BorderList.Delete(K);
|
||
|
end;
|
||
|
end
|
||
|
else
|
||
|
begin
|
||
|
SetTextJustification(Canvas.Handle, 0, 0);
|
||
|
// if OwnerBlock <> nil then
|
||
|
// FlObj.Positioning := OwnerBlock.Positioning
|
||
|
// else
|
||
|
// FlObj.Positioning := posStatic;
|
||
|
TfrxFrHtImageObj(FlObj).DrawInline(Canvas, CPx + FlObj.HSpaceL, LR.DrawY, Y - Descent, FO);
|
||
|
Document.Printed := True;
|
||
|
{see if there's an inline border for the image}
|
||
|
if LR.FirstDraw and Assigned(LR.BorderList) then
|
||
|
for K := 0 to LR.BorderList.Count - 1 do
|
||
|
begin
|
||
|
BR := LR.BorderList[K];
|
||
|
if (Start - Buff >= BR.BStart) and (Start - Buff <= BR.BEnd) then
|
||
|
begin {there is a border here, find the image dimensions}
|
||
|
TopP := 0;
|
||
|
if not (FlObj.Positioning in [posAbsolute, posFixed]) then
|
||
|
begin
|
||
|
case FlObj.VertAlign of
|
||
|
|
||
|
ATop, ANone:
|
||
|
TopP := Y - LR.LineHt + FlObj.VSpaceT;
|
||
|
|
||
|
AMiddle:
|
||
|
TopP := Y - Descent + FO.Descent - FO.tmHeight div 2 - (FlObj.ClientHeight - FlObj.VSpaceT + FlObj.VSpaceB) div 2;
|
||
|
|
||
|
ABottom, ABaseline:
|
||
|
TopP := Y - Descent - FlObj.VSpaceB - FlObj.ClientHeight;
|
||
|
|
||
|
end;
|
||
|
BottomP := TopP + FlObj.ClientHeight;
|
||
|
|
||
|
if Start - Buff = BR.BStart then
|
||
|
begin {border starts at image}
|
||
|
BR.bRect.Top := TopP;
|
||
|
BR.bRect.Left := CPx + FlObj.HSpaceL;
|
||
|
if BR.BEnd = BR.BStart + 1 then {border ends with image also, rt side set by image width}
|
||
|
BR.bRect.Right := BR.bRect.Left + FlObj.ClientWidth;
|
||
|
BR.bRect.Bottom := BottomP;
|
||
|
end
|
||
|
else if Start - Buff <> BR.BEnd then
|
||
|
begin {image is included in border and may effect the border top and bottom}
|
||
|
BR.bRect.Top := Min(BR.bRect.Top, TopP);
|
||
|
BR.bRect.Bottom := Max(BR.bRect.Bottom, BottomP);
|
||
|
end;
|
||
|
end
|
||
|
else if FlObj.Positioning in [posAbsolute, posFixed] {differ only when scrolling} then
|
||
|
BR.BRect := Bounds(FlObj.DrawXX, FlObj.DrawYY, FlObj.ClientWidth - 1 {?}, FlObj.ClientHeight)
|
||
|
;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
if not (FlObj.Positioning in [posAbsolute, posFixed]) then
|
||
|
begin
|
||
|
CPx := CPx + FlObj.TotalWidth;
|
||
|
NewCP := True;
|
||
|
end;
|
||
|
end;
|
||
|
end
|
||
|
end
|
||
|
else
|
||
|
begin
|
||
|
J := Min(J1, J2);
|
||
|
Inverted := ChkInversion(Start, J3);
|
||
|
J := Min(J, J3 - 1);
|
||
|
I := Min(Cnt, J + 1);
|
||
|
|
||
|
BkMode := Opaque;
|
||
|
if Inverted then
|
||
|
begin
|
||
|
if BackColor = clNone then
|
||
|
Canvas.Font.Color := ForeColor xor $FFFFFF
|
||
|
else
|
||
|
Canvas.Font.Color := BackColor;
|
||
|
BackColor := ForeColor;
|
||
|
end
|
||
|
else
|
||
|
if BackColor = clNone then
|
||
|
BkMode := Transparent;
|
||
|
|
||
|
if BkMode = Opaque then
|
||
|
begin
|
||
|
Canvas.Brush.Color := BackColor;
|
||
|
Canvas.Brush.Style := bsSolid;
|
||
|
{$ifdef LCLgtk2}
|
||
|
// background is missing if Canvas.Brush.Color = GetBkColor(Canvas.Handle)
|
||
|
if Canvas.Brush.Color = GetBkColor(Canvas.Handle) then
|
||
|
Canvas.Brush.Color := Canvas.Brush.Color xor $010101;
|
||
|
{$endif}
|
||
|
end
|
||
|
else
|
||
|
Canvas.Brush.Style := bsClear;
|
||
|
SetBkMode(Canvas.Handle, BkMode);
|
||
|
|
||
|
SetTextAlign(Canvas.Handle, TA_BaseLine);
|
||
|
{figure any offset for subscript or superscript}
|
||
|
with FO do
|
||
|
if SScript = ANone then
|
||
|
Addon := 0
|
||
|
else if SScript = ASuper then
|
||
|
Addon := -(FontHeight div 3)
|
||
|
else
|
||
|
Addon := Descent div 2 + 1;
|
||
|
NewCP := NewCP or (Addon <> 0);
|
||
|
{calc a new CP if required}
|
||
|
if NewCP then
|
||
|
begin
|
||
|
CPy := Y - Descent + Addon - YOffset;
|
||
|
NewCP := Addon <> 0;
|
||
|
end;
|
||
|
|
||
|
if not Document.NoOutput and (Canvas.Font.Size <> 0) and (Canvas.Font.Color <> clNone) then
|
||
|
begin
|
||
|
Tmp := I;
|
||
|
if Cnt - I <= 0 then
|
||
|
case (Start + I - 1)^ of
|
||
|
' ', BrkCh:
|
||
|
Dec(Tmp); {at end of line, don't show space or break}
|
||
|
end;
|
||
|
|
||
|
if (WhiteSpaceStyle in [wsPre, wsPreLine, wsNoWrap]) and not OwnerBlock.HideOverflow then
|
||
|
begin {so will clip in Table cells}
|
||
|
ARect := Rect(IMgr.LfEdge, Y - LR.LineHt - LR.SpaceBefore - YOffset, X + IMgr.ClipWidth, Y - YOffset + 1);
|
||
|
if Direction = diRTL then
|
||
|
ExtTextOutW(Canvas.Handle, CPx, CPy, ETO_CLIPPED + ETO_RTLREADING, @ARect, Start, Tmp, nil)
|
||
|
else
|
||
|
ExtTextOutW(Canvas.Handle, CPx, CPy, ETO_CLIPPED, @ARect, Start, Tmp, nil);
|
||
|
CP1x := CPx + GetTextExtent(Canvas.Handle, Start, Tmp).cx;
|
||
|
end
|
||
|
else
|
||
|
begin
|
||
|
if LR.Spaces = 0 then
|
||
|
SetTextJustification(Canvas.Handle, 0, 0)
|
||
|
else
|
||
|
SetTextJustification(Canvas.Handle, LR.Extra, LR.Spaces);
|
||
|
|
||
|
if (Cnt - I <= 0) and LR.Shy then
|
||
|
begin
|
||
|
St := AddHyphen(Start, Tmp);
|
||
|
OutStart := PWideChar(St);
|
||
|
Tmp := Length(St);
|
||
|
end
|
||
|
else
|
||
|
OutStart := Start;
|
||
|
|
||
|
if Direction = diRTL then
|
||
|
SetTextAlign(Canvas.Handle, TA_BASELINE or TA_RTLREADING or TA_RIGHT);
|
||
|
|
||
|
CP1x := CPx + GetTextExtent(Canvas.Handle, OutStart, Tmp).cx;
|
||
|
OutX := IfInt(Direction = diRTL, CP1x - IfInt(OwnerBlock is TfrxHtBlockLI, 40), CPx);
|
||
|
|
||
|
TextOutW(Canvas.Handle, OutX, CPy, OutStart, Tmp);
|
||
|
end;
|
||
|
Document.Printed := True;
|
||
|
|
||
|
if FO.Active or IsCopy and Assigned(Document.LinkDrawnEvent)
|
||
|
and (FO.UrlTarget.Url <> '') then
|
||
|
begin
|
||
|
Tmp := Y - Descent + FO.Descent + Addon - YOffset;
|
||
|
ARect := Rect(CPx, Tmp - FO.FontHeight, CP1x + 1, Tmp);
|
||
|
if FO.Active then
|
||
|
begin
|
||
|
Canvas.Brush.Color := clWhite;
|
||
|
Canvas.Font.Color := clBlack; {black font needed for DrawFocusRect}
|
||
|
Canvas.Handle; {Dummy call needed to make Delphi add font color change to handle}
|
||
|
end;
|
||
|
if Assigned(Document.LinkDrawnEvent) then
|
||
|
Document.LinkDrawnEvent(Document.TheOwner, Document.LinkPage,
|
||
|
FO.UrlTarget.Url, FO.UrlTarget.Target, ARect);
|
||
|
end;
|
||
|
CPx := CP1x;
|
||
|
|
||
|
end;
|
||
|
end;
|
||
|
Dec(Cnt, I);
|
||
|
Inc(Start, I);
|
||
|
end;
|
||
|
SetTextJustification(Canvas.Handle, 0, 0);
|
||
|
{at the end of this line. see if there are open borders which need right side set}
|
||
|
if LR.FirstDraw and Assigned(LR.BorderList) then
|
||
|
for K := 0 to LR.BorderList.Count - 1 do
|
||
|
begin
|
||
|
BR := LR.BorderList[K];
|
||
|
if BR.OpenEnd or (BR.BRect.Right = 0) then
|
||
|
BR.BRect.Right := CPx;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
procedure DoDraw(I: Integer);
|
||
|
{draw the Ith line in this section}
|
||
|
var
|
||
|
BR: TfrxHtBorderRec;
|
||
|
K: Integer;
|
||
|
XOffset: Integer;
|
||
|
begin
|
||
|
with Lines[I] do
|
||
|
begin
|
||
|
Inc(Y, LineHt + SpaceBefore);
|
||
|
if FirstDraw then
|
||
|
begin {see if any inline borders in this line}
|
||
|
CheckForInlines(Lines[I]);
|
||
|
if FirstDraw then {if there are, need a first pass to get boundaries}
|
||
|
begin
|
||
|
FirstX := X;
|
||
|
DrawTheText(I);
|
||
|
end;
|
||
|
end;
|
||
|
XOffset := X - FirstX;
|
||
|
FirstDraw := False;
|
||
|
Drawn := True;
|
||
|
if Assigned(BorderList) then {draw any borders found in this line}
|
||
|
for K := 0 to BorderList.Count - 1 do
|
||
|
begin
|
||
|
BR := BorderList[K];
|
||
|
BR.DrawTheBorder(Canvas, XOffset, YOffSet, False);
|
||
|
end;
|
||
|
DrawTheText(I); {draw the text, etc., in this line}
|
||
|
Inc(Y, SpaceAfter);
|
||
|
end;
|
||
|
Document.FirstPageItem := False;
|
||
|
end;
|
||
|
|
||
|
var
|
||
|
I: Integer;
|
||
|
DC: HDC;
|
||
|
begin {TfrxHtSection.Draw}
|
||
|
Y := YDraw;
|
||
|
Result := Y + SectionHeight;
|
||
|
|
||
|
if (OwnerBlock <> nil) and (OwnerBlock.Positioning = posFixed) then
|
||
|
YOffset := 0
|
||
|
else
|
||
|
YOffset := Document.YOff;
|
||
|
|
||
|
{Only draw if will be in display rectangle}
|
||
|
if (Len > 0) and (Y - YOffset + DrawHeight + 40 >= ARect.Top) and (Y - YOffset - 40 < ARect.Bottom) then
|
||
|
begin
|
||
|
DC := Canvas.Handle;
|
||
|
SetTextAlign(DC, TA_BaseLine);
|
||
|
for I := 0 to Lines.Count - 1 do
|
||
|
with Lines[I] do
|
||
|
if ((Y - YOffset + LineImgHt + 40 >= ARect.Top) and (Y - YOffset - 40 < ARect.Bottom)) then
|
||
|
DoDraw(I)
|
||
|
else {do not completely draw extremely long paragraphs}
|
||
|
Inc(Y, SpaceBefore + LineHt + SpaceAfter);
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
{----------------TfrxHtSection.FindString}
|
||
|
|
||
|
function TfrxHtSection.FindString(From: Integer; const ToFind: UnicodeString; MatchCase: Boolean): Integer;
|
||
|
{find the first occurance of the ThtString, ToFind, with a cursor value >= From.
|
||
|
ToFind is in lower case if MatchCase is False. ToFind is known to have a length of at least one.
|
||
|
}
|
||
|
var
|
||
|
P: PWideChar;
|
||
|
I: Integer;
|
||
|
ToSearch: UnicodeString;
|
||
|
|
||
|
begin
|
||
|
Result := -1;
|
||
|
if (Len = 0) or (From >= StartCurs + Len) then
|
||
|
Exit;
|
||
|
if From < StartCurs then
|
||
|
I := 0
|
||
|
else
|
||
|
I := From - StartCurs;
|
||
|
|
||
|
if MatchCase then
|
||
|
ToSearch := BuffS
|
||
|
else
|
||
|
ToSearch := htLowerCase(BuffS); {ToFind already lower case}
|
||
|
|
||
|
P := StrPosW(PWideChar(ToSearch) + I, PWideChar(ToFind));
|
||
|
if Assigned(P) then
|
||
|
Result := StartCurs + (P - PWideChar(ToSearch));
|
||
|
end;
|
||
|
|
||
|
{----------------TfrxHtSection.FindStringR}
|
||
|
|
||
|
function TfrxHtSection.FindStringR(From: Integer; const ToFind: UnicodeString; MatchCase: Boolean): Integer;
|
||
|
{find the first occurance of the ThtString, ToFind, with a cursor value <= to From.
|
||
|
ToFind is in lower case if MatchCase is False. ToFind is known to have a length of at least one.
|
||
|
}
|
||
|
var
|
||
|
P: PWideChar;
|
||
|
ToFindLen: word;
|
||
|
ToMatch, ToSearch: UnicodeString;
|
||
|
|
||
|
begin
|
||
|
Result := -1;
|
||
|
if (Len = 0) or (From < StartCurs) then
|
||
|
Exit;
|
||
|
ToFindLen := Length(ToFind);
|
||
|
if (Len < ToFindLen) or (From - StartCurs + 1 < ToFindLen) then
|
||
|
Exit;
|
||
|
|
||
|
if From >= StartCurs + Len then
|
||
|
ToSearch := BuffS {search all of BuffS}
|
||
|
else
|
||
|
ToSearch := Copy(BuffS, 1, From - StartCurs); {Search smaller part}
|
||
|
if not MatchCase then
|
||
|
ToSearch := htLowerCase(ToSearch); {ToFind already lower case}
|
||
|
|
||
|
{search backwards for the end ThtChar of ToFind}
|
||
|
P := StrRScanW(PWideChar(ToSearch), ToFind[ToFindLen]);
|
||
|
while Assigned(P) and (P - PWideChar(ToSearch) + 1 >= ToFindLen) do
|
||
|
begin
|
||
|
{pick out a ThtString of proper length from end ThtChar to see if it matches}
|
||
|
SetString(ToMatch, P - ToFindLen + 1, ToFindLen);
|
||
|
if WideSameStr1(ToFind, ToMatch) then
|
||
|
begin {matches, return the cursor position}
|
||
|
Result := StartCurs + (P - ToFindLen + 1 - PWideChar(ToSearch));
|
||
|
Exit;
|
||
|
end;
|
||
|
{doesn't match, shorten ThtString to search for next search}
|
||
|
ToSearch := Copy(ToSearch, 1, P - PWideChar(ToSearch));
|
||
|
{and search backwards for end ThtChar again}
|
||
|
P := StrRScanW(PWideChar(ToSearch), ToFind[ToFindLen]);
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
{----------------TfrxHtSection.FindSourcePos}
|
||
|
|
||
|
function TfrxHtSection.FindSourcePos(DocPos: Integer): Integer;
|
||
|
var
|
||
|
I: Integer;
|
||
|
IO: TfrxHtIndexObj;
|
||
|
begin
|
||
|
Result := -1;
|
||
|
if (Len = 0) or (DocPos >= StartCurs + Len) then
|
||
|
Exit;
|
||
|
|
||
|
for I := SIndexList.Count - 1 downto 0 do
|
||
|
begin
|
||
|
IO := PosIndex[I];
|
||
|
if IO.Pos <= DocPos - StartCurs then
|
||
|
begin
|
||
|
Result := IO.Index + DocPos - StartCurs - IO.Pos;
|
||
|
break;
|
||
|
end;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
{----------------TfrxHtSection.FindDocPos}
|
||
|
|
||
|
function TfrxHtSection.FindDocPos(SourcePos: Integer; Prev: Boolean): Integer;
|
||
|
{for a given Source position, find the nearest document position either Next or
|
||
|
previous}
|
||
|
var
|
||
|
I: Integer;
|
||
|
IO, IOPrev: TfrxHtIndexObj;
|
||
|
begin
|
||
|
Result := -1;
|
||
|
if Len = 0 then
|
||
|
Exit;
|
||
|
|
||
|
if not Prev then
|
||
|
begin
|
||
|
I := SIndexList.Count - 1;
|
||
|
IO := PosIndex[I];
|
||
|
if SourcePos > IO.Index + (Len - 1) - IO.Pos then
|
||
|
Exit; {beyond this section}
|
||
|
|
||
|
IOPrev := PosIndex[0];
|
||
|
if SourcePos <= IOPrev.Index then
|
||
|
begin {in this section but before the start of Document text}
|
||
|
Result := StartCurs;
|
||
|
Exit;
|
||
|
end;
|
||
|
|
||
|
for I := 1 to SIndexList.Count - 1 do
|
||
|
begin
|
||
|
IO := PosIndex[I];
|
||
|
if (SourcePos >= IOPrev.Index) and (SourcePos < IO.Index) then
|
||
|
begin {between IOprev and IO}
|
||
|
if SourcePos - IOPrev.Index + IOPrev.Pos < IO.Pos then
|
||
|
Result := StartCurs + IOPrev.Pos + (SourcePos - IOPrev.Index)
|
||
|
else
|
||
|
Result := StartCurs + IO.Pos;
|
||
|
Exit;
|
||
|
end;
|
||
|
IOPrev := IO;
|
||
|
end;
|
||
|
{after the last TfrxHtIndexObj in list}
|
||
|
Result := StartCurs + IOPrev.Pos + (SourcePos - IOPrev.Index);
|
||
|
end
|
||
|
else {prev -- we're iterating from the end of TfrxHtDocument}
|
||
|
begin
|
||
|
IOPrev := PosIndex[0];
|
||
|
if SourcePos < IOPrev.Index then
|
||
|
Exit; {before this section}
|
||
|
|
||
|
I := SIndexList.Count - 1;
|
||
|
IO := PosIndex[I];
|
||
|
if SourcePos > IO.Index + (Len - 1) - IO.Pos then
|
||
|
begin {SourcePos is after the end of this section}
|
||
|
Result := StartCurs + (Len - 1);
|
||
|
Exit;
|
||
|
end;
|
||
|
|
||
|
for I := 1 to SIndexList.Count - 1 do
|
||
|
begin
|
||
|
IO := PosIndex[I];
|
||
|
if (SourcePos >= IOPrev.Index) and (SourcePos < IO.Index) then
|
||
|
begin {between IOprev and IO}
|
||
|
if SourcePos - IOPrev.Index + IOPrev.Pos < IO.Pos then
|
||
|
Result := StartCurs + IOPrev.Pos + (SourcePos - IOPrev.Index)
|
||
|
else
|
||
|
Result := StartCurs + IO.Pos - 1;
|
||
|
Exit;
|
||
|
end;
|
||
|
IOPrev := IO;
|
||
|
end;
|
||
|
{after the last TfrxHtIndexObj in list}
|
||
|
Result := StartCurs + IOPrev.Pos + (SourcePos - IOPrev.Index);
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
{----------------TfrxHtSection.GetChAtPos}
|
||
|
|
||
|
function TfrxHtSection.GetChAtPos(Pos: Integer; out Ch: WideChar; out Obj: TfrxHtSectionBase): Boolean;
|
||
|
begin
|
||
|
Result := False;
|
||
|
if (Len = 0) or (Pos < StartCurs) or (Pos >= StartCurs + Len) then
|
||
|
Exit;
|
||
|
Ch := Buff[Pos - StartCurs];
|
||
|
Obj := Self;
|
||
|
Result := True;
|
||
|
end;
|
||
|
|
||
|
{----------------TfrxHtCell.Create}
|
||
|
|
||
|
constructor TfrxHtCell.Create(Parent: TfrxHtBlock);
|
||
|
begin
|
||
|
inherited Create(Parent);
|
||
|
IMgr := TfrxHtIndentManager.Create;
|
||
|
end;
|
||
|
|
||
|
{----------------TfrxHtCell.CreateCopy}
|
||
|
|
||
|
constructor TfrxHtCell.CreateCopy(Parent: TfrxHtBlock; T: TfrxHtCellBasic);
|
||
|
begin
|
||
|
inherited CreateCopy(Parent, T);
|
||
|
IMgr := TfrxHtIndentManager.Create;
|
||
|
end;
|
||
|
|
||
|
destructor TfrxHtCell.Destroy;
|
||
|
begin
|
||
|
IMgr.Free;
|
||
|
inherited Destroy;
|
||
|
end;
|
||
|
|
||
|
{----------------TfrxHtCell.DoLogic}
|
||
|
|
||
|
function TfrxHtCell.DoLogic(Canvas: TCanvas; Y: Integer; Width, AHeight, BlHt: Integer;
|
||
|
var ScrollWidth, Curs: Integer; ARemainHeight: Integer): Integer;
|
||
|
{Do the entire layout of the cell or document. Return the total document pixel height}
|
||
|
var
|
||
|
IB: Integer;
|
||
|
LIndex, RIndex: Integer;
|
||
|
SaveID: TObject;
|
||
|
begin
|
||
|
IMgr.Init(0, Width);
|
||
|
SaveID := IMgr.CurrentID;
|
||
|
IMgr.CurrentID := Self;
|
||
|
|
||
|
LIndex := IMgr.SetLeftIndent(0, Y);
|
||
|
RIndex := IMgr.SetRightIndent(0 + Width, Y);
|
||
|
|
||
|
Result := inherited DoLogic(Canvas, Y, Width, AHeight, BlHt, ScrollWidth, Curs, ARemainHeight);
|
||
|
|
||
|
IMgr.FreeLeftIndentRec(LIndex);
|
||
|
IMgr.FreeRightIndentRec(RIndex);
|
||
|
IB := IMgr.ImageBottom - Y; //YValue; {check for image overhang}
|
||
|
IMgr.CurrentID := SaveID;
|
||
|
if IB > Result then
|
||
|
Result := IB;
|
||
|
end;
|
||
|
|
||
|
{----------------TfrxHtCell.Draw}
|
||
|
|
||
|
function TfrxHtCell.Draw(Canvas: TCanvas; ARect: TRect; ClipWidth, X, Y, XRef, YRef: Integer): Integer;
|
||
|
{draw the document or cell. Note: individual sections not in ARect don't bother drawing}
|
||
|
begin
|
||
|
IMgr.Reset(X);
|
||
|
IMgr.ClipWidth := ClipWidth;
|
||
|
DrawYY := Y; {This is overridden in TfrxHtCellObj.Draw}
|
||
|
Result := inherited Draw(Canvas, ARect, ClipWidth, X, Y, XRef, YRef);
|
||
|
end;
|
||
|
|
||
|
{----------------TfrxHtCellObjCell.CreateCopy}
|
||
|
|
||
|
constructor TfrxHtCellObjCell.CreateCopy(Parent: TfrxHtBlock; T: TfrxHtCellObjCell);
|
||
|
begin
|
||
|
inherited CreateCopy(Parent, T);
|
||
|
MyRect := T.MyRect;
|
||
|
end;
|
||
|
|
||
|
{ TfrxHtBlockCell }
|
||
|
|
||
|
function TfrxHtBlockCell.DoLogicX(Canvas: TCanvas; X, Y, XRef, YRef, Width, AHeight, BlHt: Integer;
|
||
|
out ScrollWidth: Integer; var Curs: Integer; ARemainHeight: Integer): Integer;
|
||
|
{Do the entire layout of the this cell. Return the total pixel height}
|
||
|
|
||
|
function DoBlockLogic: Integer;
|
||
|
// Returns CellHeight
|
||
|
var
|
||
|
I, Sw, Tmp: Integer;
|
||
|
SB: TfrxHtSectionBase;
|
||
|
begin
|
||
|
Result := 0;
|
||
|
for I := 0 to Count - 1 do
|
||
|
begin
|
||
|
SB := Items[I];
|
||
|
Sw := 0;
|
||
|
//TODO: clean it !
|
||
|
if (ARemainHeight > 0) then
|
||
|
Tmp := SB.DrawLogic1(Canvas, X, Y + Result, XRef, YRef, Width, AHeight, BlHt, IMgr, Sw, Curs, ARemainHeight - Result)
|
||
|
else
|
||
|
Tmp := SB.DrawLogic1(Canvas, X, Y + Result, XRef, YRef, Width, AHeight, BlHt, IMgr, Sw, Curs, 0);
|
||
|
if (ARemainHeight > 0) and (ARemainHeight < Tmp + Result) and (Result > 0 ) then
|
||
|
Break;
|
||
|
|
||
|
Inc(Result, Tmp);
|
||
|
if OwnerBlock.HideOverflow then
|
||
|
ScrollWidth := Width
|
||
|
else
|
||
|
ScrollWidth := Max(ScrollWidth, Sw);
|
||
|
if SB is TfrxHtSection then
|
||
|
TextWidth := Max(TextWidth, TfrxHtSection(SB).TextWidth);
|
||
|
if not (SB is TfrxHtBlock) or (TfrxHtBlock(SB).Positioning <> posAbsolute) then
|
||
|
tcContentBot := Max(tcContentBot, SB.ContentBot);
|
||
|
tcDrawTop := Min(tcDrawTop, SB.DrawTop);
|
||
|
tcDrawBot := Max(tcDrawBot, SB.DrawBot);
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
//TODO -oBG, 15.03.2014: support display:inline
|
||
|
{$ifdef DO_PD_INLINE}
|
||
|
// function DoInlineLogic: Integer;
|
||
|
// // Returns CellHeight
|
||
|
// var
|
||
|
// I, Sw, Tmp: Integer;
|
||
|
// LineSize: TSize;
|
||
|
// SB: TfrxHtSectionBase;
|
||
|
// SC: TfrxHtSection;
|
||
|
// begin
|
||
|
// Result := 0;
|
||
|
// LineSize.cx := 0;
|
||
|
// LineSize.cy := 0;
|
||
|
// for I := 0 to Count - 1 do
|
||
|
// begin
|
||
|
// SB := Items[I];
|
||
|
// if SB is TfrxHtSection then
|
||
|
// SC := TfrxHtSection(SB)
|
||
|
// else
|
||
|
// SC := nil;
|
||
|
// Tmp := SB.DrawLogic1(Canvas, X + LineSize.cx, Y + Result, XRef, YRef, Width, AHeight, BlHt, IMgr, Sw, Curs);
|
||
|
// if (SC <> nil) {and (SC.WhiteSpaceStyle in [wsPre, wsNoWrap])} then
|
||
|
// begin
|
||
|
// // Each section accumulates elements up to complete lines.
|
||
|
// Inc(Result, Tmp);
|
||
|
// if OwnerBlock.HideOverflow then
|
||
|
// ScrollWidth := Width
|
||
|
// else
|
||
|
// ScrollWidth := Max(ScrollWidth, Sw);
|
||
|
// TextWidth := Max(TextWidth, TfrxHtSection(SB).TextWidth);
|
||
|
// end
|
||
|
// else
|
||
|
// begin
|
||
|
// if LineSize.cy < Tmp then
|
||
|
// LineSize.cy := Tmp;
|
||
|
// Inc(LineSize.cx, SB.DrawRect.Right - SB.DrawRect.Left);
|
||
|
// if LineSize.cx > Width then
|
||
|
// begin
|
||
|
// Inc(Result, LineSize.cy);
|
||
|
// if OwnerBlock.HideOverflow then
|
||
|
// ScrollWidth := Width
|
||
|
// else
|
||
|
// ScrollWidth := Max(ScrollWidth, LineSize.cx);
|
||
|
// if TextWidth < LineSize.cx then
|
||
|
// TextWidth := LineSize.cx;
|
||
|
// LineSize.cx := 0;
|
||
|
// LineSize.cy := 0;
|
||
|
// end;
|
||
|
// end;
|
||
|
// if not (SB is TfrxHtBlock) or (TfrxHtBlock(SB).Positioning <> posAbsolute) then
|
||
|
// tcContentBot := Max(tcContentBot, SB.ContentBot);
|
||
|
// tcDrawTop := Min(tcDrawTop, SB.DrawTop);
|
||
|
// tcDrawBot := Max(tcDrawBot, SB.DrawBot);
|
||
|
// end;
|
||
|
// Inc(Result, LineSize.cy);
|
||
|
// end;
|
||
|
{$endif}
|
||
|
|
||
|
begin
|
||
|
// YValue := Y;
|
||
|
StartCurs := Curs;
|
||
|
|
||
|
ScrollWidth := 0;
|
||
|
TextWidth := 0;
|
||
|
tcContentBot := 0;
|
||
|
tcDrawTop := 990000;
|
||
|
tcDrawBot := 0;
|
||
|
|
||
|
//TODO -oBG, 15.03.2014: support display:inline
|
||
|
{$ifdef DO_PD_INLINE}
|
||
|
if CalcDisplayExtern = pdInline then
|
||
|
CellHeight := DoInlineLogic
|
||
|
else
|
||
|
{$endif}
|
||
|
CellHeight := DoBlockLogic;
|
||
|
|
||
|
Len := Curs - StartCurs;
|
||
|
Result := CellHeight;
|
||
|
end;
|
||
|
|
||
|
|
||
|
{ TfrxHtDrawList }
|
||
|
|
||
|
type
|
||
|
TImageRec = class(TObject)
|
||
|
public
|
||
|
AObj: TfrxFrHtImageObj;
|
||
|
ACanvas: TCanvas;
|
||
|
AX, AY: Integer;
|
||
|
AYBaseline: Integer;
|
||
|
AFO: TfrxHtFontObj;
|
||
|
end;
|
||
|
|
||
|
procedure TfrxHtDrawList.AddImage(Obj: TfrxFrHtImageObj; Canvas: TCanvas; X, Y, YBaseline: Integer; FO: TfrxHtFontObj);
|
||
|
var
|
||
|
Result: TImageRec;
|
||
|
begin
|
||
|
Result := TImageRec.Create;
|
||
|
Result.AObj := Obj;
|
||
|
Result.ACanvas := Canvas;
|
||
|
Result.AX := X;
|
||
|
Result.AY := Y;
|
||
|
Result.AYBaseline := YBaseline;
|
||
|
Result.AFO := FO;
|
||
|
Add(Result);
|
||
|
end;
|
||
|
|
||
|
procedure TfrxHtDrawList.DrawImages;
|
||
|
var
|
||
|
I: Integer;
|
||
|
Item: TObject;
|
||
|
begin
|
||
|
I := 0;
|
||
|
while I < Count do {note: Count may increase during this operation}
|
||
|
begin
|
||
|
Item := Items[I];
|
||
|
if (Item is TImageRec) then
|
||
|
with TImageRec(Item) do
|
||
|
AObj.DrawInline(ACanvas, AX, AY, AYBaseline, AFO);
|
||
|
Inc(I);
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
{----------------TfrxHtLineRec.Create}
|
||
|
|
||
|
constructor TfrxHtLineRec.Create(SL: TfrxHtDocument);
|
||
|
begin
|
||
|
inherited Create;
|
||
|
if SL.InlineList.Count > 0 then
|
||
|
FirstDraw := True;
|
||
|
end;
|
||
|
|
||
|
procedure TfrxHtLineRec.Clear;
|
||
|
begin
|
||
|
FreeAndNil(BorderList);
|
||
|
end;
|
||
|
|
||
|
destructor TfrxHtLineRec.Destroy;
|
||
|
begin
|
||
|
BorderList.Free;
|
||
|
inherited Destroy;
|
||
|
end;
|
||
|
|
||
|
{----------------TfrxHtBorderRec.DrawTheBorder}
|
||
|
|
||
|
procedure TfrxHtBorderRec.DrawTheBorder(Canvas: TCanvas; XOffset, YOffSet: Integer; Printing: Boolean);
|
||
|
var
|
||
|
IRect, ORect: TRect;
|
||
|
begin
|
||
|
IRect := BRect;
|
||
|
Dec(IRect.Top, YOffSet);
|
||
|
Dec(IRect.Bottom, YOffSet);
|
||
|
Inc(IRect.Left, XOffset);
|
||
|
Inc(IRect.Right, XOffset);
|
||
|
if OpenStart then
|
||
|
MargArray[BorderLeftStyle] := ord(bssNone);
|
||
|
if OpenEnd then
|
||
|
MargArray[BorderRightStyle] := ord(bssNone);
|
||
|
|
||
|
if MargArray[BackgroundColor] <> clNone then
|
||
|
begin
|
||
|
Canvas.Brush.Color := ThemedColor(MargArray[BackgroundColor]) or PalRelative;
|
||
|
Canvas.Brush.Style := bsSolid;
|
||
|
Canvas.FillRect(IRect);
|
||
|
end;
|
||
|
|
||
|
ORect.Left := IRect.Left - MargArray[BorderLeftWidth];
|
||
|
ORect.Top := IRect.Top - MargArray[BorderTopWidth];
|
||
|
ORect.Right := IRect.Right + MargArray[BorderRightWidth];
|
||
|
ORect.Bottom := IRect.Bottom + MargArray[BorderBottomWidth];
|
||
|
|
||
|
DrawBorder(Canvas, ORect, IRect,
|
||
|
htColors(MargArray[BorderLeftColor], MargArray[BorderTopColor], MargArray[BorderRightColor], MargArray[BorderBottomColor]),
|
||
|
htStyles(ThtBorderStyle(MargArray[BorderLeftStyle]), ThtBorderStyle(MargArray[BorderTopStyle]), ThtBorderStyle(MargArray[BorderRightStyle]), ThtBorderStyle(MargArray[BorderBottomStyle])),
|
||
|
MargArray[BackgroundColor], Printing)
|
||
|
end;
|
||
|
|
||
|
{----------------TfrxHtPage.Draw1}
|
||
|
|
||
|
constructor TfrxHtPage.Create(Parent: TfrxHtCellBasic; Attributes: TfrxHtAttributeList; Properties: TfrxHTProperties);
|
||
|
begin
|
||
|
inherited Create(Parent, Attributes, Properties);
|
||
|
if FDisplay = pdUnassigned then
|
||
|
FDisplay := pdBlock;
|
||
|
end;
|
||
|
|
||
|
function TfrxHtPage.Draw1(Canvas: TCanvas; const ARect: TRect; IMgr: TfrxHtIndentManager; X, XRef, YRef: Integer): Integer;
|
||
|
begin
|
||
|
Result := inherited Draw1(Canvas, ARect, Imgr, X, XRef, YRef);
|
||
|
end;
|
||
|
|
||
|
{----------------TfrxHtHorzLine.Create}
|
||
|
|
||
|
constructor TfrxHtHorzLine.Create(Parent: TfrxHtCellBasic; L: TfrxHtAttributeList; Prop: TfrxHTProperties);
|
||
|
var
|
||
|
LwName: ThtString;
|
||
|
I: Integer;
|
||
|
TmpColor: TColor;
|
||
|
begin
|
||
|
inherited Create(Parent, L, Prop);
|
||
|
if FDisplay = pdUnassigned then
|
||
|
FDisplay := pdBlock;
|
||
|
VSize := 2;
|
||
|
Align := Centered;
|
||
|
Color := clNone;
|
||
|
for I := 0 to L.Count - 1 do
|
||
|
with L[I] do
|
||
|
case Which of
|
||
|
SizeSy: if (Value > 0) and (Value <= 20) then
|
||
|
begin
|
||
|
VSize := Value;
|
||
|
end;
|
||
|
WidthSy:
|
||
|
if Value > 0 then
|
||
|
if Pos('%', Name) > 0 then
|
||
|
begin
|
||
|
if (Value <= 100) then
|
||
|
Prop.Assign(IntToStr(Value) + '%', piWidth);
|
||
|
end
|
||
|
else
|
||
|
Prop.Assign(Value, piWidth);
|
||
|
ColorSy: if TryStrToColor(Name, False, Color) then
|
||
|
Prop.Assign(Color, frxHTMLStyleUn.Color);
|
||
|
AlignSy:
|
||
|
begin
|
||
|
LwName := Lowercase(Name);
|
||
|
if LwName = 'left' then
|
||
|
Align := Left
|
||
|
else if LwName = 'right' then
|
||
|
Align := Right;
|
||
|
end;
|
||
|
NoShadeSy: NoShade := True;
|
||
|
end;
|
||
|
UseDefBorder := not Prop.BorderStyleNotBlank;
|
||
|
Prop.Assign(VSize, piHeight); {assigns if no property exists yet}
|
||
|
TmpColor := Prop.GetOriginalForegroundColor;
|
||
|
if TmpColor <> clNone then
|
||
|
Color := TmpColor;
|
||
|
with Prop do
|
||
|
if (VarIsStr(Props[TextAlign])) and Originals[TextAlign] then
|
||
|
if Props[TextAlign] = 'left' then
|
||
|
Align := Left
|
||
|
else if Props[TextAlign] = 'right' then
|
||
|
Align := Right
|
||
|
else if Props[TextAlign] = 'center' then
|
||
|
Align := Centered;
|
||
|
end;
|
||
|
|
||
|
constructor TfrxHtHorzLine.CreateCopy(Parent: TfrxHtCellBasic; Source: TfrxHtmlNode);
|
||
|
var
|
||
|
T: TfrxHtHorzLine absolute Source;
|
||
|
begin
|
||
|
inherited CreateCopy(Parent,Source);
|
||
|
System.Move(T.VSize, VSize, PtrSub(@BkGnd, @VSize) + Sizeof(BkGnd));
|
||
|
end;
|
||
|
|
||
|
function TfrxHtHorzLine.DrawLogic1(Canvas: TCanvas; X, Y, XRef, YRef, AWidth, AHeight, BlHt: Integer; IMgr: TfrxHtIndentManager;
|
||
|
var MaxWidth: Integer; var Curs: Integer; ARemainHeight: Integer): Integer;
|
||
|
begin
|
||
|
YDraw := Y;
|
||
|
StartCurs := Curs;
|
||
|
{Note: VSize gets updated in TfrxHtHRBlock.FindWidth}
|
||
|
ContentTop := Y;
|
||
|
DrawTop := Y;
|
||
|
Indent := Max(0, IMgr.LeftIndent(Y) - X);
|
||
|
Width := Min(AWidth, IMgr.RightSide(Y) - X) - Indent;
|
||
|
MaxWidth := Width;
|
||
|
SectionHeight := VSize;
|
||
|
DrawHeight := SectionHeight;
|
||
|
ContentBot := Y + SectionHeight;
|
||
|
DrawBot := Y + DrawHeight;
|
||
|
Result := SectionHeight;
|
||
|
end;
|
||
|
|
||
|
{----------------TfrxHtHorzLine.Draw}
|
||
|
|
||
|
function TfrxHtHorzLine.Draw1(Canvas: TCanvas; const ARect: TRect; IMgr: TfrxHtIndentManager; X, XRef, YRef: Integer): Integer;
|
||
|
var
|
||
|
XR: Integer;
|
||
|
YT, YO, Y: Integer;
|
||
|
White, BlackBorder: Boolean;
|
||
|
begin
|
||
|
Y := YDraw;
|
||
|
Result := inherited Draw1(Canvas, ARect, IMgr, X, XRef, YRef);
|
||
|
YO := Y - Document.YOff;
|
||
|
if (YO + SectionHeight >= ARect.Top) and (YO < ARect.Bottom) then
|
||
|
begin
|
||
|
Inc(X, Indent);
|
||
|
YT := YO;
|
||
|
XR := X + Width - 1;
|
||
|
with Canvas do
|
||
|
begin
|
||
|
if Color <> clNone then
|
||
|
begin
|
||
|
Brush.Color := ThemedColor(Color) or $2000000;
|
||
|
Brush.Style := bsSolid;
|
||
|
FillRect(Rect(X, YT, XR + 1, YT + VSize));
|
||
|
end
|
||
|
else
|
||
|
begin
|
||
|
if UseDefBorder then begin
|
||
|
with Document do
|
||
|
begin
|
||
|
White := (ThemedColor(Background) = clWhite);
|
||
|
BlackBorder := NoShade;
|
||
|
end;
|
||
|
if BlackBorder then
|
||
|
Pen.Color := clBlack
|
||
|
else if White then
|
||
|
Pen.Color := clSilver
|
||
|
else
|
||
|
Pen.Color := ThemedColor(clBtnHighLight);
|
||
|
MoveTo(XR, YT);
|
||
|
LineTo(XR, YT + VSize - 1);
|
||
|
LineTo(X, YT + VSize - 1);
|
||
|
if BlackBorder then
|
||
|
Pen.Color := clBlack
|
||
|
else
|
||
|
Pen.Color := ThemedColor(clBtnShadow);
|
||
|
LineTo(X, YT);
|
||
|
LineTo(XR, YT);
|
||
|
end;
|
||
|
end;
|
||
|
Document.FirstPageItem := False; {items after this will not be first on page}
|
||
|
end;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
{ TfrxHtmlPropStack }
|
||
|
|
||
|
{ Add a TfrxHTProperties to the PropStack. }
|
||
|
procedure TfrxHtmlPropStack.PushNewProp(Sym: TElemSymb; Properties: TfrxHTProperties; Attributes: TfrxHtAttributeList; const APseudo: ThtString = '');
|
||
|
var
|
||
|
NewProp: TfrxHTProperties;
|
||
|
Tag: ThtString;
|
||
|
begin
|
||
|
Tag := SymbToStr(Sym);
|
||
|
NewProp := TfrxHTProperties.Create(Self);
|
||
|
NewProp.PropSym := Sym;
|
||
|
NewProp.Inherit(Tag, Last);
|
||
|
Add(NewProp);
|
||
|
NewProp.Combine(Document.Styles, Sym, Tag, APseudo, Properties, Attributes, Count - 1);
|
||
|
end;
|
||
|
|
||
|
procedure TfrxHtmlPropStack.PopProp;
|
||
|
{pop and free a TfrxHTProperties from the Prop stack}
|
||
|
var
|
||
|
TopIndex: Integer;
|
||
|
begin
|
||
|
TopIndex := Count - 1;
|
||
|
if TopIndex > 0 then
|
||
|
Delete(TopIndex);
|
||
|
end;
|
||
|
|
||
|
procedure TfrxHtmlPropStack.PopAProp(Sym: TElemSymb);
|
||
|
{pop and free a TfrxHTProperties from the Prop stack. It should be on top but in
|
||
|
case of a nesting error, find it anyway}
|
||
|
var
|
||
|
I, J: Integer;
|
||
|
begin
|
||
|
for I := Count - 1 downto 1 do
|
||
|
if Items[I].PropSym = Sym then
|
||
|
begin
|
||
|
if Items[I].HasBorderStyle then
|
||
|
{this would be the end of an inline border}
|
||
|
Document.ProcessInlines(SIndex, Items[I], False);
|
||
|
Delete(I);
|
||
|
if I > 1 then {update any stack items which follow the deleted one}
|
||
|
for J := I to Count - 1 do
|
||
|
Items[J].Update(Items[J - 1], Document.Styles, J);
|
||
|
Break;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
//-- BG ---------------------------------------------------------- 12.09.2010 --
|
||
|
constructor TfrxHtmlStyleList.Create(AMasterList: TfrxHtDocument);
|
||
|
begin
|
||
|
inherited Create;
|
||
|
Document := AMasterList;
|
||
|
end;
|
||
|
|
||
|
//-- BG ---------------------------------------------------------- 08.03.2011 --
|
||
|
procedure TfrxHtmlStyleList.SetLinksActive(Value: Boolean);
|
||
|
begin
|
||
|
// inherited SetLinksActive(Value);
|
||
|
Document.LinksActive := Value;
|
||
|
end;
|
||
|
|
||
|
{ TfrxHtFieldsetBlock }
|
||
|
|
||
|
//-- BG ---------------------------------------------------------- 09.10.2010 --
|
||
|
procedure TfrxHtFieldsetBlock.ContentMinMaxWidth(Canvas: TCanvas; out Min, Max: Integer; AvailableWidth, AvailableHeight: Integer);
|
||
|
var
|
||
|
LegendMin, LegendMax: Integer;
|
||
|
ContentMin, ContentMax: Integer;
|
||
|
begin
|
||
|
Legend.MinMaxWidth(Canvas, LegendMin, LegendMax, AvailableWidth, AvailableHeight);
|
||
|
inherited ContentMinMaxWidth(Canvas, ContentMin, ContentMax, AvailableWidth, AvailableHeight);
|
||
|
Min := Math.Max(ContentMin, LegendMin);
|
||
|
Max := Math.Max(ContentMax, LegendMax);
|
||
|
end;
|
||
|
|
||
|
//-- BG ---------------------------------------------------------- 06.10.2010 --
|
||
|
procedure TfrxHtFieldsetBlock.ConvMargArray(BaseWidth, BaseHeight: Integer; out AutoCount: Integer);
|
||
|
var
|
||
|
PaddTop, Delta: Integer;
|
||
|
begin
|
||
|
inherited ConvMargArray(BaseWidth, BaseHeight,AutoCount);
|
||
|
MargArray[MarginTop] := VMargToMarg(MargArrayO[MarginTop], False, BaseHeight, EmSize, ExSize, 10);
|
||
|
Delta := Legend.CellHeight - (MargArray[MarginTop] + MargArray[BorderTopWidth] + MargArray[PaddingTop]);
|
||
|
if Delta > 0 then
|
||
|
begin
|
||
|
PaddTop := Delta div 2;
|
||
|
MargArray[MarginTop] := MargArray[MarginTop] + Delta - PaddTop;
|
||
|
MargArray[PaddingTop] := MargArray[PaddingTop] + PaddTop;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
//-- BG ---------------------------------------------------------- 05.10.2010 --
|
||
|
constructor TfrxHtFieldsetBlock.Create(Parent: TfrxHtCellBasic; Attributes: TfrxHtAttributeList; Prop: TfrxHTProperties);
|
||
|
var
|
||
|
Index: ThtPropIndices;
|
||
|
begin
|
||
|
inherited Create(Parent,Attributes,Prop);
|
||
|
HasBorderStyle := True;
|
||
|
for Index := BorderTopStyle to BorderLeftStyle do
|
||
|
if VarIsIntNull(MargArrayO[Index]) or VarIsEmpty(MargArrayO[Index]) then
|
||
|
MargArrayO[Index] := bssSolid;
|
||
|
for Index := BorderTopColor to BorderLeftColor do
|
||
|
if VarIsIntNull(MargArrayO[Index]) or VarIsEmpty(MargArrayO[Index]) then
|
||
|
MargArrayO[Index] := RGB(165, 172, 178);
|
||
|
for Index := BorderTopWidth to BorderLeftWidth do
|
||
|
if VarIsIntNull(MargArrayO[Index]) or VarIsEmpty(MargArrayO[Index]) then
|
||
|
MargArrayO[Index] := 1;
|
||
|
// for Index := MarginTop to MarginLeft do
|
||
|
// if VarIsIntNull(MargArrayO[Index]) or VarIsEmpty(MargArrayO[Index]) then
|
||
|
// MargArrayO[Index] := 10;
|
||
|
for Index := PaddingTop to PaddingLeft do
|
||
|
if VarIsIntNull(MargArrayO[Index]) or VarIsEmpty(MargArrayO[Index]) then
|
||
|
MargArrayO[Index] := 10;
|
||
|
FLegend := TfrxHtBlockCell.Create(Self);
|
||
|
end;
|
||
|
|
||
|
//-- BG ---------------------------------------------------------- 05.10.2010 --
|
||
|
constructor TfrxHtFieldsetBlock.CreateCopy(Parent: TfrxHtCellBasic; Source: TfrxHtmlNode);
|
||
|
var
|
||
|
T: TfrxHtFieldsetBlock absolute Source;
|
||
|
begin
|
||
|
inherited CreateCopy(Parent,Source);
|
||
|
FLegend := TfrxHtBlockCell.CreateCopy(Self, T.FLegend);
|
||
|
end;
|
||
|
|
||
|
//-- BG ---------------------------------------------------------- 05.10.2010 --
|
||
|
destructor TfrxHtFieldsetBlock.Destroy;
|
||
|
begin
|
||
|
FLegend.Free;
|
||
|
inherited Destroy;
|
||
|
end;
|
||
|
|
||
|
//-- BG ---------------------------------------------------------- 06.10.2010 --
|
||
|
function TfrxHtFieldsetBlock.Draw1(Canvas: TCanvas; const ARect: TRect; IMgr: TfrxHtIndentManager; X, XRef, YRef: Integer): Integer;
|
||
|
var
|
||
|
Rect: TRect;
|
||
|
begin
|
||
|
case Display of
|
||
|
pdNone: Result := 0;
|
||
|
else
|
||
|
Rect.Left := X + MargArray[MarginLeft] + MargArray[BorderLeftWidth] + MargArray[PaddingLeft] - 2;
|
||
|
Rect.Right := Rect.Left + Legend.TextWidth + 4;
|
||
|
Rect.Top := YDraw - Document.YOff;
|
||
|
Rect.Bottom := Rect.Top + Legend.CellHeight;
|
||
|
Legend.Draw(Canvas, ARect, ContentWidth, Rect.Left + 2, YDraw, XRef, YRef);
|
||
|
Rect := CalcClipRect(Canvas, Rect, False);
|
||
|
ExcludeClipRect(Canvas.Handle, Rect.Left, Rect.Top, Rect.Right, Rect.Bottom);
|
||
|
Result := inherited Draw1(Canvas, ARect, IMgr, X, XRef, YRef);
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
//-- BG ---------------------------------------------------------- 05.10.2010 --
|
||
|
function TfrxHtFieldsetBlock.DrawLogic1(Canvas: TCanvas; X, Y, XRef, YRef, AWidth, AHeight, BlHt: Integer;
|
||
|
IMgr: TfrxHtIndentManager; var MaxWidth, Curs: Integer; ARemainHeight: Integer): Integer;
|
||
|
var
|
||
|
BorderWidth: TRect;
|
||
|
AutoCount, BlockHeight, ScrollWidth, L, LI, RI: Integer;
|
||
|
SaveID: TObject;
|
||
|
begin
|
||
|
case Display of
|
||
|
|
||
|
pdNone:
|
||
|
begin
|
||
|
SectionHeight := 0;
|
||
|
DrawHeight := 0;
|
||
|
ContentBot := 0;
|
||
|
DrawBot := 0;
|
||
|
MaxWidth := 0;
|
||
|
Result := 0;
|
||
|
end;
|
||
|
|
||
|
else
|
||
|
frxHTMLStyleUn.ConvMargArray(MargArrayO, AWidth, AHeight, EmSize, ExSize, self.BorderWidth, AutoCount, MargArray);
|
||
|
frxHTMLStyleUn.ApplyBoxSettings(MargArray);
|
||
|
BorderWidth.Left := MargArray[MarginLeft] + MargArray[BorderLeftWidth] + MargArray[PaddingLeft];
|
||
|
BorderWidth.Right := MargArray[MarginRight] + MargArray[BorderRightWidth] + MargArray[PaddingRight];
|
||
|
BorderWidth.Top := MargArray[MarginTop] + MargArray[BorderTopWidth] + MargArray[PaddingTop];
|
||
|
if MargArray[piHeight] > 0 then
|
||
|
BlockHeight := MargArray[piHeight]
|
||
|
else if AHeight > 0 then
|
||
|
BlockHeight := AHeight
|
||
|
else
|
||
|
BlockHeight := BlHt;
|
||
|
|
||
|
L := X + BorderWidth.Left;
|
||
|
ContentWidth := AWidth - BorderWidth.Left - BorderWidth.Right;
|
||
|
|
||
|
SaveID := IMgr.CurrentID;
|
||
|
IMgr.CurrentID := Self;
|
||
|
Legend.IMgr := IMgr;
|
||
|
LI := IMgr.SetLeftIndent(L, Y);
|
||
|
RI := IMgr.SetRightIndent(L + ContentWidth, Y);
|
||
|
Legend.DoLogicX(Canvas, X + BorderWidth.Left, Y, XRef, YRef, ContentWidth, MargArray[piHeight], BlockHeight, ScrollWidth, Curs, ARemainHeight);
|
||
|
IMgr.FreeLeftIndentRec(LI);
|
||
|
IMgr.FreeRightIndentRec(RI);
|
||
|
IMgr.CurrentID := SaveID;
|
||
|
|
||
|
Result := inherited DrawLogic1(Canvas, X, Y, XRef, YRef, AWidth, AHeight, BlHt, IMgr, MaxWidth, Curs, ARemainHeight);
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
{ TfrxHtSizeableObj }
|
||
|
|
||
|
//-- BG ---------------------------------------------------------- 12.11.2011 --
|
||
|
procedure TfrxHtSizeableObj.CalcSize(AvailableWidth, AvailableHeight, SetWidth, SetHeight: Integer; IsClientSizeSpecified: Boolean);
|
||
|
// Extracted from TPanelObj.DrawLogic() and TfrxFrHtImageObj.DrawLogic()
|
||
|
|
||
|
function CroppedSize(S: Integer; piMin, piMax: ThtPropertyIndex): Integer;
|
||
|
begin
|
||
|
Result := S;
|
||
|
|
||
|
if MargArray[piMax] > 0 then
|
||
|
Result := Min(Result, MargArray[piMax]);
|
||
|
|
||
|
if MargArray[piMin] > 0 then
|
||
|
Result := Max(Result, MargArray[piMin]);
|
||
|
end;
|
||
|
|
||
|
var
|
||
|
MargArrayO: ThtVMarginArray;
|
||
|
H, W: Integer;
|
||
|
begin
|
||
|
if FProperties <> nil then
|
||
|
FProperties.GetVMarginArray(MargArrayO)
|
||
|
else
|
||
|
begin
|
||
|
MargArrayO[piMinWidth] := IntNull;
|
||
|
MargArrayO[piMaxWidth] := IntNull;
|
||
|
MargArrayO[piMinHeight] := IntNull;
|
||
|
MargArrayO[piMaxHeight] := IntNull;
|
||
|
end;
|
||
|
|
||
|
ConvInlineMargArray(MargArrayO, AvailableWidth, AvailableHeight, EmSize, ExSize, BorderWidth, MargArray);
|
||
|
|
||
|
if PercentWidth then
|
||
|
begin
|
||
|
W := CroppedSize(MulDiv(AvailableWidth, SpecWidth, 100), piMinWidth, piMaxWidth);
|
||
|
if SpecHeight > 0 then
|
||
|
if PercentHeight then
|
||
|
H := MulDiv(AvailableHeight, SpecHeight, 100)
|
||
|
else
|
||
|
H := SpecHeight
|
||
|
else
|
||
|
H := MulDiv(W, SetHeight, SetWidth);
|
||
|
H := CroppedSize(H, piMinHeight, piMaxHeight);
|
||
|
end
|
||
|
else if PercentHeight then
|
||
|
begin
|
||
|
H := CroppedSize(MulDiv(AvailableHeight, SpecHeight, 100), piMinHeight, piMaxHeight);
|
||
|
if SpecWidth > 0 then
|
||
|
W := SpecWidth
|
||
|
else
|
||
|
W := MulDiv(H, SetWidth, SetHeight);
|
||
|
W := CroppedSize(W, piMinWidth, piMaxWidth);
|
||
|
end
|
||
|
else if (SpecWidth > 0) and (SpecHeight > 0) then
|
||
|
begin {Both width and height specified}
|
||
|
H := SpecHeight;
|
||
|
W := SpecWidth;
|
||
|
H := CroppedSize(H, piMinHeight, piMaxHeight);
|
||
|
W := CroppedSize(W, piMinWidth, piMaxWidth);
|
||
|
ClientSizeKnown := True;
|
||
|
end
|
||
|
else if SpecHeight > 0 then
|
||
|
begin
|
||
|
H := SpecHeight;
|
||
|
H := CroppedSize(H, piMinHeight, piMaxHeight);
|
||
|
W := MulDiv(H, SetWidth, SetHeight);
|
||
|
W := CroppedSize(W, piMinWidth, piMaxWidth);
|
||
|
ClientSizeKnown := IsClientSizeSpecified;
|
||
|
end
|
||
|
else if SpecWidth > 0 then
|
||
|
begin
|
||
|
W := SpecWidth;
|
||
|
W := CroppedSize(W, piMinWidth, piMaxWidth);
|
||
|
H := MulDiv(W, SetHeight, SetWidth);
|
||
|
H := CroppedSize(H, piMinHeight, piMaxHeight);
|
||
|
ClientSizeKnown := IsClientSizeSpecified;
|
||
|
end
|
||
|
else
|
||
|
begin {neither height and width specified}
|
||
|
H := SetHeight;
|
||
|
W := SetWidth;
|
||
|
CalcAutoMinMaxConstraints(W, H, MargArray[piMinWidth], MargArray[piMaxWidth], MargArray[piMinHeight], MargArray[piMaxHeight], W, H);
|
||
|
ClientSizeKnown := IsClientSizeSpecified;
|
||
|
end;
|
||
|
|
||
|
ClientWidth := W;
|
||
|
ClientHeight := H;
|
||
|
if ClientSizeKnown then
|
||
|
if (Pos('%', MargArrayO[piMinWidth]) > 0) or (Pos('%', MargArrayO[piMaxWidth]) > 0) or (Pos('%', MargArrayO[piMinHeight]) > 0) or (Pos('%', MargArrayO[piMaxHeight]) > 0) then
|
||
|
ClientSizeKnown := False;
|
||
|
end;
|
||
|
|
||
|
//-- BG ---------------------------------------------------------- 12.11.2011 --
|
||
|
constructor TfrxHtSizeableObj.Create(Parent: TfrxHtCellBasic; Position: Integer; L: TfrxHtAttributeList; Prop: TfrxHTProperties);
|
||
|
var
|
||
|
I: Integer;
|
||
|
NewHSpace: Integer;
|
||
|
NewVSpace: Integer;
|
||
|
S: ThtString;
|
||
|
begin
|
||
|
inherited Create(Parent,Position,L,Prop);
|
||
|
NewHSpace := -1;
|
||
|
NewVSpace := -1;
|
||
|
SpecHeight := -1;
|
||
|
SpecWidth := -1;
|
||
|
|
||
|
for I := 0 to L.Count - 1 do
|
||
|
with L[I] do
|
||
|
case Which of
|
||
|
|
||
|
HeightSy:
|
||
|
begin
|
||
|
if System.Pos('%', Name) = 0 then
|
||
|
begin
|
||
|
SpecHeight := Value;
|
||
|
end
|
||
|
else if (Value >= 0) and (Value <= 100) then
|
||
|
begin
|
||
|
SpecHeight := Value;
|
||
|
PercentHeight := True;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
WidthSy:
|
||
|
if System.Pos('%', Name) = 0 then
|
||
|
begin
|
||
|
SpecWidth := Value;
|
||
|
end
|
||
|
else if (Value >= 0) and (Value <= 100) then
|
||
|
begin
|
||
|
SpecWidth := Value;
|
||
|
PercentWidth := True;
|
||
|
end;
|
||
|
|
||
|
HSpaceSy:
|
||
|
NewHSpace := Min(40, Abs(Value));
|
||
|
|
||
|
VSpaceSy:
|
||
|
NewVSpace := Min(40, Abs(Value));
|
||
|
|
||
|
AlignSy:
|
||
|
begin
|
||
|
S := htUpperCase(htTrim(Name));
|
||
|
if S = 'TOP' then
|
||
|
VertAlign := ATop
|
||
|
else if (S = 'MIDDLE') or (S = 'ABSMIDDLE') then
|
||
|
VertAlign := AMiddle
|
||
|
else if S = 'LEFT' then
|
||
|
begin
|
||
|
VertAlign := ANone;
|
||
|
FFloating := ALeft;
|
||
|
end
|
||
|
else if S = 'RIGHT' then
|
||
|
begin
|
||
|
VertAlign := ANone;
|
||
|
FFloating := ARight;
|
||
|
end;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
if NewVSpace >= 0 then
|
||
|
begin
|
||
|
VSpaceT := NewVSpace;
|
||
|
VSpaceB := VSpaceT;
|
||
|
end;
|
||
|
|
||
|
if NewHSpace >= 0 then
|
||
|
begin
|
||
|
HSpaceL := NewHSpace;
|
||
|
HSpaceR := HSpaceL;
|
||
|
end
|
||
|
else
|
||
|
begin
|
||
|
HSpaceR := HSpaceL;
|
||
|
end;
|
||
|
|
||
|
end;
|
||
|
|
||
|
constructor TfrxHtSizeableObj.CreateCopy(Parent: TfrxHtCellBasic; Source: TfrxHtmlNode);
|
||
|
var
|
||
|
T: TfrxHtSizeableObj absolute Source;
|
||
|
begin
|
||
|
inherited CreateCopy(Parent,Source);
|
||
|
BorderWidth := T.BorderWidth;
|
||
|
FAlt := T.FAlt;
|
||
|
FClientHeight := T.FClientHeight;
|
||
|
FClientWidth := T.FClientWidth;
|
||
|
ClientSizeKnown := T.ClientSizeKnown;
|
||
|
NoBorder := T.NoBorder;
|
||
|
SpecHeight := T.SpecHeight;
|
||
|
SpecWidth := T.SpecWidth;
|
||
|
Title := T.Title;
|
||
|
end;
|
||
|
|
||
|
//-- BG ---------------------------------------------------------- 30.08.2013 --
|
||
|
procedure TfrxHtSizeableObj.DrawInline(Canvas: TCanvas; X, Y, YBaseline: Integer; FO: TfrxHtFontObj);
|
||
|
begin
|
||
|
if not IsCopy then
|
||
|
begin
|
||
|
DrawXX := X;
|
||
|
DrawYY := Y;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
//-- BG ---------------------------------------------------------- 21.09.2016 --
|
||
|
procedure TfrxHtSizeableObj.DrawLogicInline(Canvas: TCanvas; FO: TfrxHtFontObj;
|
||
|
AvailableWidth, AvailableHeight: Integer);
|
||
|
begin
|
||
|
|
||
|
end;
|
||
|
|
||
|
//-- BG ---------------------------------------------------------- 06.08.2013 --
|
||
|
function TfrxHtSizeableObj.GetClientHeight: Integer;
|
||
|
begin
|
||
|
Result := FClientHeight;
|
||
|
end;
|
||
|
|
||
|
//-- BG ---------------------------------------------------------- 06.08.2013 --
|
||
|
function TfrxHtSizeableObj.GetClientWidth: Integer;
|
||
|
begin
|
||
|
Result := FClientWidth;
|
||
|
end;
|
||
|
|
||
|
procedure TfrxHtSizeableObj.ProcessProperties(Prop: TfrxHTProperties);
|
||
|
const
|
||
|
DummyHtWd = 200;
|
||
|
var
|
||
|
MargArrayO: ThtVMarginArray;
|
||
|
Align: ThtAlignmentStyle;
|
||
|
begin
|
||
|
if Prop.GetVertAlign(Align) then
|
||
|
VertAlign := Align;
|
||
|
if Prop.GetFloat(Align) and (Align <> ANone) then
|
||
|
begin
|
||
|
// if HSpaceR = 0 then
|
||
|
// begin {default is different for Align = left/right}
|
||
|
// HSpaceR := ImageSpace;
|
||
|
// HSpaceL := ImageSpace;
|
||
|
// end;
|
||
|
VertAlign := ANone;
|
||
|
FFloating := Align;
|
||
|
end;
|
||
|
if Title = '' then {a Title attribute will have higher priority than inherited}
|
||
|
Title := Prop.PropTitle;
|
||
|
Prop.GetVMarginArray(MargArrayO);
|
||
|
EmSize := Prop.EmSize;
|
||
|
ExSize := Prop.ExSize;
|
||
|
ConvInlineMargArray(MargArrayO, DummyHtWd, DummyHtWd, EmSize, ExSize, BorderWidth, MargArray);
|
||
|
|
||
|
if MargArray[MarginLeft] <> IntNull then
|
||
|
HSpaceL := MargArray[MarginLeft];
|
||
|
if MargArray[MarginRight] <> IntNull then
|
||
|
HSpaceR := MargArray[MarginRight];
|
||
|
if MargArray[MarginTop] <> IntNull then
|
||
|
VSpaceT := MargArray[MarginTop];
|
||
|
if MargArray[MarginBottom] <> IntNull then
|
||
|
VSpaceB := MargArray[MarginBottom];
|
||
|
|
||
|
if MargArray[piWidth] <> IntNull then
|
||
|
begin
|
||
|
PercentWidth := False;
|
||
|
if MargArray[piWidth] <> Auto then
|
||
|
if (VarIsStr(MargArrayO[piWidth]))
|
||
|
and (System.Pos('%', MargArrayO[piWidth]) > 0) then
|
||
|
begin
|
||
|
PercentWidth := True;
|
||
|
SpecWidth := MulDiv(MargArray[piWidth], 100, DummyHtWd);
|
||
|
end
|
||
|
else
|
||
|
SpecWidth := MargArray[piWidth];
|
||
|
end;
|
||
|
if MargArray[piHeight] <> IntNull then
|
||
|
begin
|
||
|
PercentHeight := False;
|
||
|
if MargArray[piHeight] <> Auto then
|
||
|
if (VarIsStr(MargArrayO[piHeight]))
|
||
|
and (System.Pos('%', MargArrayO[piHeight]) > 0) then
|
||
|
begin
|
||
|
PercentHeight := True;
|
||
|
SpecHeight := MulDiv(MargArray[piHeight], 100, DummyHtWd);
|
||
|
end
|
||
|
else
|
||
|
SpecHeight := MargArray[piHeight];
|
||
|
end;
|
||
|
|
||
|
if Prop.GetVertAlign(Align) then
|
||
|
VertAlign := Align;
|
||
|
if Prop.GetFloat(Align) and (Align <> ANone) then
|
||
|
FFloating := Align;
|
||
|
|
||
|
if Prop.BorderStyleNotBlank then
|
||
|
begin
|
||
|
NoBorder := True; {will have inline border instead}
|
||
|
BorderWidth := 0;
|
||
|
end
|
||
|
else if Prop.HasBorderStyle then
|
||
|
begin
|
||
|
Inc(HSpaceL, MargArray[BorderLeftWidth]);
|
||
|
Inc(HSpaceR, MargArray[BorderRightWidth]);
|
||
|
Inc(VSpaceT, MargArray[BorderTopWidth]);
|
||
|
Inc(VSpaceB, MargArray[BorderBottomWidth]);
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
//-- BG ---------------------------------------------------------- 30.11.2010 --
|
||
|
procedure TfrxHtSizeableObj.SetAlt(CodePage: Integer; const Value: ThtString);
|
||
|
begin
|
||
|
FAlt := Value;
|
||
|
while Length(FAlt) > 0 do
|
||
|
case FAlt[Length(FAlt)] of
|
||
|
CrChar, LfChar:
|
||
|
Delete(FAlt, Length(FAlt), 1);
|
||
|
else
|
||
|
break;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
//-- BG ---------------------------------------------------------- 31.08.2013 --
|
||
|
procedure TfrxHtSizeableObj.SetClientHeight(Value: Integer);
|
||
|
begin
|
||
|
FClientHeight := Value;
|
||
|
end;
|
||
|
|
||
|
//-- BG ---------------------------------------------------------- 31.08.2013 --
|
||
|
procedure TfrxHtSizeableObj.SetClientWidth(Value: Integer);
|
||
|
begin
|
||
|
FClientWidth := Value;
|
||
|
end;
|
||
|
|
||
|
//-- BG ---------------------------------------------------------- 12.11.2011 --
|
||
|
constructor TfrxHtSizeableObj.SimpleCreate(Parent: TfrxHtCellBasic);
|
||
|
begin
|
||
|
inherited Create(Parent, 0, nil, nil);
|
||
|
VertAlign := ABottom; {default}
|
||
|
NoBorder := True;
|
||
|
BorderWidth := 0;
|
||
|
SpecHeight := -1;
|
||
|
SpecWidth := -1;
|
||
|
end;
|
||
|
|
||
|
{ TfrxHtSectionBase }
|
||
|
|
||
|
//-- BG ---------------------------------------------------------- 20.09.2009 --
|
||
|
constructor TfrxHtSectionBase.Create(Parent: TfrxHtCellBasic; Attributes: TfrxHtAttributeList; Properties: TfrxHTProperties);
|
||
|
var
|
||
|
TheId, TheClass: ThtString;
|
||
|
begin
|
||
|
if Properties <> nil then
|
||
|
begin
|
||
|
TheID := Properties.PropID;
|
||
|
TheClass := Properties.PropClass;
|
||
|
end
|
||
|
else if Attributes <> nil then
|
||
|
begin
|
||
|
TheId := Attributes.TheId;
|
||
|
TheClass := Attributes.TheClass;
|
||
|
end;
|
||
|
Create(Parent, Attributes, Properties, TheId, TheClass);
|
||
|
end;
|
||
|
|
||
|
//-- BG ---------------------------------------------------------- 20.09.2009 --
|
||
|
constructor TfrxHtSectionBase.Create(Parent: TfrxHtCellBasic; Attributes: TfrxHtAttributeList; Properties: TfrxHTProperties; const TheId, TheClass: ThtString);
|
||
|
begin
|
||
|
inherited Create(Parent, Attributes, Properties, TheId);
|
||
|
if Properties <> nil then
|
||
|
begin
|
||
|
TagClass := Properties.PropTag;
|
||
|
end;
|
||
|
htAppendStr(TagClass, '.' + TheClass + '#' + TheId);
|
||
|
|
||
|
ContentTop := 999999999; {large number in case it has Display: none; }
|
||
|
end;
|
||
|
|
||
|
constructor TfrxHtSectionBase.CreateCopy(Parent: TfrxHtCellBasic; Source: TfrxHtmlNode);
|
||
|
var
|
||
|
T: TfrxHtSectionBase absolute Source;
|
||
|
begin
|
||
|
inherited CreateCopy(Parent,Source);
|
||
|
StartCurs := T.StartCurs;
|
||
|
Len := T.Len;
|
||
|
SectionHeight := T.SectionHeight;
|
||
|
ZIndex := T.ZIndex;
|
||
|
end;
|
||
|
|
||
|
function TfrxHtSectionBase.GetYPosition: Integer;
|
||
|
begin
|
||
|
Result := ContentTop;
|
||
|
end;
|
||
|
|
||
|
function TfrxHtSectionBase.DrawLogic1(Canvas: TCanvas; X, Y, XRef, YRef, AWidth, AHeight, BlHt: Integer; IMgr: TfrxHtIndentManager;
|
||
|
var MaxWidth, Curs: Integer; ARemainHeight: Integer): Integer;
|
||
|
// Computes all coordinates of the section.
|
||
|
//
|
||
|
// Normal sections, absolutely positioned blocks and floating blocks start at given (X,Y) relative to document origin.
|
||
|
// Table cells start at given (X,Y) coordinates relative to the outmost containing block.
|
||
|
//
|
||
|
// Returns the nominal height of the section (without overhanging floating blocks)
|
||
|
var
|
||
|
ClearAddon: Integer;
|
||
|
begin
|
||
|
case FDisplay of
|
||
|
pdNone:
|
||
|
ClearAddon := 0;
|
||
|
else
|
||
|
ClearAddon := GetClearSpace(IMgr, Y);
|
||
|
end;
|
||
|
|
||
|
StartCurs := Curs;
|
||
|
Len := 0;
|
||
|
MaxWidth := 0;
|
||
|
SectionHeight := 0;
|
||
|
DrawHeight := SectionHeight;
|
||
|
YDraw := Y + ClearAddon;
|
||
|
|
||
|
ContentTop := YDraw;
|
||
|
ContentBot := ContentTop + SectionHeight;
|
||
|
|
||
|
DrawTop := YDraw;
|
||
|
DrawBot := DrawTop + DrawHeight;
|
||
|
|
||
|
Result := ContentBot - Y;
|
||
|
end;
|
||
|
|
||
|
function TfrxHtSectionBase.Draw1(Canvas: TCanvas; const ARect: TRect; IMgr: TfrxHtIndentManager; X, XRef, YRef: Integer): Integer;
|
||
|
// returns the pixel row, where the section ends.
|
||
|
begin
|
||
|
Result := YDraw + SectionHeight;
|
||
|
end;
|
||
|
|
||
|
function TfrxHtSectionBase.FindString(From: Integer; const ToFind: UnicodeString; MatchCase: Boolean): Integer;
|
||
|
begin
|
||
|
Result := -1;
|
||
|
end;
|
||
|
|
||
|
function TfrxHtSectionBase.FindStringR(From: Integer; const ToFind: UnicodeString; MatchCase: Boolean): Integer;
|
||
|
begin
|
||
|
Result := -1;
|
||
|
end;
|
||
|
|
||
|
function TfrxHtSectionBase.FindSourcePos(DocPos: Integer): Integer;
|
||
|
begin
|
||
|
Result := -1;
|
||
|
end;
|
||
|
|
||
|
function TfrxHtSectionBase.FindDocPos(SourcePos: Integer; Prev: Boolean): Integer;
|
||
|
begin
|
||
|
Result := -1;
|
||
|
end;
|
||
|
|
||
|
function TfrxHtSectionBase.GetChAtPos(Pos: Integer; out Ch: WideChar; out Obj: TfrxHtSectionBase): Boolean;
|
||
|
begin
|
||
|
Result := False;
|
||
|
Ch := #0;
|
||
|
Obj := nil;
|
||
|
end;
|
||
|
|
||
|
procedure TfrxHtSectionBase.SetDocument(List: TfrxHtDocument);
|
||
|
begin
|
||
|
FDocument := List;
|
||
|
end;
|
||
|
|
||
|
procedure TfrxHtSectionBase.MinMaxWidth(Canvas: TCanvas; out Min, Max: Integer; AvailableWidth, AvailableHeight: Integer);
|
||
|
begin
|
||
|
Min := 0;
|
||
|
Max := 0;
|
||
|
end;
|
||
|
|
||
|
procedure TfrxHtSectionBase.AddSectionsToList;
|
||
|
begin
|
||
|
Document.addSectionsToPositionList(Self);
|
||
|
end;
|
||
|
|
||
|
{ TfrxHtSectionBaseList }
|
||
|
|
||
|
function TfrxHtSectionBaseList.FindDocPos(SourcePos: Integer; Prev: Boolean): Integer;
|
||
|
var
|
||
|
I: Integer;
|
||
|
begin
|
||
|
Result := -1;
|
||
|
if not Prev then
|
||
|
for I := 0 to Count - 1 do
|
||
|
begin
|
||
|
Result := Items[I].FindDocPos(SourcePos, Prev);
|
||
|
if Result >= 0 then
|
||
|
Break;
|
||
|
end
|
||
|
else {Prev, iterate backwards}
|
||
|
for I := Count - 1 downto 0 do
|
||
|
begin
|
||
|
Result := Items[I].FindDocPos(SourcePos, Prev);
|
||
|
if Result >= 0 then
|
||
|
Break;
|
||
|
end
|
||
|
end;
|
||
|
|
||
|
function TfrxHtSectionBaseList.GetItem(Index: Integer): TfrxHtSectionBase;
|
||
|
begin
|
||
|
Result := inherited Get(Index);
|
||
|
end;
|
||
|
|
||
|
{ TfrxHtChPosObj }
|
||
|
|
||
|
//-- BG ---------------------------------------------------------- 04.03.2011 --
|
||
|
constructor TfrxHtChPosObj.Create(Document: TfrxHtDocument; Pos: Integer);
|
||
|
begin
|
||
|
inherited Create('');
|
||
|
FChPos := Pos;
|
||
|
FDocument := Document;
|
||
|
end;
|
||
|
|
||
|
//-- BG ---------------------------------------------------------- 06.03.2011 --
|
||
|
function TfrxHtChPosObj.FreeMe: Boolean;
|
||
|
begin
|
||
|
Result := True;
|
||
|
end;
|
||
|
|
||
|
function TfrxHtChPosObj.GetYPosition: Integer;
|
||
|
begin
|
||
|
Result := 0;
|
||
|
end;
|
||
|
|
||
|
//-- BG ---------------------------------------------------------- 26.12.2011 --
|
||
|
function TfrxHtRowList.GetItem(Index: Integer): TfrxHtCellList;
|
||
|
begin
|
||
|
Result := Get(Index);
|
||
|
end;
|
||
|
|
||
|
{ TfrxHtColSpecList }
|
||
|
|
||
|
//-- BG ---------------------------------------------------------- 26.12.2011 --
|
||
|
function TfrxHtColSpecList.GetItem(Index: Integer): TfrxHtColSpec;
|
||
|
begin
|
||
|
Result := Get(Index);
|
||
|
end;
|
||
|
|
||
|
{ TfrxHtColSpec }
|
||
|
|
||
|
//-- BG ---------------------------------------------------------- 12.01.2012 --
|
||
|
constructor TfrxHtColSpec.Create(const Width: TSpecWidth; Align: ThtString; VAlign: ThtAlignmentStyle);
|
||
|
begin
|
||
|
inherited Create;
|
||
|
FWidth := Width;
|
||
|
FAlign := Align;
|
||
|
FVAlign := VAlign;
|
||
|
end;
|
||
|
|
||
|
//-- BG ---------------------------------------------------------- 27.01.2012 --
|
||
|
constructor TfrxHtColSpec.CreateCopy(const ColSpec: TfrxHtColSpec);
|
||
|
begin
|
||
|
Create(ColSpec.FWidth, ColSpec.FAlign, ColSpec.FVAlign);
|
||
|
end;
|
||
|
|
||
|
{ TfrxHtFloatingObj }
|
||
|
|
||
|
//-- BG ---------------------------------------------------------- 12.11.2011 --
|
||
|
function TfrxHtFloatingObj.Clone(Parent: TfrxHtCellBasic): TfrxHtFloatingObj;
|
||
|
begin
|
||
|
Result := TFloatingObjClass(ClassType).CreateCopy(Parent, Self);
|
||
|
end;
|
||
|
|
||
|
//-- BG ---------------------------------------------------------- 04.08.2013 --
|
||
|
constructor TfrxHtFloatingObj.Create(Parent: TfrxHtCellBasic; Position: Integer; L: TfrxHtAttributeList; Prop: TfrxHTProperties);
|
||
|
begin
|
||
|
inherited Create(Parent,Position,L,Prop);
|
||
|
StartCurs := Position;
|
||
|
VertAlign := ABottom; {default}
|
||
|
end;
|
||
|
|
||
|
//-- BG ---------------------------------------------------------- 04.08.2013 --
|
||
|
constructor TfrxHtFloatingObj.CreateCopy(Parent: TfrxHtCellBasic; Source: TfrxHtmlNode);
|
||
|
var
|
||
|
T: TfrxHtFloatingObj absolute Source;
|
||
|
begin
|
||
|
inherited CreateCopy(Parent,Source);
|
||
|
System.Move(T.VertAlign, VertAlign, PtrSub(@PercentHeight, @VertAlign) + SizeOf(PercentHeight));
|
||
|
DrawXX := T.DrawXX;
|
||
|
DrawYY := T.DrawYY;
|
||
|
end;
|
||
|
|
||
|
//-- BG ---------------------------------------------------------- 08.09.2013 --
|
||
|
function TfrxHtFloatingObj.Draw1(Canvas: TCanvas; const ARect: TRect; IMgr: TfrxHtIndentManager; X, XRef, YRef: Integer): Integer;
|
||
|
begin
|
||
|
Result := ContentBot;
|
||
|
end;
|
||
|
|
||
|
//-- BG ---------------------------------------------------------- 08.09.2013 --
|
||
|
function TfrxHtFloatingObj.DrawLogic1(Canvas: TCanvas; X, Y, XRef, YRef, AWidth, AHeight, BlHt: Integer; IMgr: TfrxHtIndentManager;
|
||
|
var MaxWidth, Curs: Integer; ARemainHeight: Integer): Integer;
|
||
|
begin
|
||
|
if Positioning in [posAbsolute, posFixed] then
|
||
|
Result := 0
|
||
|
else
|
||
|
Result := SectionHeight;
|
||
|
end;
|
||
|
|
||
|
//-- BG ---------------------------------------------------------- 14.02.2016 --
|
||
|
function TfrxHtFloatingObj.GetYPosition: Integer;
|
||
|
begin
|
||
|
Result := DrawYY;
|
||
|
end;
|
||
|
|
||
|
//-- BG ---------------------------------------------------------- 02.03.2011 --
|
||
|
function TfrxHtFloatingObj.TotalHeight: Integer;
|
||
|
begin
|
||
|
Result := VSpaceT + ClientHeight + VSpaceB;
|
||
|
end;
|
||
|
|
||
|
//-- BG ---------------------------------------------------------- 02.03.2011 --
|
||
|
function TfrxHtFloatingObj.TotalWidth: Integer;
|
||
|
begin
|
||
|
Result := HSpaceL + ClientWidth + HSpaceR;
|
||
|
end;
|
||
|
|
||
|
{ TFloatingObjList }
|
||
|
|
||
|
//-- BG ---------------------------------------------------------- 05.08.2013 --
|
||
|
constructor TFloatingObjList.CreateCopy(Parent: TfrxHtCellBasic; T: TFloatingObjList);
|
||
|
var
|
||
|
I: Integer;
|
||
|
begin
|
||
|
inherited Create;
|
||
|
if T <> nil then
|
||
|
for I := 0 to T.Count - 1 do
|
||
|
Add(T.Items[I].Clone(Parent));
|
||
|
end;
|
||
|
|
||
|
//-- BG ---------------------------------------------------------- 07.08.2013 --
|
||
|
procedure TFloatingObjList.Decrement(N: Integer);
|
||
|
{called when a character is removed to change the Position figure}
|
||
|
var
|
||
|
I: Integer;
|
||
|
begin
|
||
|
for I := Count - 1 downto 0 do
|
||
|
with Items[I] do
|
||
|
if StartCurs > N then
|
||
|
Dec(StartCurs)
|
||
|
else
|
||
|
break;
|
||
|
end;
|
||
|
|
||
|
//-- BG ---------------------------------------------------------- 07.08.2013 --
|
||
|
function TFloatingObjList.FindObject(Posn: Integer): TfrxHtFloatingObj;
|
||
|
{find the object at a given character position}
|
||
|
begin
|
||
|
if GetObjectAt(Posn, Result) <> 0 then
|
||
|
Result := nil;
|
||
|
end;
|
||
|
|
||
|
//-- BG ---------------------------------------------------------- 07.08.2013 --
|
||
|
function TFloatingObjList.GetItem(Index: Integer): TfrxHtFloatingObj;
|
||
|
begin
|
||
|
Result := Get(Index);
|
||
|
end;
|
||
|
|
||
|
//-- BG ---------------------------------------------------------- 05.08.2013 --
|
||
|
function TFloatingObjList.GetObjectAt(Posn: Integer; out Obj): Integer;
|
||
|
var
|
||
|
I: Integer;
|
||
|
begin
|
||
|
for I := 0 to Count - 1 do
|
||
|
begin
|
||
|
Result := Items[I].StartCurs - Posn;
|
||
|
if Result >= 0 then
|
||
|
begin
|
||
|
TfrxHtFloatingObj(Obj) := Items[I];
|
||
|
Exit;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
TfrxHtFloatingObj(Obj) := nil;
|
||
|
Result := 99999999;
|
||
|
end;
|
||
|
|
||
|
//-- BG ---------------------------------------------------------- 07.08.2013 --
|
||
|
procedure TFloatingObjList.SetItem(Index: Integer; const Item: TfrxHtFloatingObj);
|
||
|
begin
|
||
|
Put(Index, Item);
|
||
|
end;
|
||
|
|
||
|
{ TfrxHtBlockBase }
|
||
|
|
||
|
//-- BG ---------------------------------------------------------- 31.08.2013 --
|
||
|
constructor TfrxHtBlockBase.Create(Parent: TfrxHtCellBasic; Position: Integer; Attributes: TfrxHtAttributeList; Prop: TfrxHTProperties);
|
||
|
begin
|
||
|
inherited Create(Parent, Attributes, Prop);
|
||
|
if FDisplay = pdUnassigned then
|
||
|
FDisplay := pdBlock;
|
||
|
StartCurs := Position;
|
||
|
end;
|
||
|
|
||
|
//-- BG ---------------------------------------------------------- 31.08.2013 --
|
||
|
constructor TfrxHtBlockBase.CreateCopy(Parent: TfrxHtCellBasic; Source: TfrxHtmlNode);
|
||
|
//var
|
||
|
// T: TfrxHtBlockBase absolute Source;
|
||
|
begin
|
||
|
inherited CreateCopy(Parent,Source);
|
||
|
end;
|
||
|
|
||
|
function TfrxHtBlockBase.GetPosition(const Index: ThtRectEdge): Integer;
|
||
|
begin
|
||
|
Result := FPositions[Index];
|
||
|
end;
|
||
|
|
||
|
//{ TRenderSectionBaseList }
|
||
|
//
|
||
|
////-- BG ---------------------------------------------------------- 01.12.2013 --
|
||
|
//procedure TRenderSectionBaseList.Notify(Ptr: Pointer; Action: TListNotification);
|
||
|
//var
|
||
|
// Obj: TObject absolute Ptr;
|
||
|
//begin
|
||
|
// inherited;
|
||
|
// if (Action = lnDeleted) and (Obj is TInlineSection) then
|
||
|
// Obj.Free;
|
||
|
//end;
|
||
|
//
|
||
|
//{ TInlineSection }
|
||
|
//
|
||
|
////-- BG ---------------------------------------------------------- 01.12.2013 --
|
||
|
//procedure TInlineSection.AddElement(Section: TfrxHtSection);
|
||
|
//var
|
||
|
// I: Integer;
|
||
|
//begin
|
||
|
// // append Buff, Fonts, Images and FormControls
|
||
|
// BuffS := Buffs + Section.BuffS;
|
||
|
// Buff := PWideChar(Buffs);
|
||
|
//
|
||
|
// for I := 0 to Section.Fonts.Count - 1 do
|
||
|
// Fonts.Add(TfrxHtFontObj.CreateCopy(Section, Section.Fonts[I]));
|
||
|
//
|
||
|
// for I := 0 to Section.Images.Count - 1 do
|
||
|
// Images.Add(Section.Images[I].Clone(Section.Images[I].OwnerCell));
|
||
|
//
|
||
|
// for I := 0 to Section.FormControls.Count - 1 do
|
||
|
// FormControls.Add(Section.FormControls[I].Clone(Section.FormControls[I].OwnerCell));
|
||
|
//end;
|
||
|
//
|
||
|
////-- BG ---------------------------------------------------------- 01.12.2013 --
|
||
|
//constructor TInlineSection.Create(Parent: TfrxHtCellBasic);
|
||
|
//begin
|
||
|
// inherited Create(Parent);
|
||
|
//end;
|
||
|
|
||
|
//-- BG ---------------------------------------------------------- 24.02.2016 --
|
||
|
|
||
|
{ TfrxHtLineBreak }
|
||
|
|
||
|
//-- BG ---------------------------------------------------------- 24.02.2016 --
|
||
|
function TfrxHtLineBreak.TryGetClear(var Clear: ThtClearStyle): Boolean;
|
||
|
var
|
||
|
T: TfrxHtAttribute;
|
||
|
begin
|
||
|
Result := inherited TryGetClear(Clear);
|
||
|
if not Result then
|
||
|
if FAttributes <> nil then
|
||
|
begin
|
||
|
T := nil;
|
||
|
if FAttributes.Find(ClearSy, T) then
|
||
|
Result := TryStrToClearStyle(LowerCase(T.Name), Clear);
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
{ TfrxHtIndexObjList }
|
||
|
|
||
|
//-- BG ---------------------------------------------------------- 06.10.2016 --
|
||
|
function TfrxHtIndexObjList.Get(Index: Integer): TfrxHtIndexObj;
|
||
|
begin
|
||
|
Result := inherited Get(Index);
|
||
|
end;
|
||
|
|
||
|
{ TfrxHtBorderRecList }
|
||
|
|
||
|
//-- BG ---------------------------------------------------------- 06.10.2016 --
|
||
|
function TfrxHtBorderRecList.Get(Index: Integer): TfrxHtBorderRec;
|
||
|
begin
|
||
|
Result := inherited Get(Index);
|
||
|
end;
|
||
|
|
||
|
{ TfrxHtLineRecList }
|
||
|
|
||
|
//-- BG ---------------------------------------------------------- 06.10.2016 --
|
||
|
function TfrxHtLineRecList.Get(Index: Integer): TfrxHtLineRec;
|
||
|
begin
|
||
|
Result := inherited Get(Index);
|
||
|
end;
|
||
|
|
||
|
{ TSameWidthFix }
|
||
|
|
||
|
constructor TSameWidthFix.Create(Widths, MinWidths, MaxWidths: TIntArray; ColumnSpecs: TWidthTypeArray);
|
||
|
var
|
||
|
i, j, Len: Integer;
|
||
|
begin
|
||
|
Len := Length(Widths);
|
||
|
SetLength(FNeedFix, Len);
|
||
|
SetLength(FFirstIndex, Len);
|
||
|
for i := 0 to Len - 2 do
|
||
|
if (ColumnSpecs[i] = wtNone) and not FNeedFix[i] then
|
||
|
for j := i + 1 to Len - 1 do
|
||
|
if (ColumnSpecs[j] = wtNone) and not FNeedFix[j] and (Widths[i] = Widths[j]) and
|
||
|
(MinWidths[i] = MinWidths[j]) and (MaxWidths[i] = MaxWidths[j]) then
|
||
|
begin
|
||
|
FAtLeastOneFix := True;
|
||
|
FNeedFix[i] := True;
|
||
|
FNeedFix[j] := True;
|
||
|
FFirstIndex[i] := i;
|
||
|
FFirstIndex[j] := i;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
procedure TSameWidthFix.Fix(Widths: TIntArray);
|
||
|
var
|
||
|
i, j, Len, SumWidth, Count: Integer;
|
||
|
begin
|
||
|
if not FAtLeastOneFix then
|
||
|
Exit;
|
||
|
Len := Length(Widths);
|
||
|
for i := 0 to Len - 2 do
|
||
|
if FNeedFix[i] and (FFirstIndex[i] = i) then
|
||
|
begin
|
||
|
SumWidth := 0;
|
||
|
Count := 0;
|
||
|
for j := i to Len - 1 do
|
||
|
if FFirstIndex[j] = i then
|
||
|
begin
|
||
|
SumWidth := SumWidth + Widths[j];
|
||
|
Inc(Count);
|
||
|
end;
|
||
|
for j := i to Len - 1 do
|
||
|
if FFirstIndex[j] = i then
|
||
|
begin
|
||
|
Widths[j] := Round(SumWidth / Count);
|
||
|
SumWidth := SumWidth - Widths[j];
|
||
|
Dec(Count);
|
||
|
end;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
procedure TfrxHtRowList.RTLSwap;
|
||
|
var
|
||
|
i: Integer;
|
||
|
begin
|
||
|
for i := 0 to Count - 1 do
|
||
|
Items[i].RTLSwap;
|
||
|
end;
|
||
|
|
||
|
initialization
|
||
|
{$ifdef UNICODE}
|
||
|
{$else}
|
||
|
{$ifdef UseElPack}
|
||
|
UnicodeControls := True;
|
||
|
{$endif}
|
||
|
{$endif}
|
||
|
WaitStream := TMemoryStream.Create;
|
||
|
ErrorStream := TMemoryStream.Create;
|
||
|
WaitBitmap := TBitmap.Create;
|
||
|
ErrorBitmap := TBitmap.Create;
|
||
|
finalization
|
||
|
ErrorBitmap.Free;
|
||
|
WaitBitmap.Free;
|
||
|
ErrorStream.Free;
|
||
|
WaitStream.Free;
|
||
|
end.
|
||
|
|