CRVFData.pas
上传用户:daoqigc
上传日期:2021-04-20
资源大小:2795k
文件大小:263k
源码类别:

RichEdit

开发平台:

Delphi

  1. {*******************************************************}
  2. {                                                       }
  3. {       RichView                                        }
  4. {       TCustomRVFormattedData is a basic class         }
  5. {       representing RichView document with             }
  6. {       formatting.                                     }
  7. {                                                       }
  8. {       Copyright (c) Sergey Tkachenko                  }
  9. {       svt@trichview.com                               }
  10. {       http://www.trichview.com                        }
  11. {                                                       }
  12. {*******************************************************}
  13. unit CRVFData;
  14. interface
  15. {$I RV_Defs.inc}
  16. uses SysUtils, Windows, Messages, Classes, Graphics, Controls, Clipbrd,
  17.      Forms,
  18.      RVFuncs, RVStyle, RVItem, CRVData, DLines, RVScroll, RVBack, RVUni,
  19.     {$IFNDEF RVDONOTUSEDRAGDROP}
  20.      ActiveX, RVDragDrop,
  21.     {$ENDIF}
  22.      RVClasses;
  23. type
  24.   TCustomRVFormattedData = class;
  25. {-----------------------------------------------------------------------}
  26.   TRVJumpInfo = class
  27.     public
  28.      RVData: TCustomRVFormattedData;
  29.      l,t,w,h: Integer;
  30.      id, DrawItemNo: Integer;
  31.      Cursor: TCursor;
  32.   end;
  33.   TRVSoftPageBreakInfo = class
  34.     ItemNo, Offset, ExtraData: Integer;
  35.   end;
  36.   TRVSoftPageBreakList = class (TRVList)
  37.   public
  38.     function FindItem(ItemNo: Integer): Integer;
  39.   end;
  40.   TRVSelectingState = (rvsesInWord, rvsesOutsideWord, rvsesFreeMode,
  41.                        rvsesParaMode);
  42.   { TRVSelectingInfo: information about the selection process (with mouse).
  43.     For internal use (used as FSelectingInfo field of TCustomRVFormattedData.
  44.     This field is allocated while user is making selection.
  45.     Contains two set of fields: for starting and for ending parts of selection
  46.     (bounds of word containing selection end, actual selection position).      }
  47.   TRVSelectingInfo = class
  48.     public
  49.       DrawItemSOffs, DrawItemEOffs, DrawItemSWordOffs1, DrawItemSWordOffs2,
  50.       DrawItemEWordOffs1, DrawItemEWordOffs2: Integer;
  51.       DrawItemSNo, DrawItemENo: Integer;
  52.       SWordState, EWordState: TRVSelectingState;
  53.       procedure InitE(ASWordState: TRVSelectingState);
  54.       function IsAboveSWord(ADrawItemNo, ADrawItemOffs: Integer): Boolean;
  55.       function IsBelowSWord(ADrawItemNo, ADrawItemOffs: Integer): Boolean;
  56.       function IsInSWord(ADrawItemNo, ADrawItemOffs: Integer): Boolean;
  57.       function AreWordsEqual: Boolean;
  58.       function IsEWord(ADrawItemNo,
  59.         ADrawItemWordOffs1, ADrawItemWordOffs2: Integer): Boolean;
  60.       function IsEFreeStateNeeded(ADrawItemNo, ADrawItemOffs: Integer): Boolean;
  61.   end;
  62.   {--------------------------------------------------------------------------- }
  63.   {$IFNDEF RVDONOTUSEDRAGDROP}
  64.   { TCustomRVFormattedData: information about drag&drop caret location.
  65.     See: TCustomRVFormattedData.GetDragDropCaretInfo                           }
  66.   TRVDragDropCaretInfo = class
  67.     public
  68.       X,Y,                       // coordinates relative to RVData top-left
  69.       Height,                    // caret height
  70.       ItemNo, ItemOffs: Integer; // item index and offset in item, in RVData
  71.       RVData: TCustomRVData;     // RVData containing d&d caret
  72.       RefCount: Integer;
  73.   end;
  74.   {$ENDIF}
  75.   TRVFontInfoCacheItem = class
  76.   public
  77.     LastBiDiMode: TRVBiDiMode;
  78.     Canvas: TCanvas;
  79.     TextMetric: TTextMetric;
  80.     FontInfo: TFontInfo;
  81.     VerticalOffset: Integer;
  82.     EmptyLineHeight: Integer;
  83.     HyphenWidth: Integer;
  84.   end;
  85.   PRVFontInfoCacheItem = ^TRVFontInfoCacheItem;
  86.   TRVFontInfoCache = class (TRVList)
  87.   protected
  88.     FCanvas: TCanvas;
  89.     FRVStyle: TRVStyle;
  90.     FCanUseCustomPPI: Boolean;
  91.     FOwner: TObject;
  92.     function GetItems(Index: Integer): TRVFontInfoCacheItem; virtual; abstract;
  93.   public
  94.     CurParaBiDiMode: TRVBiDiMode;
  95.     IgnoreParaBiDiMode: Boolean;
  96.     LastTextStyle: Integer;
  97.     constructor Create(const AData: TCustomRVFormattedData;
  98.       const ARVStyle: TRVStyle; const ACanvas: TCanvas; ACanUseCustomPPI: Boolean); virtual;
  99.     property Items[Index: Integer]: TRVFontInfoCacheItem read GetItems; default;
  100.   end;
  101.   TRVFormatParams = record
  102.     x, baseline, prevdesc, prevabove:Integer;
  103.     IsParaStart: Boolean;
  104.     LineWidth, FirstIndent, LastDrawItem, VerticalOffs, LeftIndent, RightIndent: Integer;
  105.     LastTextStyle: Integer;
  106.     FirstParaItemNo: Integer;
  107.     NoCaching, Reformatting: Boolean;
  108.     DontFSL: Boolean;
  109.     LastTabDrawItemNo: Integer;
  110.     LastTabAlign: TRVTabAlign;
  111.     LastTabPosition: Integer;
  112.     SpaceEaten: Boolean;
  113.     FontInfoCache: TRVFontInfoCache;
  114.     FormatCanvas: TCanvas;
  115.     FormatCanvasHandle: HDC;
  116.     TextMetric: TTextMetric;
  117.   end;
  118.   {--------------------------------------------------------------------------- }
  119.   { TCustomRVFormattedData: RichView document with formatting.                 }
  120.   TCustomRVFormattedData = class (TCustomRVData)
  121.     private
  122.       LastRaisedCP: TRVCPInfo;
  123.       FXORDrawing: TMouseMoveEvent;
  124.       FCaptureMouseItem: TCustomRVItemInfo;
  125.       FSelectingInfo: TRVSelectingInfo;
  126.       //FZoomPercent: Integer;
  127.       //LastSelectionRect: TRect;
  128.       function FindDrawItemAtPos(X, Y: Integer): Integer;
  129.       procedure CopyText_;
  130.       procedure CopyTextW_;
  131.       procedure CopyImage_;
  132.       {$IFNDEF RVDONOTUSERVF}
  133.       procedure CopyRVF_(Color: TColor; Background: TRVBackground);
  134.       {$ENDIF}
  135.       {$IFNDEF RVDONOTUSERTF}
  136.       procedure CopyRTF_(Color: TColor; Background: TRVBackground);
  137.       {$ENDIF}
  138.       procedure StartFormatting;
  139.       procedure EndFormatting;
  140.       procedure SearchHotItem(X, Y, HOffs, VOffs: Integer);
  141.       procedure AdjustSelection;
  142.       //procedure SetZoomPercent(const Value: Integer);
  143.     protected
  144.       { Protected declarations }
  145.       XorImageDrawn: Boolean;
  146.       MouseX, MouseY: Integer;
  147.       Jumps: TList;
  148.       nJmps: Integer;
  149.       LastItemFormatted: Integer;
  150.       LastJumpMovedAbove, LastDIMovedAbove: Integer;
  151.       LastRVDataMovedAbove: TCustomRVFormattedData;
  152.       LastJumpDowned: Integer;
  153.       FPartialSelectedItem: TCustomRVItemInfo;
  154.       AlreadyFormatted: Boolean;
  155.       FSoftPageBreaks: TRVSoftPageBreakList;
  156.       FClickedDrawItemNo: Integer;
  157.       { Inplace }
  158.       function GetInplaceEditor: TControl; dynamic;
  159.       procedure DestroyInplaceEditor; dynamic;
  160.       { Clearing }
  161.       procedure ClearLastJump;
  162.       { Drawing item info }
  163.       function IsDrawItemParaStart(DrawItemNo: Integer): Boolean;
  164.       function IsDrawItemItemStart(DrawItemNo: Integer): Boolean;
  165.       function IsDrawItemParaSectionStart(DrawItemNo: Integer): Boolean;
  166.       function IsDrawItemParaEnd(DrawItemNo: Integer): Boolean;
  167.       function IsDrawItemFromNewLine(DrawItemNo: Integer): Boolean;
  168.       function IsDrawItemLastOnWrappedLine(DrawItemNo: Integer): Boolean;
  169.       function GetDrawItemStyle(DrawItemNo: Integer): Integer;
  170.       function IsSpaceBetweenDrawItems(DrawItemNo: Integer): Boolean;
  171.       { Drawing }
  172.       procedure PostPaintTo(Canvas: TCanvas;
  173.         HOffs, VOffs, FirstDrawItemNo, LastDrawItemNo: Integer); virtual;
  174.       { Selecting }
  175.       procedure FindDrawItemForSel(X, Y: Integer; var No, Offs: Integer; Strict: Boolean);
  176.       function AdjustSelectionByMode(X,Y: Integer): Boolean;
  177.       function AdjustLineSelection(X,Y: Integer): Boolean;
  178.       function ExpandSelectionToParagraph(OnlyIfMultiple: Boolean): Boolean;
  179.       procedure ExpandSelectionToLines(OneLine: Boolean);
  180.       procedure DeselectPartiallySelectedItem(NewPartiallySelected: TCustomRVItemInfo); dynamic;
  181.       procedure SetPartialSelectedItem(Item: TCustomRVItemInfo); virtual;
  182.       { Selection info }
  183.       function IsSelectionTopDown: Boolean;
  184.       function DItem_InsideSelection(DItemNo, DItemOffs: Integer): Boolean;
  185.       function GetClientSelectionRect: TRect;
  186.       {$IFNDEF RVDONOTUSEDRAGDROP}
  187.       { Drag & drop: drop to }
  188.       procedure DrawDragDropCaret(Canvas: TCanvas; OnlyForSelf: Boolean);
  189.       { Drag & drop: drop from }
  190.       function CanStartDragging: Boolean; dynamic;
  191.       function InitDragging(var DropSource: TRVDropSource; var OKEffect: Integer): Boolean; dynamic;
  192.       procedure DoneDragging(FDeleteSelection: Boolean); dynamic;
  193.       {$ENDIF}
  194.       { Formatting }
  195.       procedure FinishScreenLine(const sad: TRVScreenAndDevice;
  196.         LineWidth, LastDrawItem: Integer; parafinished: Boolean;
  197.         var ExtraSpace: Integer; var dontdoit: Boolean; Canvas: TCanvas);
  198.       procedure UpdateLastTab(var Params: TRVFormatParams);
  199.       procedure FormatLine(const Text, OrigText: String; StartOffs, Len, ItemNo: Integer;
  200.         Canvas: TCanvas; var sad: TRVScreenAndDevice;
  201.         var Params: TRVFormatParams);
  202.       procedure FormatWords(ItemNo: Integer; Canvas: TCanvas;
  203.         var sad: TRVScreenAndDevice; var Params: TRVFormatParams);
  204.       procedure GetSADForFormatting(Canvas: TCanvas; var sad: TRVScreenAndDevice);  virtual;
  205.       procedure Formatted(FirstItemNo, LastItemNo: Integer; Partial: Boolean); dynamic;
  206.       procedure CreateFontInfoCache(ACanvas: TCanvas); dynamic;
  207.       procedure DestroyFontInfoCache(var Cache: TRVFontInfoCache); dynamic;
  208.       function GetFontInfoCache(ACanvas: TCanvas;
  209.         RVData: TCustomRVFormattedData): TRVFontInfoCache; dynamic;
  210.       { Misc. }
  211.       procedure ConcateItems(FirstItemNo: Integer);
  212.       function InsideWord(DrawItemNo, DrawItemOffs: Integer): Boolean;
  213.       procedure GetWordBounds(DrawItemNo, DrawItemOffs: Integer;
  214.         var DrawItemWordOffs1, DrawItemWordOffs2: Integer);
  215.       procedure GetScreenLineBounds(DrawItemNo: Integer; var First, Last: Integer);
  216.       procedure AfterDeleteStyles(Data: TRVDeleteUnusedStylesData); override;
  217.       procedure InternalFreeItem(item: TCustomRVItemInfo; Clearing: Boolean); override;
  218.       procedure ApplyZoom(Canvas: TCanvas);
  219.       procedure ZoomRectDown(var r: TRect);
  220.       procedure ZoomInt(var v: Integer);
  221.       procedure RestoreZoom(Canvas: TCanvas);
  222.       function GetFirstItemMarker(var ListNo, Level: Integer): Boolean; virtual;
  223.       procedure GetIndents(ItemNo: Integer; IsParaStart: Boolean;
  224.         var FirstParaItemNo: Integer; var LeftIndent, RightIndent,
  225.         PureLeftIndent: Integer);
  226.       function GetRVDataExtraVOffs: Integer; virtual;
  227.       function GetMaxIndent(ItemNo: Integer; var FirstParaItemNo: Integer): Integer;
  228.       {$IFNDEF RVDONOTUSERVF}
  229.       procedure RVFGetLimits(SaveScope: TRVFSaveScope;
  230.         var StartItem, EndItem, StartOffs, EndOffs: Integer;
  231.         var StartPart, EndPart: TRVMultiDrawItemPart); override;
  232.       {$ENDIF}
  233.       { Live spelling }
  234.       {$IFNDEF RVDONOTUSELIVESPELL}
  235.       procedure LiveSpellingCheckCurrentItem; dynamic;
  236.       {$ENDIF}      
  237.     public
  238.       FActiveItem: TCustomRVItemInfo;
  239.       DocumentWidth: Integer;
  240.       DocumentHeight, TextWidth,FocusedItemNo: Integer;
  241.       DrawItems: TRVDrawLines;
  242.       FSelStartNo, FSelEndNo, FSelStartOffs, FSelEndOffs: Integer;
  243.       { Create & Destroy }
  244.       constructor Create;
  245.       destructor Destroy; override;
  246.       { Clearing }
  247.       procedure ClearTemporal;virtual;
  248.       procedure Clear; override;
  249.       { Soft page breaks }
  250.       procedure AssignSoftPageBreaks(RVPrint: TComponent);
  251.       function ClearSoftPageBreaks: Boolean;
  252.       { Focused items }
  253.       function GetNextFocusedItem(ItemNo: Integer; GoForward: Boolean;
  254.         var TopLevelRVData: TCustomRVFormattedData;
  255.         var TopLevelItemNo: Integer): Integer;
  256.       procedure ClearFocus;
  257.       procedure AdjustFocus(NewFocusedItemNo: Integer;
  258.         TopLevelRVData: TPersistent; TopLevelItemNo: Integer); dynamic;
  259.       { Animation }
  260.       {$IFNDEF RVDONOTUSEANIMATION}
  261.       function AllowAnimation: Boolean; dynamic;
  262.       procedure InsertAnimator(var Animator: TObject); dynamic;
  263.       procedure ResetAniBackground; dynamic;
  264.       {$ENDIF}
  265.       { Size and position of document }
  266.       procedure GetOrigin(var ALeft, ATop: Integer); virtual;
  267.       procedure GetOriginEx(var ALeft, ATop: Integer); dynamic;
  268.       function GetAreaWidth: Integer; virtual;                abstract;
  269.       function GetAreaHeight: Integer; virtual;                abstract;      
  270.       function GetLeftMargin: Integer; virtual;               abstract;
  271.       function GetRightMargin: Integer; virtual;              abstract;
  272.       function GetTopMargin: Integer; virtual;                abstract;
  273.       function GetBottomMargin: Integer; virtual;             abstract;
  274.       function GetMinTextWidth: Integer; virtual;             abstract;
  275.       function GetMaxTextWidth: Integer; virtual;             abstract;
  276.       function GetWidth: Integer; virtual; abstract;
  277.       function GetHeight: Integer; virtual; abstract;
  278.       procedure SetDocumentAreaSize(Width,Height: Integer;
  279.         UpdateH: Boolean); virtual; abstract;
  280.       function CalculatePureParaSectionWidth(ItemNo: Integer;
  281.         var FirstParaItemNo: Integer; sad: PRVScreenAndDevice; Canvas: TCanvas): Integer;
  282.       function CalculateParaSectionMinWidth(StartItemNo: Integer;
  283.         var FirstParaItemNo: Integer; sad: PRVScreenAndDevice;
  284.         Canvas: TCanvas): Integer;
  285.       function CalculateParaSectionMinWidthDef(StartItemNo: Integer): Integer;
  286.       function CalculateParaSectionsMinWidth(StartItemNo, EndItemNo: Integer;
  287.         var FirstParaItemNo: Integer; sad: PRVScreenAndDevice;
  288.         Canvas: TCanvas): Integer;
  289.       function CalculateParaSectionsMinWidthDef(StartItemNo, EndItemNo: Integer): Integer;
  290.       function CalculateMinItemWidthPlus_WithoutPSWidth(ItemNo: Integer;
  291.         sad: PRVScreenAndDevice; Canvas: TCanvas): Integer;
  292.       function CalculateMinItemsWidthPlus(StartItemNo, EndItemNo: Integer;
  293.         var FirstParaItemNo: Integer; sad: PRVScreenAndDevice;
  294.         Canvas: TCanvas): Integer;
  295.       function CalculateMinItemWidthPlusEx(ItemNo: Integer): Integer;
  296.       function CalculateMinItemsWidthPlusEx(StartItemNo, EndItemNo: Integer): Integer;
  297.       function CalculateMinDocWidthPlus(sad: PRVScreenAndDevice; Canvas: TCanvas): Integer;
  298.       function CalculateMinWidthAfterInsert(item:TCustomRVItemInfo; InsertItemNo: Integer): Integer;
  299.       { Coordinates }
  300.       procedure ResetSubCoords; dynamic;
  301.       function GetDrawItemNo(BoundLine: Integer; Option: Integer): Integer;
  302.       function GetItemCoords(ItemNo: Integer;var Left,Top: Integer): Boolean;
  303.       function GetItemClientCoords(ItemNo: Integer;var Left,Top: Integer): Boolean;
  304.       function ClientToScreen(const p: TPoint): TPoint; dynamic;
  305.       function ScreenToClient(const p: TPoint): TPoint; dynamic;
  306.       {$IFNDEF RVDONOTUSESMARTPOPUP}
  307.       procedure AdjustSpecialControlsCoords(RVData: TCustomRVFormattedData); dynamic;
  308.       {$ENDIF}
  309.       procedure AdjustChildrenCoords;
  310.       { Get ... at (X,Y) }
  311.       procedure GetWordAt(X, Y: Integer; var RVData: TCustomRVFormattedData;
  312.         var ItemNo: Integer; var Word: String);
  313.       function FindWordAt(var Word: String; X, Y: Integer; var StyleNo,
  314.         ItemNo, Offs: Integer; var RVData: TCustomRVFormattedData): Boolean;
  315.       procedure GetItemAt(X,Y: Integer; var ItemNo, OffsetInItem: Integer);
  316.       procedure GetItemAtEx(X,Y: Integer; var RVData: TCustomRVFormattedData;
  317.         var ItemNo, OffsetInItem: Integer; Strict: Boolean;
  318.         var InSubRVDataOwnerItem: Boolean);
  319.       { Scrolling }
  320.       procedure ShowRectangle(Left, Top, Width, Height: Integer); dynamic;
  321.       procedure AdjustVScrollUnits; virtual; abstract;
  322.       function GetHOffs: Integer; virtual;
  323.       function GetVOffs: Integer; virtual;
  324.       function GetZHOffs: Integer;
  325.       function GetZVOffs: Integer;
  326.       procedure ScrollTo(Y: Integer; Redraw: Boolean); virtual; abstract;
  327.       procedure HScrollTo(X: Integer); virtual; abstract;
  328.       function GetVSmallStep: Integer; virtual; abstract;
  329.       procedure AfterVScroll;
  330.       procedure OnTimerScroll;
  331.       { Calling events }
  332.       procedure DoCopy; dynamic;
  333.       function IsAssignedCopy: Boolean; dynamic;
  334.       function IsAssignedRVMouseUp: Boolean; dynamic; abstract;
  335.       function IsAssignedRVMouseDown: Boolean; dynamic; abstract;
  336.       function IsAssignedRVRightClick: Boolean; dynamic;
  337.       function IsAssignedJump: Boolean; dynamic; abstract;
  338.       function IsAssignedRVDblClick: Boolean; dynamic;
  339.       function IsAssignedCheckpointVisible: Boolean; dynamic; abstract;
  340.       procedure DoRVMouseUp(Button: TMouseButton; Shift: TShiftState;
  341.         ItemNo, X, Y: Integer); dynamic; abstract;
  342.       procedure DoRVMouseDown(Button: TMouseButton; Shift: TShiftState;
  343.                             ItemNo, X, Y: Integer); dynamic; abstract;
  344.       procedure DoRVRightClick(const ClickedWord: String; StyleNo, X, Y: Integer);dynamic;
  345.       procedure DoJump(id: Integer); dynamic; abstract;
  346.       procedure DoRVMouseMove(id: Integer); dynamic; abstract;
  347.       procedure DoRVDblClick(const ClickedWord: String; StyleNo: Integer); dynamic;
  348.       procedure DoSelect; dynamic;
  349.       procedure DoCheckpointVisible(CheckpointData: TCheckpointData); dynamic; abstract;
  350.       procedure DoCurrentTextStyleConversion(var StyleNo: Integer;
  351.         ParaStyleNo, ItemNo, UserData: Integer; ToWholeParagraphs: Boolean); dynamic;
  352.       { Properties }
  353.       function GetNormalCursor: TCursor; dynamic; abstract;
  354.       function GetCPEventKind: TCPEventKind; dynamic;
  355.       function GetBackground: TRVBackground; virtual; abstract;
  356.       function GetCanvas: TCanvas; virtual;
  357.       function GetColor: TColor; virtual; abstract;
  358.       procedure SetCursor(Cursor: TCursor); dynamic;
  359.       function GetEditor: TWinControl; dynamic;
  360.       { Mouse }
  361.       procedure MouseLeave;
  362.       procedure MouseMove(Shift: TShiftState; X, Y: Integer); dynamic;
  363.       procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer);dynamic;
  364.       procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer);dynamic;
  365.       procedure DblClick;
  366.       procedure AdjustMouseUpSelection; dynamic;
  367.       { Mouse capture }
  368.       procedure SetMouseCapture(Item: TCustomRVItemInfo;  var Left,Top: Integer);
  369.       procedure ReleaseMouseCapture(Item: TCustomRVItemInfo);
  370.       {$IFNDEF RVDONOTUSEDRAGDROP}
  371.       { Drag & drop: drop to }
  372.       function GetDragDropCaretInfo: TRVDragDropCaretInfo; dynamic;      
  373.       procedure SetDragDropCaretTo(X,Y: Integer);
  374.       procedure RemoveDragDropCaret;
  375.       procedure SetDragDropCaret(ItemNo, Offs: Integer);
  376.       { Drag & drop: drop from }
  377.       procedure DoDrag;
  378.       function IsDragging: Boolean; dynamic;
  379.       {$ENDIF}
  380.       { Insertion and protection (used in editor or by drag&drop) }
  381.       function CanInsertHere(ItemNo, Offs: Integer): Boolean;
  382.       function IsProtected(ItemNo: Integer; Option: TRVProtectOption): Boolean;
  383.       function IsParaProtected(ParaNo: Integer; Option: TRVParaOption): Boolean;
  384.       function IsItemParaProtected(ItemNo: Integer): Boolean;
  385.       function IsSticking(FirstItemNo: Integer; NoSound: Boolean): Boolean;
  386.       { Drawing }
  387.       procedure DrawBackground(Canvas: TCanvas; r: TRect); virtual;
  388.       procedure PaintTo(Canvas: TCanvas; AClipRect: TRect);
  389.       procedure GetItemBackground(ItemNo: Integer; r: TRect; MakeImageRect: Boolean;
  390.         var Color: TColor; var bmp: TBitmap;
  391.         var UseBitmap: Boolean); virtual;
  392.       { Redrawing }
  393.       procedure InvalidateJumpRect(id: Integer);
  394.       procedure Refresh;
  395.       procedure UpdateView;
  396.       procedure Invalidate;
  397.       procedure InvalidateRect(const r: TRect);
  398.       { Palette }
  399.       procedure UpdateBackgroundPaletteInfo(Background: TRVBackground);
  400.       function UpdatingBackgroundPalette: Boolean;
  401.       { Drawing XOR }
  402.       procedure XorDrawing; virtual;
  403.       procedure XorDrawingEx(X,Y: Integer);
  404.       function ClearXorDrawing: Boolean;
  405.       procedure AssignXorDrawing(P: TMouseMoveEvent);
  406.       function UsingThisXorDrawing(P: TMouseMoveEvent): Boolean;
  407.       procedure UnAssignXorDrawing(P: TMouseMoveEvent);
  408.       { Formatting }
  409.       procedure FormatParas(StartDrawItemNo, EndDrawItemNo, ItemsInserted: Integer);
  410.       procedure FormatParasExact(StartDrawItemNo, EndDrawItemNo,
  411.         ItemsInserted: Integer; NoCaching: Boolean);
  412.       procedure Format_(OnlyResized, ForceFormat, NoScroll: Boolean;
  413.         depth: Integer; Canvas: TCanvas; OnlyTail, NoCaching, Reformatting: Boolean); virtual;
  414.       procedure Format(NoCaching: Boolean);
  415.       { Selecting }
  416.       procedure DoSetSelectionBounds(StartItemNo, StartItemOffs, EndItemNo,
  417.         EndItemOffs: Integer);
  418.       procedure SetSelectionBounds(StartItemNo, StartItemOffs, EndItemNo,
  419.         EndItemOffs: Integer);
  420.       function SearchText(Down, MatchCase, WholeWord: Boolean; s: String): Boolean;
  421.       procedure SelectWordAt(X, Y: Integer);
  422.       function SelectControl(AControl: TControl): Boolean;
  423.       procedure Deselect(NewPartiallySelected: TCustomRVItemInfo;
  424.         MakeEvent: Boolean); dynamic;
  425.       procedure SelectAll;
  426.       procedure SelectLine(ItemNo, Offs: Integer);
  427.       procedure RestoreSelBounds(StartNo, EndNo, StartOffs, EndOffs: Integer);
  428.       procedure SrchSelectIt(strt, offs, len: Integer; Invert: Boolean); dynamic;
  429.       procedure SrchStart(Down: Boolean; var strt, offs: Integer);dynamic;
  430.       { Chosen RVData & Item }
  431.       procedure AssignChosenRVData(RVData: TCustomRVFormattedData;
  432.         Item: TCustomRVItemInfo); dynamic;
  433.       procedure SilentReplaceChosenRVData(RVData: TCustomRVFormattedData); dynamic;
  434.       procedure UnassignChosenRVData(RVData: TCustomRVData); dynamic;
  435.       { Get selection }
  436.       function SelectionExists(AllowReset: Boolean;
  437.         UsePartialSelected: Boolean): Boolean;
  438.       procedure GetSelectionBounds(var StartItemNo, StartItemOffs, EndItemNo,
  439.         EndItemOffs: Integer; Normalize: Boolean);
  440.       procedure GetSelBounds(var StartNo, EndNo, StartOffs, EndOffs: Integer;
  441.         Normalize: Boolean); dynamic;
  442.       procedure StoreSelBounds(var StartNo, EndNo, StartOffs, EndOffs: Integer;
  443.         Normalize: Boolean);
  444.       procedure GetSelectionBoundsEx(var StartItemNo, StartItemOffs, EndItemNo,
  445.         EndItemOffs: Integer; Normalize: Boolean); dynamic;
  446.       procedure GetSelStart(var DINo, DIOffs: Integer);dynamic;
  447.       function GetSelText(Unicode: Boolean): String;
  448.       function GetSelectedImage: TGraphic;
  449.       function GetSelectionRect: TRect;
  450.       { Selection misc. }
  451.       procedure DoOnSelection(AllowScrolling: Boolean); dynamic;
  452.       function Item_InsideSelection(ItemNo, ItemOffs: Integer): Boolean;      
  453.       { Checkpoints }
  454.       procedure GetCheckpointXY(CheckpointData: TCheckpointData; var X, Y: Integer);
  455.       function  GetCheckpointYEx(CheckpointData: TCheckpointData): Integer;
  456.       { Hypertext }
  457.       procedure BuildJumpsCoords(var StartJumpNo: Integer; jumps: TList);
  458.       procedure ClearJumps;
  459.       procedure AdjustJumpsCoords;
  460.       function  GetJumpPointY(id: Integer): Integer;
  461.       function  GetJumpPointItemNo(id: Integer): Integer;
  462.       procedure GetJumpPointLocation(id: Integer; var RVData: TCustomRVFormattedData; var ItemNo: Integer);
  463.       { Copying to the Clipboard }
  464.       {$IFNDEF RVDONOTUSERVF}
  465.       procedure CopyRVF(Color: TColor; Background: TRVBackground);
  466.       {$ENDIF}
  467.       {$IFNDEF RVDONOTUSERTF}
  468.       procedure CopyRTF(Color: TColor; Background: TRVBackground);
  469.       {$ENDIF}
  470.       procedure CopyText;
  471.       procedure CopyTextW;
  472.       procedure CopyImage;
  473.       procedure Copy(Color: TColor; Background: TRVBackground);
  474.       function  CopyDef(Color: TColor; Background: TRVBackground): Boolean;
  475.       { Items and drawitems indices, line numbers }
  476.       function GetLineNo(ItemNo, ItemOffs: Integer): Integer;
  477.       procedure GetParaBounds(DINo1, DINo2: Integer; var ParaStart, ParaEnd: Integer);
  478.       function GetFirstVisible(TopLine: Integer): Integer;
  479.       function GetFirstItemVisible: Integer; dynamic;
  480.       function GetLastItemVisible: Integer; dynamic;
  481.       function GetOffsBeforeDrawItem(DrawItemNo: Integer): Integer;
  482.       function GetOffsAfterDrawItem(DrawItemNo: Integer): Integer;
  483.       procedure DrawItem2Item(DrawItemNo, DrawItemOffs: Integer; var ItemNo, ItemOffs: Integer);
  484.       procedure Item2DrawItem(ItemNo, ItemOffs: Integer; var DrawItemNo, DrawItemOffs: Integer);
  485.       procedure Item2FirstDrawItem(ItemNo: Integer; var DrawItemNo: Integer);
  486.       procedure Item2LastDrawItem(ItemNo: Integer; var DrawItemNo: Integer);
  487.       function FindDrawItemByItem(ItemNo: Integer): Integer;
  488.       procedure InvalidateDrawItem(DrawItemNo, Spacing: Integer);
  489.       { Deleting }
  490.       procedure DeleteItems(FirstItemNo, Count: Integer); override;
  491.       procedure DeleteParas(FirstItemNo, LastItemNo: Integer);
  492.       { Others }
  493.       procedure Normalize;
  494.       { Properties }
  495.       property PartialSelectedItem: TCustomRVItemInfo
  496.         read FPartialSelectedItem write SetPartialSelectedItem;
  497.       property CaptureMouseItem: TCustomRVItemInfo read FCaptureMouseItem;
  498.       property SoftPageBreaks: TRVSoftPageBreakList read FSoftPageBreaks;
  499.       //property ZoomPercent:Integer read FZoomPercent write SetZoomPercent;
  500.       { Selection Info }
  501.       function IsMultiParagraphSelection: Boolean;      
  502.   end;
  503. const
  504.   RichViewSafeFormatting:Boolean = False;
  505.   RichViewShowGhostSpaces: Boolean = False;
  506. implementation
  507. uses RichView,
  508.     {$IFNDEF RVDONOTUSELIVESPELL}
  509.     RVWordPaint,
  510.     {$ENDIF}
  511.     {$IFNDEF RVDONOTUSELISTS}
  512.     RVMarker,
  513.     {$ENDIF}
  514.     RVCtrlData, RVStr, PtblRV, PtRVData
  515.     ;
  516. {==============================================================================}
  517. const gdinFirstVisible        = 1;
  518. const gdinLastCompleteVisible = 2;
  519. const gdinLastVisible         = 3;
  520. const MAXLINELENGTH           = 1000;
  521. {------------------------------------------------------------------------------}
  522. function MyStrRScanA(Str: PChar; Chr: Char; Length: Integer): PChar;
  523. begin
  524.   Result := Str+Length-1;
  525.   while Result>=Str do begin
  526.     if Result^=Chr then
  527.       exit;
  528.     dec(Result);
  529.   end;
  530.   Result := nil;
  531. end;
  532. {------------------------------------------------------------------------------}
  533. {$IFNDEF RVDONOTUSEUNICODE}
  534. {
  535. function MyStrRScanW(Str: PChar; Chr: Char; Length: Integer): PChar;
  536. begin
  537.   Result := Str+(Length-1)*2;
  538.   while Result>=Str do begin
  539.     if (Result^=Chr) and ((Result+1)^=#0) then
  540.       exit;
  541.     dec(Result, 2);
  542.   end;
  543.   Result := nil;
  544. end;
  545. }
  546. {$ENDIF}
  547. {------------------------------------------------------------------------------}
  548. function max(a,b: Integer): Integer;
  549. begin
  550.   if a>b then
  551.     max := a
  552.   else
  553.     max := b;
  554. end;
  555. {================================ TRVSelectingInfo ============================}
  556. { Initializing ending values with the starting values                          }
  557. procedure TRVSelectingInfo.InitE(ASWordState: TRVSelectingState);
  558. begin
  559.   DrawItemEOffs := DrawItemSOffs;
  560.   DrawItemENo := DrawItemSNo;
  561.   DrawItemEWordOffs1 := DrawItemSWordOffs1;
  562.   DrawItemEWordOffs2 := DrawItemSWordOffs2;
  563.   if ASWordState=rvsesParaMode then begin
  564.     SWordState := rvsesParaMode;
  565.     EWordState := rvsesParaMode;
  566.     end
  567.   else begin
  568.     SWordState := ASWordState;
  569.     EWordState := rvsesInWord;
  570.   end;
  571. end;
  572. {------------------------------------------------------------------------------}
  573. { Is (ADrawItemNo, ADrawItemOffs) in inside the starting word?                 }
  574. function TRVSelectingInfo.IsInSWord(ADrawItemNo, ADrawItemOffs: Integer): Boolean;
  575. begin
  576.   Result := (ADrawItemNo=DrawItemSNo) and
  577.             (ADrawItemOffs>=DrawItemSWordOffs1) and
  578.             (ADrawItemOffs<=DrawItemSWordOffs2)
  579. end;
  580. {------------------------------------------------------------------------------}
  581. { Is (ADrawItemNo, ADrawItemOffs) below the starting word?                     }
  582. function TRVSelectingInfo.IsBelowSWord(ADrawItemNo, ADrawItemOffs: Integer): Boolean;
  583. begin
  584.   Result := (ADrawItemNo>DrawItemSNo) or
  585.             ((ADrawItemNo=DrawItemSNo) and (ADrawItemOffs>DrawItemSWordOffs2));
  586. end;
  587. {------------------------------------------------------------------------------}
  588. { Is (ADrawItemNo, ADrawItemOffs) above the starting word?                     }
  589. function TRVSelectingInfo.IsAboveSWord(ADrawItemNo, ADrawItemOffs: Integer): Boolean;
  590. begin
  591.   Result := (ADrawItemNo<DrawItemSNo) or
  592.             ((ADrawItemNo=DrawItemSNo) and (ADrawItemOffs<DrawItemSWordOffs1));
  593. end;
  594. {------------------------------------------------------------------------------}
  595. { Are the positions of the ending and the starting words equal?                }
  596. function TRVSelectingInfo.AreWordsEqual: Boolean;
  597. begin
  598.   Result := (DrawItemENo=DrawItemSNo) and
  599.             (DrawItemEWordOffs1=DrawItemSWordOffs1) and
  600.             (DrawItemEWordOffs2=DrawItemSWordOffs2);
  601. end;
  602. {------------------------------------------------------------------------------}
  603. { Are the parameters equal to the ending word?                                 }
  604. function TRVSelectingInfo.IsEWord(ADrawItemNo,
  605.   ADrawItemWordOffs1, ADrawItemWordOffs2: Integer): Boolean;
  606. begin
  607.   Result := (DrawItemENo=DrawItemENo) and
  608.             (DrawItemEWordOffs1=ADrawItemWordOffs1) and
  609.             (DrawItemEWordOffs2=ADrawItemWordOffs2);
  610. end;
  611. {------------------------------------------------------------------------------}
  612. { Should we change EWordState to rvsesFreeMode?
  613.   This function assumes that the ending point of the selection
  614.   (ADrawItemNo, ADrawItemOffs) is inside the ending word                       }
  615. function TRVSelectingInfo.IsEFreeStateNeeded(ADrawItemNo,
  616.   ADrawItemOffs: Integer): Boolean;
  617. begin
  618.   Result :=
  619.     (IsAboveSWord(ADrawItemNo,ADrawItemOffs) and (ADrawItemOffs>DrawItemEOffs))
  620.     or
  621.     (IsBelowSWord(ADrawItemNo,ADrawItemOffs) and (ADrawItemOffs<DrawItemEOffs));
  622. end;
  623. {=========================== TRVSoftPageBreakList =============================}
  624. function TRVSoftPageBreakList.FindItem(ItemNo: Integer): Integer;
  625. var a,b,no: Integer;
  626.   {....................................}
  627.   procedure AdjustResult(var R: Integer);
  628.   begin
  629.     while (R>0) and (TRVSoftPageBreakInfo(Items[R-1]).ItemNo=ItemNo) do
  630.       dec(R);
  631.   end;
  632.   {....................................}
  633. begin
  634.   a := 0;
  635.   b := Count-1;
  636.   while b-a>1 do begin
  637.     Result := (a+b) div 2;
  638.     no := TRVSoftPageBreakInfo(Items[Result]).ItemNo;
  639.     if no=ItemNo then begin
  640.       AdjustResult(Result);
  641.       exit;
  642.     end;
  643.     if no<ItemNo then
  644.       a := Result
  645.     else
  646.       b := Result;
  647.   end;
  648.   if TRVSoftPageBreakInfo(Items[a]).ItemNo=ItemNo then
  649.     Result := a
  650.   else if TRVSoftPageBreakInfo(Items[b]).ItemNo=ItemNo then
  651.     Result := b
  652.   else
  653.     Result := -1;
  654.   AdjustResult(Result);
  655. end;
  656. {============================ TCustomRVFormattedData ==========================}
  657. constructor TCustomRVFormattedData.Create;
  658. begin
  659.   inherited Create;
  660.   DrawItems := TRVDrawLines.Create;
  661.   Jumps     := TList.Create;
  662.   FSelStartNo    := -1;
  663.   FSelEndNo      := -1;
  664.   FSelStartOffs  := 0;
  665.   FSelEndOffs    := 0;
  666.   TextWidth      := -1;
  667.   DocumentWidth  := -1;
  668.   DocumentHeight := 0;//GetTopMargin;
  669.   LastItemFormatted  := -1;
  670.   LastJumpMovedAbove := -1;
  671.   LastDIMovedAbove   := -1;
  672.   LastJumpDowned     := -1;
  673.   FocusedItemNo      := -1;
  674.   FActiveItem        := nil;
  675.   FPartialSelectedItem :=  nil;
  676.   //FZoomPercent       := 100;
  677. end;
  678. {------------------------------------------------------------------------------}
  679. destructor TCustomRVFormattedData.Destroy;
  680. begin
  681.   ClearTemporal;
  682.   DrawItems.Free;
  683.   DrawItems := nil;
  684.   Jumps.Free;
  685.   Jumps  := nil;
  686.   inherited Destroy;
  687. end;
  688. {------------------------------------------------------------------------------}
  689. procedure TCustomRVFormattedData.ClearLastJump;
  690. begin
  691.   if LastRVDataMovedAbove<>nil then begin
  692.     LastRVDataMovedAbove.State := LastRVDataMovedAbove.State - [rvstDrawHover];
  693.     LastRVDataMovedAbove.LastJumpMovedAbove := -1;
  694.     LastRVDataMovedAbove.LastJumpDowned     := -1;
  695.     DoRVMouseMove(-1);
  696.   end;
  697.   State := State - [rvstDrawHover];
  698.   LastJumpMovedAbove := -1;
  699.   LastJumpDowned     := -1;
  700.   LastRVDataMovedAbove := nil;
  701. end;
  702. {------------------------------------------------------------------------------}
  703. procedure TCustomRVFormattedData.ClearJumps;
  704. var i: Integer;
  705. begin
  706.   if Jumps<>nil then begin
  707.     for i:=0 to Jumps.Count-1 do
  708.       TObject(Jumps[i]).Free;
  709.     Jumps.Clear;
  710.     ClearLastJump;
  711.   end;
  712. end;
  713. {------------------------------------------------------------------------------}
  714. procedure TCustomRVFormattedData.ClearTemporal;
  715. var i: Integer;
  716. begin
  717.   if DrawItems<>nil then begin
  718.     for i:=0 to DrawItems.Count-1 do
  719.       DrawItems[i].Free;
  720.     DrawItems.Clear;
  721.     ClearJumps;
  722.     nJmps        := 0;
  723.     FActiveItem  := nil;
  724.     //FPartialSelectedItem := nil;
  725.     FCaptureMouseItem := nil;
  726.     LastDIMovedAbove := -1;
  727.     LastRVDataMovedAbove := nil;
  728.     State := State - [ rvstMakingSelection, rvstLineSelection, rvstDrawHover];
  729.     LastRaisedCP := nil;
  730.     FClickedDrawItemNo := -1;
  731.     FSelectingInfo.Free;
  732.     FSelectingInfo := nil;
  733.     LastItemFormatted := -1;
  734.     DocumentHeight := GetTopMargin+GetBottomMargin;
  735.   end;
  736. end;
  737. {------------------------------------------------------------------------------}
  738. procedure TCustomRVFormattedData.Clear;
  739. var Clearing: Boolean;
  740. begin
  741.   Clearing := rvstClearing in State;
  742.   Include(State, rvstClearing);
  743.   try
  744.     ClearSoftPageBreaks;
  745.     Deselect(nil, True);
  746.     ClearTemporal;
  747.     inherited Clear;
  748.   finally
  749.     if not Clearing then
  750.       Exclude(State, rvstClearing);
  751.   end;
  752. end;
  753. {------------------------------------------------------------------------------}
  754. procedure TCustomRVFormattedData.Deselect(NewPartiallySelected: TCustomRVItemInfo;
  755.                                           MakeEvent: Boolean);
  756. begin
  757.   if rvstDeselecting in State then
  758.     exit;
  759.   State := State + [rvstDeselecting];
  760.   try
  761.     State := State - [rvstMakingSelection, rvstLineSelection];
  762.     FSelStartNo   := -1;
  763.     FSelEndNo     := -1;
  764.     FSelStartOffs := 0;
  765.     FSelEndOffs   := 0;
  766.     if (FocusedItemNo>=0) and (FocusedItemNo<ItemCount) then
  767.       GetItem(FocusedItemNo).ClearFocus;
  768.     FocusedItemNo := -1;
  769.     DeselectPartiallySelectedItem(NewPartiallySelected);
  770.     if MakeEvent then
  771.       DoSelect;
  772.   finally
  773.     State := State - [rvstDeselecting];
  774.   end;
  775. end;
  776. {------------------------------------------------------------------------------}
  777. procedure TCustomRVFormattedData.SelectAll;
  778. begin
  779.   if Items.Count=0 then
  780.     exit;
  781.   {$IFNDEF RVDONOTUSELIVESPELL}
  782.   LiveSpellingCheckCurrentItem;
  783.   {$ENDIF}    
  784.   DestroyInplaceEditor;
  785.   DeselectPartiallySelectedItem(nil);
  786.   FSelStartNo   := 0;
  787.   FSelEndNo     := DrawItems.Count-1;
  788.   FSelStartOffs := GetOffsBeforeDrawItem(0);
  789.   FSelEndOffs   := GetOffsAfterDrawItem(FSelEndNo);
  790.   DoOnSelection(False);
  791.   DoSelect;
  792. end;
  793. procedure TCustomRVFormattedData.ConcateItems(FirstItemNo: Integer);
  794. var item1,item2: TCustomRVItemInfo;
  795. begin
  796.   item1 := TCustomRVItemInfo(Items.Objects[FirstItemNo]);
  797.   item2 := TCustomRVItemInfo(Items.Objects[FirstItemNo+1]);
  798.   if ((rvioUnicode in item1.ItemOptions)<>
  799.      (rvioUnicode in item2.ItemOptions)) and
  800.      (Items[FirstItemNo+1]<>'') then begin
  801.     item2.SameAsPrev := item1.SameAsPrev;
  802.     item2.BR := item1.BR;
  803.     FreeItem(FirstItemNo, False);
  804.     Items.Delete(FirstItemNo);
  805.     end
  806.   else begin
  807.     Items[FirstItemNo] := Items[FirstItemNo]+Items[FirstItemNo+1];
  808.     FreeItem(FirstItemNo+1, False);
  809.     Items.Delete(FirstItemNo+1);
  810.   end;
  811. end;
  812. {------------------------------------------------------------------------------}
  813. procedure TCustomRVFormattedData.Normalize;
  814. var li, li2: TCustomRVItemInfo;
  815.     i: Integer;
  816. begin
  817.   for i := Items.Count-1 downto 1 do begin
  818.     li := TCustomRVItemInfo(Items.Objects[i-1]);
  819.     li2 := TCustomRVItemInfo(Items.Objects[i]);
  820.     if RV_CanConcateItems(i-1, li,li2,False) then
  821.       ConcateItems(i-1);
  822.   end;
  823. end;
  824. {------------------------------------------------------------------------------}
  825. function TCustomRVFormattedData.GetOffsBeforeDrawItem(DrawItemNo: Integer): Integer;
  826. begin
  827.   if GetDrawItemStyle(DrawItemNo)<0 then
  828.     Result := 0
  829.   else
  830.     Result := 1;
  831. end;
  832. {------------------------------------------------------------------------------}
  833. function TCustomRVFormattedData.GetOffsAfterDrawItem(DrawItemNo: Integer): Integer;
  834. begin
  835.   if GetDrawItemStyle(DrawItemNo)<0 then
  836.     Result := 1
  837.   else
  838.     Result := DrawItems[DrawItemNo].Length+1;
  839. end;
  840. {------------------------------------------------------------------------------}
  841. procedure TCustomRVFormattedData.FinishScreenLine(const sad: TRVScreenAndDevice;
  842.   LineWidth, LastDrawItem: Integer; parafinished: Boolean;
  843.   var ExtraSpace: Integer; var dontdoit: Boolean; Canvas: TCanvas);
  844. var  pi: TParaInfo;
  845.      BiDiMode: TRVBiDiMode;
  846.      Alignment: TRVAlignment;
  847.   {.......................................................}
  848.   function  GetDevY(ScreenY: Integer): Integer;
  849.   begin
  850.     Result := MulDiv(ScreenY, sad.ppiyDevice, sad.ppiyScreen);
  851.   end;
  852.   {.......................................................}
  853.   function  GetDevX(ScreenX: Integer): Integer;
  854.   begin
  855.     Result := MulDiv(ScreenX, sad.ppixDevice, sad.ppixScreen);
  856.   end;
  857.   {.......................................................}
  858.   procedure RearrangeMarker(FirstDrawItem, LastDrawItem: Integer);
  859.   var extrax, i: Integer;
  860.   begin
  861.     if not GetItem(DrawItems[FirstDrawItem].ItemNo).SameAsPrev and
  862.        (DrawItems[FirstDrawItem].Offs<=GetOffsBeforeItem(DrawItems[FirstDrawItem].ItemNo)) then begin
  863.        {$IFNDEF RVDONOTUSELISTS}
  864.        if (GetItemStyle(DrawItems[FirstDrawItem].ItemNo)=rvsListMarker) then begin
  865.          extrax := GetDevX(-TRVMarkerItemInfo(GetItem(DrawItems[FirstDrawItem].ItemNo)).GetLeftOverhang);
  866.          end
  867.        else
  868.        {$ENDIF}
  869.        begin
  870.          extrax := GetDevX(pi.FirstIndent);
  871.        end;
  872.       if extrax<>0 then
  873.         for i := FirstDrawItem to LastDrawItem do
  874.           dec(DrawItems[i].Left, extrax);
  875.     end;
  876.   end;
  877.   {.......................................................}
  878.   function GetDrawItemBiDi(DrawItemNo: Integer; var Start, Ending: TRVBiDiMode): Boolean;
  879.   var item: TCustomRVItemInfo;
  880.       Locale: Cardinal;
  881.       Len: Integer;
  882.       s: String;
  883.       CharTypes: PWordArray;
  884.   begin
  885.     Start  := BiDiMode;
  886.     Ending := BiDiMode;
  887.     Result := True;
  888.     item := GetItem(DrawItems[DrawItemNo].ItemNo);
  889.     if item.StyleNo<0 then
  890.       exit;
  891.     s := DrawItems.GetString(DrawItemNo, Items);
  892.     if s='' then
  893.       exit;
  894.     {$IFNDEF RVDONOTUSEUNICODE}
  895.     if GetRVStyle.TextStyles[GetActualStyle(item)].Unicode then
  896.       Len := Length(s) div 2
  897.     else
  898.     {$ENDIF}
  899.       Len := Length(s);
  900.     Locale := GetStyleLocale(GetActualStyle(item));
  901.     if GetRVStyle.TextStyles[GetActualStyle(item)].BiDiMode<>rvbdUnspecified then begin
  902.       Start  := GetRVStyle.TextStyles[GetActualStyle(item)].BiDiMode;
  903.       Ending := GetRVStyle.TextStyles[GetActualStyle(item)].BiDiMode;
  904.     end;
  905.     GetMem(CharTypes, Len*sizeof(Word));
  906.     try
  907.       {$IFNDEF RVDONOTUSEUNICODE}
  908.       if GetRVStyle.TextStyles[GetActualStyle(item)].Unicode then
  909.         GetStringTypeExW(Locale, CT_CTYPE2, Pointer(s), Len, CharTypes^)
  910.       else
  911.       {$ENDIF}
  912.         GetStringTypeExA(Locale, CT_CTYPE2, Pointer(s), Len, CharTypes^);
  913.       case CharTypes[0] of
  914.         C2_LEFTTORIGHT:
  915.           Start := rvbdLeftToRight;
  916.         C2_RIGHTTOLEFT:
  917.           Start := rvbdRightToLeft;
  918.       end;
  919.       case CharTypes[Len-1] of
  920.         C2_LEFTTORIGHT:
  921.           Ending := rvbdLeftToRight;
  922.         C2_RIGHTTOLEFT:
  923.           Ending := rvbdRightToLeft;
  924.       end;
  925.     finally
  926.       FreeMem(CharTypes);
  927.     end;
  928.   end;
  929.   {.......................................................}
  930.   function RearrangeLineEx(LastDrawItem: Integer): Boolean;
  931.   var FirstDrawItem, i,insertpoint: Integer;
  932.       extrax, curx: Integer;
  933.       diorder: TRVIntegerList;
  934.       CurBiDi, PrevBiDi, StartBiDi, EndBiDi: TRVBiDiMode;
  935.   begin
  936.     Result := True;
  937.     if BiDiMode=rvbdUnspecified then
  938.       exit;
  939.     FirstDrawItem := LastDrawItem;
  940.     while (FirstDrawItem>0) and not DrawItems[FirstDrawItem].FromNewLine do
  941.       dec(FirstDrawItem);
  942.     if BiDiMode=rvbdRightToLeft then
  943.       RearrangeMarker(FirstDrawItem, LastDrawItem);
  944.     if FirstDrawItem=LastDrawItem then
  945.       exit;
  946.     insertpoint := 0;
  947.     diorder := TRVIntegerList.Create;
  948.     try
  949.       PrevBiDi := BiDiMode;
  950.       for i := FirstDrawItem to LastDrawItem do begin
  951.         if not GetDrawItemBiDi(i, StartBiDi, EndBiDi) then begin
  952.           diorder.Free;
  953.           Result := False;
  954.           exit;
  955.         end;
  956.         CurBiDi := BiDiMode;
  957.         if PrevBiDi=StartBiDi then
  958.           CurBiDi := PrevBiDi;
  959.         PrevBiDi := EndBiDi;
  960.         if CurBiDi=rvbdLeftToRight then begin
  961.           if insertpoint<diorder.Count then
  962.             inc(insertpoint);
  963.         end;
  964.         diorder.Insert(insertpoint, i);
  965.       end;
  966.       curx := DrawItems[FirstDrawItem].Left;
  967.       for i := 0 to diorder.Count-1 do begin
  968.         if diorder[i]>FirstDrawItem then
  969.           extrax := DrawItems[diorder[i]].Left-(DrawItems[diorder[i]-1].Left+DrawItems[diorder[i]-1].Width)
  970.         else
  971.           extrax := 0;
  972.         DrawItems[diorder[i]].Left := curx;
  973.         inc(curx, DrawItems[diorder[i]].Width+extrax);
  974.       end;
  975.     finally
  976.       diorder.Free;
  977.     end;
  978.   end;
  979.   {.......................................................}
  980.   procedure RearrangeLine(LastDrawItem: Integer);
  981.   var FirstDrawItem, i: Integer;
  982.       curx, extrax: Integer;
  983.   begin
  984.     if BiDiMode<>rvbdRightToLeft then
  985.       exit;
  986.     FirstDrawItem := LastDrawItem;
  987.     while (FirstDrawItem>0) and
  988.           not DrawItems[FirstDrawItem].FromNewLine do
  989.       dec(FirstDrawItem);
  990.     RearrangeMarker(FirstDrawItem, LastDrawItem);
  991.     if FirstDrawItem=LastDrawItem then
  992.       exit;
  993.     curx := DrawItems[FirstDrawItem].Left;
  994.     for i := LastDrawItem downto FirstDrawItem do begin
  995.       if i>FirstDrawItem then
  996.         extrax := DrawItems[i].Left-(DrawItems[i-1].Left+DrawItems[i-1].Width)
  997.       else
  998.         extrax := 0;
  999.       DrawItems[i].Left := curx;
  1000.       inc(curx, DrawItems[i].Width+extrax);
  1001.     end;
  1002.   end;
  1003.   {.......................................................}
  1004. var i, j, dx, min,max: Integer;
  1005.     fl: Boolean;
  1006.     dli: TRVDrawLineInfo;
  1007.     item: TCustomRVItemInfo;
  1008.     {$IFNDEF RVDONOTUSEJUSTIFY}
  1009.     SpaceCount, strt: Integer;
  1010.     s:  String;
  1011.     {$ENDIF}
  1012. begin
  1013.   ExtraSpace := 0;
  1014.   if dontdoit then begin
  1015.     dontdoit := False;
  1016.     exit;
  1017.   end;
  1018.   i := LastDrawItem-1;
  1019.   if i=-1 then
  1020.     exit;
  1021.   dli := DrawItems[i];
  1022.   item := GetItem(dli.ItemNo);
  1023.   if item.GetBoolValue(rvbpFullWidth) then
  1024.     exit;
  1025.   pi := GetRVStyle.ParaStyles[item.ParaNo];
  1026.   BiDiMode := GetParaBiDiMode(item.ParaNo);
  1027.   Alignment := pi.Alignment;
  1028.   if (Alignment=rvaJustify)
  1029.     {$IFNDEF RVDONOTUSEJUSTIFY}
  1030.       and (BiDiMode<>rvbdUnspecified)
  1031.     {$ENDIF}
  1032.     then
  1033.     Alignment := rvaLeft;
  1034.   if (Alignment = rvaLeft) or ((Alignment = rvaJustify) and ParaFinished) then
  1035.     dx := 0
  1036.   else begin
  1037.     dx := LineWidth - (dli.Left+dli.Width);
  1038.     if Alignment = rvaCenter then begin
  1039.       dx := dx div 2;
  1040.       if dx<0 then
  1041.         dx := 0;
  1042.     end;
  1043.   end;
  1044.   case pi.LineSpacingType of
  1045.     rvlsSpaceBetween:
  1046.       if pi.LineSpacing>=0 then
  1047.         ExtraSpace := GetDevY(pi.LineSpacing);
  1048.     rvlsPercent:
  1049.       begin
  1050.         if pi.LineSpacing>=50 then begin
  1051.           j := i;
  1052.           min := 0;
  1053.           max := 0;
  1054.           fl  := True;
  1055.           repeat
  1056.             if GetDrawItemStyle(j)>=0 then begin
  1057.               if fl or (DrawItems[j].Top<min) then
  1058.                 min := DrawItems[j].Top;
  1059.               if fl or (DrawItems[j].Top+DrawItems[j].Height>max) then
  1060.                 max := DrawItems[j].Top+DrawItems[j].Height;
  1061.               fl := False;
  1062.             end;
  1063.             dec(j);
  1064.           until (j<0) or DrawItems[j+1].FromNewLine;
  1065.           if not fl then
  1066.             ExtraSpace := (max-min)*(pi.LineSpacing-100) div 100;
  1067.         end;
  1068.       end;
  1069.   end;
  1070.   if ExtraSpace<>0 then begin
  1071.     j := i;
  1072.     repeat
  1073.       DrawItems[j].ExtraSpaceBelow := ExtraSpace;
  1074.       dec(j);
  1075.     until (j<0) or DrawItems[j+1].FromNewLine;
  1076.   end;
  1077.   {$IFNDEF RVDONOTUSEJUSTIFY}
  1078.   if (Alignment = rvaJustify) and not ParaFinished then begin
  1079.     if DrawItems[i].FromNewLine then
  1080.       exit;
  1081.     SpaceCount := 0;
  1082.     while (i>=0) and not DrawItems[i].FromNewLine and (GetDrawItemStyle(i)<>rvsTab) do
  1083.       with DrawItems[i] do begin
  1084.         if (GetItemStyle(ItemNo)>=0) then begin
  1085.           s := DrawItems.GetString(i,Items);
  1086.           if (System.Length(s)>0) and RVU_IsSpace(s, 1, GetItemOptions(ItemNo)) then
  1087.             inc(SpaceCount)
  1088.         end;
  1089.         dec(i);
  1090.       end;
  1091.     strt := i+1;
  1092.     for i := strt to LastDrawItem-1 do
  1093.       with DrawItems[i] do begin
  1094.         if (GetItemStyle(ItemNo)>=0) then begin
  1095.           s := DrawItems.GetString(i,Items);
  1096.           if (System.Length(s)>0) and RVU_IsSpace(s, 1, GetItemOptions(ItemNo)) then begin
  1097.             SpaceBefore := dx div SpaceCount;
  1098.             inc(Width,SpaceBefore);
  1099.             dec(dx,SpaceBefore);
  1100.             dec(SpaceCount);
  1101.           end;
  1102.         end;
  1103.         if not FromNewLine then
  1104.           Left := DrawItems[i-1].Left+DrawItems[i-1].Width;
  1105.       end;
  1106.     RearrangeLineEx(LastDrawItem-1);
  1107.     exit;
  1108.   end;
  1109.   {$ENDIF}
  1110.   while (i>=0) do begin
  1111.     with DrawItems[i] do begin
  1112.       inc(Left,dx);
  1113.       if FromNewLine then begin
  1114.         RearrangeLineEx(LastDrawItem-1);
  1115.         exit;
  1116.       end;
  1117.     end;
  1118.     dec(i);
  1119.   end;
  1120. end;
  1121. {------------------------------------------------------------------------------}
  1122. function TCustomRVFormattedData.GetFirstItemMarker(var ListNo, Level: Integer): Boolean;
  1123. begin
  1124.   ListNo := -1;
  1125.   Level  := -1;
  1126.   Result := False;
  1127. end;
  1128. {------------------------------------------------------------------------------}
  1129. function TCustomRVFormattedData.GetRVDataExtraVOffs: Integer;
  1130. begin
  1131.   Result := 0;
  1132. end;
  1133. {------------------------------------------------------------------------------}
  1134. procedure TCustomRVFormattedData.GetIndents(ItemNo: Integer; IsParaStart: Boolean;
  1135.   var FirstParaItemNo: Integer; var LeftIndent, RightIndent,
  1136.   PureLeftIndent: Integer);
  1137. var RVStyle: TRVStyle;
  1138.     item   : TCustomRVItemInfo;
  1139.     {$IFNDEF RVDONOTUSELISTS}
  1140.     item2  : TCustomRVItemInfo;
  1141.     bidimode: TRVBiDiMode;
  1142.     ListNo, Level: Integer;
  1143.     {$ENDIF}
  1144.     pi     : TParaInfo;
  1145. begin
  1146.   RVStyle := GetRVStyle;
  1147.   item  := GetItem(ItemNo);
  1148.   {$IFNDEF RVDONOTUSELISTS}
  1149.   bidimode := GetParaBiDiMode(item.ParaNo);
  1150.   {$ENDIF}
  1151.   pi    := RVStyle.ParaStyles[item.ParaNo];
  1152.   if (rvstFirstParaAborted in State) then begin
  1153.     if FirstParaItemNo<0 then
  1154.       FirstParaItemNo := GetFirstParaItem(ItemNo);
  1155.     if FirstParaItemNo=0 then
  1156.       IsParaStart := False;
  1157.   end;
  1158.   if IsParaStart then begin
  1159.     {$IFNDEF RVDONOTUSELISTS}
  1160.     if (item.StyleNo=rvsListMarker) and (TRVMarkerItemInfo(item).GetLevelInfo(RVStyle)<>nil) then
  1161.       if bidimode=rvbdRightToLeft then begin
  1162.         RightIndent := TRVMarkerItemInfo(item).GetLevelInfo(RVStyle).MarkerIndent;
  1163.         LeftIndent  := pi.LeftIndent;
  1164.         PureLeftIndent := LeftIndent;
  1165.         end
  1166.       else begin
  1167.         LeftIndent := TRVMarkerItemInfo(item).GetLevelInfo(RVStyle).MarkerIndent;
  1168.         RightIndent  := pi.RightIndent;
  1169.         PureLeftIndent := LeftIndent;
  1170.       end
  1171.     else begin
  1172.       if FirstParaItemNo<0 then
  1173.         FirstParaItemNo := GetFirstParaItem(ItemNo);
  1174.       item2 := GetItem(FirstParaItemNo);
  1175.       if (item2.StyleNo=rvsListMarker) and (TRVMarkerItemInfo(item2).GetLevelInfo(RVStyle)<>nil) then
  1176.         if bidimode=rvbdRightToLeft then begin
  1177.           RightIndent := TRVMarkerItemInfo(item2).GetLevelInfo(RVStyle).LeftIndent;
  1178.           LeftIndent  := pi.LeftIndent;
  1179.           PureLeftIndent := LeftIndent;
  1180.           end
  1181.         else begin
  1182.           LeftIndent := TRVMarkerItemInfo(item2).GetLevelInfo(RVStyle).LeftIndent;
  1183.           RightIndent  := pi.RightIndent;
  1184.           PureLeftIndent := LeftIndent;
  1185.         end
  1186.       else
  1187.       {$ENDIF}
  1188.       begin
  1189.         LeftIndent := pi.LeftIndent;
  1190.         PureLeftIndent := LeftIndent;
  1191.         if not item.BR and not item.GetBoolValue(rvbpFullWidth) then
  1192.            inc(LeftIndent, pi.FirstIndent);
  1193.          RightIndent := pi.RightIndent;
  1194.       end;
  1195.     {$IFNDEF RVDONOTUSELISTS}
  1196.     end;
  1197.     {$ENDIF}
  1198.     end
  1199.   else begin
  1200.     {$IFNDEF RVDONOTUSELISTS}
  1201.     if FirstParaItemNo<0 then
  1202.       FirstParaItemNo := GetFirstParaItem(ItemNo);
  1203.     item2 := GetItem(FirstParaItemNo);
  1204.     if (item2.StyleNo=rvsListMarker) and (TRVMarkerItemInfo(item2).GetLevelInfo(RVStyle)<>nil) then begin
  1205.       if bidimode=rvbdRightToLeft then begin
  1206.         RightIndent := TRVMarkerItemInfo(item2).GetLevelInfo(RVStyle).LeftIndent;
  1207.         LeftIndent  := pi.LeftIndent;
  1208.         PureLeftIndent := LeftIndent;
  1209.         end
  1210.       else begin
  1211.         LeftIndent := TRVMarkerItemInfo(item2).GetLevelInfo(RVStyle).LeftIndent;
  1212.         RightIndent  := pi.RightIndent;
  1213.         PureLeftIndent := LeftIndent;
  1214.       end
  1215.       end
  1216.     else if (FirstParaItemNo=0) and (rvstFirstParaAborted in State) and
  1217.       GetFirstItemMarker(ListNo, Level) then begin
  1218.       if bidimode=rvbdRightToLeft then begin
  1219.         RightIndent := RVGetLevelInfo(RVStyle, ListNo, Level).LeftIndent;
  1220.         LeftIndent  := pi.LeftIndent;
  1221.         PureLeftIndent := LeftIndent;
  1222.         end
  1223.       else begin
  1224.         LeftIndent := RVGetLevelInfo(RVStyle, ListNo, Level).LeftIndent;
  1225.         RightIndent  := pi.RightIndent;
  1226.         PureLeftIndent := LeftIndent;
  1227.       end
  1228.       end
  1229.     else
  1230.     {$ENDIF}
  1231.     begin
  1232.       LeftIndent := pi.LeftIndent;
  1233.       RightIndent := pi.RightIndent;
  1234.       PureLeftIndent := LeftIndent;
  1235.     end;
  1236.   end;
  1237. end;
  1238. {------------------------------------------------------------------------------}
  1239. function TCustomRVFormattedData.GetMaxIndent(ItemNo: Integer; var FirstParaItemNo: Integer): Integer;
  1240. var RVStyle: TRVStyle;
  1241.     item: TCustomRVItemInfo;
  1242.     pi     : TParaInfo;
  1243.     {$IFNDEF RVDONOTUSELISTS}
  1244.     levelinfo: TRVListLevel;
  1245.     item2   : TCustomRVItemInfo;
  1246.     bidimode: TRVBiDiMode;
  1247.     ListNo, Level: Integer;
  1248.     {$ENDIF}
  1249. begin
  1250.   RVStyle := GetRVStyle;
  1251.   item  := GetItem(ItemNo);
  1252.   {$IFNDEF RVDONOTUSELISTS}
  1253.   bidimode := GetParaBiDiMode(item.ParaNo);
  1254.   {$ENDIF}
  1255.   pi    := RVStyle.ParaStyles[item.ParaNo];
  1256.   {$IFNDEF RVDONOTUSELISTS}
  1257.   if FirstParaItemNo<0 then
  1258.     FirstParaItemNo := GetFirstParaItem(ItemNo);
  1259.   item2 := GetItem(FirstParaItemNo);
  1260.   if (item2.StyleNo=rvsListMarker) and (TRVMarkerItemInfo(item2).GetLevelInfo(RVStyle)<>nil) then
  1261.     levelinfo := TRVMarkerItemInfo(item2).GetLevelInfo(RVStyle)
  1262.   else if (FirstParaItemNo=0) and (rvstFirstParaAborted in State) and GetFirstItemMarker(ListNo, Level) then
  1263.     levelinfo := RVGetLevelInfo(RVStyle, ListNo, Level)
  1264.   else
  1265.     levelinfo := nil;
  1266.   if levelinfo<>nil then begin
  1267.     Result := levelinfo.LeftIndent;
  1268.     if levelinfo.FirstIndent>0 then
  1269.       inc(Result,levelinfo.FirstIndent);
  1270.     if bidimode=rvbdRightToLeft then
  1271.       inc(Result, pi.LeftIndent)
  1272.     else
  1273.       inc(Result, pi.RightIndent);
  1274.     end
  1275.   else
  1276.   {$ENDIF}
  1277.   begin
  1278.     Result := pi.LeftIndent+pi.RightIndent;
  1279.     if (pi.FirstIndent>0) and not item.GetBoolValue(rvbpFullWidth) then
  1280.       inc(Result,pi.FirstIndent);
  1281.   end;
  1282. end;
  1283. {------------------------------------------------------------------------------}
  1284. procedure TCustomRVFormattedData.UpdateLastTab(var Params: TRVFormatParams);
  1285. var FreeSpace, i, XShift: Integer;
  1286.     LastDrawItem, TabDrawItem: TRVDrawLineInfo;
  1287. begin
  1288.   if Params.LastTabDrawItemNo<0 then
  1289.     exit;
  1290.   LastDrawItem := DrawItems[Params.LastDrawItem-1];
  1291.   TabDrawItem  := DrawItems[Params.LastTabDrawItemNo];
  1292.   XShift := Params.x - (LastDrawItem.Left+LastDrawItem.Width);
  1293.   if Params.LastTabPosition>Params.LineWidth+Params.FirstIndent then
  1294.     Params.LastTabPosition := Params.LineWidth+Params.FirstIndent;
  1295.   case Params.LastTabAlign of
  1296.     rvtaRight:
  1297.       begin
  1298.         FreeSpace := Params.LastTabPosition-(LastDrawItem.Left+LastDrawItem.Width);
  1299.       end;
  1300.     rvtaCenter:
  1301.       begin
  1302.         FreeSpace := Params.LastTabPosition+
  1303.           (Params.LastTabPosition-TabDrawItem.Left-TabDrawItem.Width)-
  1304.           (LastDrawItem.Left+LastDrawItem.Width);
  1305.         FreeSpace := FreeSpace div 2;
  1306.       end;
  1307.     else
  1308.       FreeSpace := 0;
  1309.   end;
  1310.   if FreeSpace<0 then
  1311.     FreeSpace := 0;
  1312.   if FreeSpace>=0 then
  1313.     inc(TabDrawItem.Width, FreeSpace);
  1314.   if FreeSpace>=0 then begin
  1315.     for i := Params.LastTabDrawItemNo+1 to Params.LastDrawItem-1 do
  1316.       inc(DrawItems[i].Left, FreeSpace);
  1317.     Params.x := LastDrawItem.Left+LastDrawItem.Width+XShift;
  1318.   end;
  1319.   Params.LastTabDrawItemNo := -1;
  1320. end;
  1321. {------------------------------------------------------------------------------}
  1322. procedure TCustomRVFormattedData.FormatLine(const Text, OrigText: String;
  1323.   StartOffs, Len, ItemNo: Integer; Canvas: TCanvas; var sad: TRVScreenAndDevice;
  1324.   var Params: TRVFormatParams);
  1325. var sourceStrPtr,OrigSourceStrPtr, sourceStrPtr2, strForAdd, strSpacePos: PChar;
  1326.     sourceStrPtrLen: Integer;
  1327.     sz: TSIZE;
  1328.     max,max2,j, y: Integer;
  1329.     dli: TRVDrawLineInfo;
  1330.     newline, AtStart:Boolean;
  1331.     jmpinfo: TRVJumpInfo;
  1332.     y5, Offs, ActualStyleNo: Integer;
  1333.     pi: TParaInfo;
  1334.     SpaceAfter, ExternalLeading, ExtraSpaceBelowLine: Integer;
  1335.     li: TCustomRVItemInfo;
  1336.     RVStyle: TRVStyle;
  1337.     {$IFNDEF RVDONOTUSEUNICODE}
  1338.     IsUnicodeItem: Boolean;
  1339.     {$ENDIF}
  1340.   {.......................................................}
  1341.   function  GetDevX(ScreenX: Integer): Integer;
  1342.   begin
  1343.     Result := MulDiv(ScreenX, sad.ppixDevice, sad.ppixScreen);
  1344.   end;
  1345.   {.......................................................}
  1346.   function  GetDevY(ScreenY: Integer): Integer;
  1347.   begin
  1348.     Result := MulDiv(ScreenY, sad.ppiyDevice, sad.ppiyScreen);
  1349.   end;
  1350.   {.......................................................}
  1351.   {$IFNDEF RVDONOTUSEUNICODE}
  1352.   function AdjustMaxFitR(value: Integer): Integer;
  1353.   var PStart, PCur, PCur2: PChar;
  1354.   begin
  1355.      Result := value;
  1356.      PStart := sourceStrPtr;
  1357.      // we cannot use CharNextW() because string does not have WideChar(0) at the end
  1358.      while True do begin
  1359.        if (Result=0) or (Result=sourceStrPtrLen) then
  1360.          exit;
  1361.        PCur := PStart + (Result+1)*2;
  1362.        PCur2 := PChar(CharPrevW(Pointer(PStart), Pointer(PCur)));
  1363.        if PCur2=PStart+(Result)*2 then
  1364.          exit;
  1365.        inc(Result);
  1366.      end;
  1367.   end;
  1368.   {.......................................................}
  1369.   function AdjustMaxFitL(value: Integer): Integer;
  1370.   var PStart, PCur, PCur2: PChar;
  1371.   begin
  1372.      Result := value;
  1373.      RVU_GetTextExtentPoint32W(Params.FormatCanvas, Pointer(sourceStrPtr), Result, sz);
  1374.      if sz.cx<=SpaceAfter then
  1375.        exit;
  1376.      PStart := sourceStrPtr;
  1377.      PCur := PStart + (Result-1)*2;
  1378.      PCur2 := PChar(CharPrevW(Pointer(PStart), Pointer(PCur)));
  1379.      Result := (PCur2-PStart) div 2;
  1380.   end;
  1381.   {$ENDIF}
  1382.   function MaxFitSafe: Integer; // out: sz
  1383.   {$IFNDEF RVDONOTUSEUNICODE}
  1384.   var r: Integer;
  1385.   {$ENDIF}
  1386.   begin
  1387.     if (rvpaoNoWrap in pi.Options) then
  1388.       Result := sourceStrPtrLen
  1389.     else begin
  1390.       {$IFDEF RVDONOTUSEUNICODE}
  1391.       RVU_GetTextExtentExPointPC(Params.FormatCanvas, OrigSourceStrPtr, sourceStrPtrLen,
  1392.         SpaceAfter, Result, nil, li.ItemOptions, sz);
  1393.       {$ELSE}
  1394.       RVU_GetTextExtentExPointPC(Params.FormatCanvas, OrigSourceStrPtr, sourceStrPtrLen,
  1395.         SpaceAfter, Result, nil, li.ItemOptions, sz);
  1396.       if IsUnicodeItem then begin
  1397.         {$IFNDEF RVDONOTUSESOFTHYPHENS}
  1398.         if (Result>0) and
  1399.           (PRVWordArray(OrigSourceStrPtr)[Result-1]=UNI_SOFT_HYPHEN) and
  1400.           (PRVWordArray(SourceStrPtr)[Result-1]=UNI_ZERO_WIDTH_SPACE) then begin
  1401.           inc(sz.cx, Params.FontInfoCache[ActualStyleNo].HyphenWidth);
  1402.           if sz.cx>SpaceAfter then
  1403.             dec(Result);
  1404.         end;
  1405.         // we do not allow to break just before the soft hyphen
  1406.         if (Result>0) and (Result<sourceStrPtrLen) and
  1407.            (PRVWordArray(OrigSourceStrPtr)[Result]=UNI_SOFT_HYPHEN) then
  1408.           dec(Result);
  1409.         {$ENDIF}
  1410.       end;
  1411.       if IsUnicodeItem and RVNT then begin
  1412.         r := Result;
  1413.         Result := AdjustMaxFitR(r);
  1414.       end;
  1415.       {$ENDIF}
  1416.     end;
  1417.   end;
  1418.   {.......................................................}
  1419.   function MaxFitA: Integer; // out: sz
  1420.   var maxlo, maxhi, cxlo, cxhi : Integer;
  1421.   begin
  1422.     if RichViewSafeFormatting or (not RVNT and (rvflPrinting in Flags)) then begin
  1423.       Result := MaxFitSafe;
  1424.       exit;
  1425.     end;
  1426.     { First, find the length of the whole string }
  1427.     GetTextExtentPoint32(Params.FormatCanvasHandle, sourceStrPtr, sourceStrPtrLen, sz);
  1428.     if (rvpaoNoWrap in pi.Options) or ((sz.cx <= SpaceAfter) and (sz.cx>=0)) then
  1429.       { it will fit on the line }
  1430.       Result := sourceStrPtrLen
  1431.     else begin
  1432.       maxlo := 0;
  1433.       maxhi := sourceStrPtrLen;
  1434.       cxlo := 0;
  1435.       cxhi := sz.cx;
  1436.       while maxhi > (maxlo + 1) do begin
  1437.         { make the best estimate of where max should be }
  1438.         if cxhi=cxlo then
  1439.           inc(cxhi);
  1440.         Result := maxlo + (maxhi - maxlo) * (SpaceAfter - cxlo) div (cxhi - cxlo);
  1441.         if Result <= maxlo then
  1442.           Result := maxlo + 1;
  1443.         if Result >= maxhi then
  1444.           Result := maxhi - 1;
  1445.         GetTextExtentPoint32(Params.FormatCanvasHandle,sourceStrPtr,Result,sz);
  1446.         { if sz.cx = SpaceAfter then max is correct }
  1447.         if sz.cx = SpaceAfter then begin
  1448.           maxlo := Result;
  1449.           maxhi := Result;
  1450.           end
  1451.         else if (sz.cx < SpaceAfter) and (sz.cx>0) then begin
  1452.           maxlo := Result;
  1453.           cxlo := sz.cx;
  1454.           end
  1455.         else { sz.cx > SpaceAfter } begin
  1456.           maxhi := Result;
  1457.           cxhi := sz.cx;
  1458.         end;
  1459.       end;
  1460.       Result := maxlo;
  1461.     end
  1462.   end;
  1463.   {.......................................................}
  1464.   {$IFNDEF RVDONOTUSEUNICODE}
  1465.   function MaxFitW: Integer; // out: sz
  1466.   var maxlo, maxhi, cxlo, cxhi : Integer;
  1467.       {$IFNDEF RVDONOTUSESOFTHYPHENS}
  1468.       HyphenWidth: Integer;
  1469.       {$ENDIF}
  1470.   begin
  1471.     if RichViewSafeFormatting or ({not RVNT and }(rvflPrinting in Flags)) then begin
  1472.       Result := MaxFitSafe;
  1473.       exit;
  1474.     end;
  1475.     {$IFNDEF RVDONOTUSESOFTHYPHENS}
  1476.     HyphenWidth := 0;
  1477.     {$ENDIF}
  1478.     { First, find the length of the whole string }
  1479.     RVU_GetTextExtentPoint32W(Params.FormatCanvas, Pointer(sourceStrPtr), sourceStrPtrLen, sz);
  1480.     if (rvpaoNoWrap in pi.Options) or ((sz.cx <= SpaceAfter) and (sz.cx>=0)) then
  1481.       { it will fit on the line }
  1482.       Result := sourceStrPtrLen
  1483.     else begin
  1484.       maxlo := 0;
  1485.       maxhi := sourceStrPtrLen;
  1486.       cxlo := 0;
  1487.       cxhi := sz.cx;
  1488.       while maxhi > (maxlo + 1) do begin
  1489.         { make the best estimate of where max should be }
  1490.         if cxhi=cxlo then
  1491.           inc(cxhi);
  1492.         Result := maxlo + (maxhi - maxlo) * (SpaceAfter - cxlo) div (cxhi - cxlo);
  1493.         if Result <= maxlo then
  1494.           Result := maxlo + 1;
  1495.         if Result >= maxhi then
  1496.           Result := maxhi - 1;
  1497.         RVU_GetTextExtentPoint32W(Params.FormatCanvas, Pointer(sourceStrPtr), Result, sz);
  1498.         {$IFNDEF RVDONOTUSESOFTHYPHENS}
  1499.         if (PRVWordArray(OrigSourceStrPtr)[Result-1]=UNI_SOFT_HYPHEN) and
  1500.            (PRVWordArray(SourceStrPtr)[Result-1]=UNI_ZERO_WIDTH_SPACE) then begin
  1501.           if HyphenWidth=0 then
  1502.             HyphenWidth := Params.FontInfoCache[ActualStyleNo].HyphenWidth;
  1503.           inc(sz.cx,HyphenWidth);
  1504.         end;
  1505.         {$ENDIF}
  1506.         { if sz.cx = SpaceAfter then max is correct }
  1507.         if sz.cx = SpaceAfter then begin
  1508.           maxlo := Result;
  1509.           maxhi := Result;
  1510.           end
  1511.         else if (sz.cx < SpaceAfter) and (sz.cx>0)  then begin
  1512.           maxlo := Result;
  1513.           cxlo := sz.cx;
  1514.           end
  1515.         else { sz.cx > SpaceAfter } begin
  1516.           maxhi := Result;
  1517.           cxhi := sz.cx;
  1518.         end;
  1519.       end;
  1520.       {$IFNDEF RVDONOTUSESOFTHYPHENS}
  1521.       // we do not allow to break just before the soft hyphen
  1522.       if (maxlo>0) and (maxlo<sourceStrPtrLen) and
  1523.          (PRVWordArray(OrigSourceStrPtr)[maxlo]=UNI_SOFT_HYPHEN) then
  1524.         dec(maxlo);
  1525.       {$ENDIF}
  1526.       // Adjusting combined characters
  1527.       if RVNT then begin
  1528.         Result := AdjustMaxFitR(maxlo);
  1529.         if Result<>maxlo then
  1530.           Result := AdjustMaxFitL(Result);
  1531.         end
  1532.       else
  1533.         Result := maxlo;
  1534.     end
  1535.   end;
  1536.   {$ENDIF}
  1537.   {.......................................................}
  1538.   procedure OnStartNewLine(li: TCustomRVItemInfo; wrapping: Boolean);
  1539.   var dli: TRVDrawLineInfo;
  1540.       SpaceAtEnd: Boolean;
  1541.       StyleNo: Integer;
  1542.       LeftIndent: Integer;
  1543.   begin
  1544.      if not Params.SpaceEaten and wrapping and (Params.LastDrawItem>0) then begin
  1545.        dli := DrawItems[Params.LastDrawItem-1];
  1546.        StyleNo := GetItemStyle(dli.ItemNo);
  1547.        if StyleNo>=0 then begin
  1548.         {$IFNDEF RVDONOTUSEUNICODE}
  1549.         if rvioUnicode in GetItemOptions(dli.ItemNo) then
  1550.           SpaceAtEnd := (dli.Length>0) and
  1551.             (PWord(PChar(Items[dli.ItemNo])+(dli.Offs+dli.Length-2)*2)^=ord(' '))
  1552.         else
  1553.         {$ENDIF}
  1554.           SpaceAtEnd := (dli.Length>0) and
  1555.             (Items[dli.ItemNo][dli.Offs+dli.Length-1]=' ');
  1556.          if SpaceAtEnd and not IsDrawItemFromNewLine(Params.LastDrawItem-1) then begin
  1557.            if (dli.Length=1) and (Params.LastDrawItem-2>=0) and
  1558.              (dli.ItemNo=DrawItems[Params.LastDrawItem-2].ItemNo) and
  1559.              not dli.FromNewLine then begin
  1560.              DrawItems.Delete(Params.LastDrawItem-1);
  1561.              dec(Params.LastDrawItem);
  1562.              end
  1563.            else begin
  1564.              dec(dli.Length);
  1565.              RVStyle.ApplyStyle(Params.FormatCanvas, StyleNo, GetItemBiDiMode(dli.ItemNo),
  1566.                rvflCanUseCustomPPI in Flags);
  1567.              dli.Width := RVU_TextWidth(DrawItems.GetString(Params.LastDrawItem-1, Items),
  1568.                Params.FormatCanvas, GetItemOptions(dli.ItemNo));
  1569.              if (GetItemStyle(ItemNo)>=0) and (GetItemStyle(ItemNo)<>StyleNo) then
  1570.                RVStyle.ApplyStyle(Params.FormatCanvas, GetItemStyle(ItemNo), GetItemBiDiMode(ItemNo),
  1571.                  rvflCanUseCustomPPI in Flags);
  1572.            end;
  1573.            Params.SpaceEaten := True;
  1574.          end;
  1575.        end;
  1576.      end;
  1577.      {$IFNDEF RVDONOTUSESOFTHYPHENS}
  1578.      // if the last draw item on the previous (just formed) line is finihed with
  1579.      // the soft hyphen, increasing its Width on the hyphen width
  1580.      if wrapping and (Params.LastDrawItem-1>=0) and (Params.LastDrawItem-1<DrawItems.Count) and
  1581.         (not (rvoShowSpecialCharacters in Options) or not (rvscSoftHyphen in RVVisibleSpecialCharacters))  then begin
  1582.        dli := DrawItems[Params.LastDrawItem-1];
  1583.        if (rvioUnicode in GetItemOptions(dli.ItemNo)) and (dli.Length>0) and
  1584.           (PRVWordArray(PChar(DrawItems.GetString(Params.LastDrawItem-1, Items)))[dli.Length-1]=UNI_SOFT_HYPHEN) then begin
  1585.          Params.FontInfoCache.IgnoreParaBiDiMode := True;
  1586.          inc(dli.Width, Params.FontInfoCache[GetActualStyle(GetItem(dli.ItemNo))].HyphenWidth);
  1587.          Params.FontInfoCache.IgnoreParaBiDiMode := False;
  1588.        end;
  1589.      end;
  1590.      {$ENDIF}
  1591.      UpdateLastTab(Params);
  1592.      FinishScreenLine(sad, Params.LineWidth+Params.FirstIndent,
  1593.        Params.LastDrawItem, Params.IsParaStart, ExtraSpaceBelowLine,
  1594.        Params.DontFSL, Params.FormatCanvas);
  1595.      pi := RVStyle.ParaStyles[TCustomRVItemInfo(Items.Objects[ItemNo]).ParaNo];
  1596.      GetIndents(ItemNo, Params.IsParaStart, Params.FirstParaItemNo,
  1597.        LeftIndent, Params.RightIndent, Params.LeftIndent);
  1598.      Params.LeftIndent := GetDevX(Params.LeftIndent);
  1599.      LeftIndent := GetDevX(LeftIndent);
  1600.      Params.RightIndent := GetDevX(Params.RightIndent);
  1601.      if Params.IsParaStart and not li.BR then begin
  1602.          if ItemNo>0 then
  1603.            inc(Params.prevdesc,
  1604.              GetDevY(RVStyle.ParaStyles[GetItemPara(ItemNo-1)].SpaceAfter));
  1605.          inc(Params.prevdesc,GetDevY(pi.SpaceBefore));
  1606.      end;
  1607.      if rvpaoNoWrap in pi.Options then
  1608.        Params.LineWidth := DocumentWidth - (LeftIndent+Params.RightIndent)
  1609.      else
  1610.        Params.LineWidth := TextWidth - (LeftIndent+Params.RightIndent);
  1611.      Params.FirstIndent :=  sad.LeftMargin+LeftIndent;
  1612.   end;
  1613.   {.......................................................}
  1614.   procedure AdjustLineHeight(h: Integer);
  1615.   begin
  1616.     if Params.prevabove < h then begin
  1617.       j := Params.LastDrawItem-1;
  1618.       if j>=0 then
  1619.         repeat
  1620.           inc(DrawItems[j].Top,h-Params.prevabove);
  1621.           dec(j);
  1622.         until DrawItems[j+1].FromNewLine;
  1623.       inc(Params.baseline,h-Params.prevabove);
  1624.       Params.prevabove := h;
  1625.     end;
  1626.   end;
  1627.   {.......................................................}
  1628.   procedure OnNonText(li: TRVRectItemInfo; dli: TRVDrawLineInfo);
  1629.   var above, VerticalOffs: Integer;
  1630.       w,h,desc,hshift: Integer;
  1631.       TabLeader: String;
  1632.       TabAlign: TRVTabAlign;
  1633.       TabPos: Integer;
  1634.   begin
  1635.     hshift := 0;
  1636.     li.OnDocWidthChange(TextWidth - GetDevX(pi.LeftIndent+pi.RightIndent+pi.FirstIndent),
  1637.       dli, rvflPrinting in Flags, Canvas, Self, @sad, hshift, desc, Params.NoCaching,
  1638.       Params.Reformatting);
  1639.     if li.GetBoolValue(rvbpDrawingChangesFont) then
  1640.       Params.LastTextStyle := -1;
  1641.     if li.GetBoolValueEx(rvbpActualPrintSize, RVStyle) then begin
  1642.       w := dli.Width;
  1643.       h := dli.Height;
  1644.       end
  1645.     else begin
  1646.       w := GetDevX(li.Width);
  1647.       h := GetDevY(li.Height);
  1648.       desc := GetDevY(desc);
  1649.     end;
  1650.     if li.StyleNo=rvsTab then begin
  1651.       UpdateLastTab(Params);
  1652.       RVStyle.GetNextTab(li.ParaNo, Params.x+Params.FirstIndent, sad, TabPos,
  1653.         TabLeader, TabAlign, GetBiDiMode, Params.LeftIndent, Params.RightIndent);
  1654.       w := TabPos-(Params.x+Params.FirstIndent);
  1655.       if Params.x+w<=Params.LineWidth then
  1656.         case TabAlign of
  1657.           rvtaRight:
  1658.             w := 0;
  1659.           rvtaCenter:
  1660.             begin
  1661.               w := w-(Params.LineWidth+Params.FirstIndent-TabPos);
  1662.               if w<0 then
  1663.                 w := 0;
  1664.             end;
  1665.         end;
  1666.       dli.Width := w;
  1667.     end;
  1668.     if li.AssociatedTextStyleNo>=0 then
  1669.       VerticalOffs := MulDiv(h, RVStyle.TextStyles[li.AssociatedTextStyleNo].VShift, 100)
  1670.     else
  1671.       if li.VShiftAbs then
  1672.         VerticalOffs := GetDevY(li.VShift)
  1673.       else
  1674.         VerticalOffs := MulDiv(h,li.VShift,100);
  1675.     dli.SetSize(w, h);
  1676.     if not li.SameAsPrev or
  1677.       ((dli is TRVMultiDrawItemInfo)
  1678.       )
  1679.        or
  1680.       (
  1681.         (Params.x+w > Params.LineWidth) and
  1682.         not (rvpaoNoWrap in pi.Options)
  1683.         {$IFNDEF RVDONOTUSELISTS}
  1684.         and not ((ItemNo>0) and (GetItemStyle(ItemNo-1)=rvsListMarker))
  1685.         {$ENDIF}
  1686.       ) then begin
  1687.       if li.SameAsPrev then
  1688.         Params.IsParaStart := False;
  1689.       OnStartNewLine(li, li.SameAsPrev);
  1690.       dli.FromNewLine := True;
  1691.       Params.x :=0;
  1692.       inc(Params.baseline, ExtraSpaceBelowLine);
  1693.       y := Params.baseline + Params.prevdesc;
  1694.       case li.VAlign of
  1695.         rvvaBaseline:
  1696.           Params.prevabove := h-desc;
  1697.         else {rvvaMiddle:}
  1698.           Params.prevabove := h div 2;
  1699.       end;
  1700.       inc(Params.prevabove, VerticalOffs);
  1701.       inc (Params.baseline,Params.prevdesc+Params.prevabove);
  1702.       Params.prevdesc :=h-Params.prevabove;
  1703.       end
  1704.     else begin
  1705.       pi := RVStyle.ParaStyles[li.ParaNo];
  1706.       case li.VAlign of
  1707.         rvvaBaseline:
  1708.           above := h-desc;
  1709.         else {rvvaMiddle:}
  1710.           above := h div 2;
  1711.       end;
  1712.       AdjustLineHeight(above+VerticalOffs);
  1713.       y := Params.baseline - above-VerticalOffs;
  1714.       if Params.prevdesc < (h-above-VerticalOffs) then
  1715.         Params.prevdesc := (h-above-VerticalOffs);
  1716.       dli.FromNewLine := False;
  1717.     end;
  1718.     dli.Left := Params.x+Params.FirstIndent+hshift;
  1719.     if li.StyleNo=rvsTab then begin
  1720.       RVStyle.GetNextTab(li.ParaNo, dli.Left, sad, TabPos, TabLeader, TabAlign,
  1721.         GetBiDiMode, Params.LeftIndent, Params.RightIndent);
  1722.       TRVTabItemInfo(li).Leader := TabLeader;
  1723.       w := TabPos-dli.Left;
  1724.       case TabAlign of
  1725.         rvtaRight:
  1726.           begin
  1727.             w := 0;
  1728.             Params.LastTabDrawItemNo := Params.LastDrawItem;
  1729.             Params.LastTabAlign := TabAlign;
  1730.             Params.LastTabPosition := TabPos;
  1731.           end;
  1732.         rvtaCenter:
  1733.           begin
  1734.             w := w-(Params.LineWidth+Params.FirstIndent-TabPos);
  1735.             if w<0 then
  1736.               w := 0;
  1737.             Params.LastTabDrawItemNo := Params.LastDrawItem;
  1738.             Params.LastTabAlign := TabAlign;
  1739.             Params.LastTabPosition := TabPos;
  1740.           end;
  1741.       end;
  1742.       dli.Width := w;
  1743.     end;
  1744.     inc(Params.x, w+hshift);
  1745.     dli.Top :=  y;
  1746.     dli.ItemNo := ItemNo;
  1747.     dli.SetSize(w, h);
  1748.     dli.Offs := 0;
  1749.     dli.Length := 0;
  1750.     if not ShareItems then
  1751.       li.DrawItemNo := Params.LastDrawItem;
  1752.     DrawItems.Insert(Params.LastDrawItem, dli);
  1753.     if rvflUseJumps in Flags then
  1754.       li.BuildJumps(dli.Left, dli.Top, nJmps, jumps);
  1755.     //AdjustCP(li);
  1756.     inc(Params.LastDrawItem);
  1757.   end;
  1758.   {.......................................................}
  1759. var HShift, Desc: Integer;
  1760. begin
  1761.   HShift := 0;
  1762.   Desc   := 0;
  1763.   RVStyle := GetRVStyle;
  1764.   li := GetItem(ItemNo);
  1765.   pi := RVStyle.ParaStyles[li.ParaNo];
  1766.   if (not li.SameAsPrev) and (StartOffs=0) then begin
  1767.     Params.IsParaStart := True;
  1768.     Params.SpaceEaten := False;
  1769.   end;
  1770.   {
  1771.   if LineWidth<0 then
  1772.     OnStartNewLine(not li.BR, li);
  1773.   }
  1774.   if li.StyleNo<0 then begin
  1775.     if li is TRVRectItemInfo then begin
  1776.       // rvsComponent, rvsHotspot, rvsBullet, rvsPicture:
  1777.       if rvflAllowCustomDrawItems in Flags then
  1778.         dli := li.CreatePrintingDrawItem(Self,sad)
  1779.       else
  1780.         dli := TRVDrawLineInfo.Create;
  1781.       OnNonText(TRVRectItemInfo(li), dli);
  1782.       if li.GetBoolValue(rvbpDrawingChangesFont) then
  1783.         Params.LastTextStyle := -1;
  1784.       if li.GetBoolValueEx(rvbpJump, RVStyle) then begin
  1785.         if rvflUseJumps in Flags then begin
  1786.           jmpinfo     := TRVJumpInfo.Create;
  1787.           jmpinfo.w   := dli.Width;
  1788.           jmpinfo.h   := dli.Height;
  1789.           jmpinfo.id  := nJmps;
  1790.           jmpinfo.DrawItemNo := Params.LastDrawItem-1;
  1791.           jmpinfo.Cursor := li.GetHypertextCursor(RVStyle);
  1792.           jmpinfo.RVData := Self;
  1793.           jumps.Add(jmpinfo);
  1794.         end;
  1795.         TCustomRVItemInfo(Items.Objects[ItemNo]).JumpID := nJmps;
  1796.         inc(nJmps);
  1797.       end;
  1798.       end
  1799.     else begin
  1800.       UpdateLastTab(Params);
  1801.       FinishScreenLine(sad, Params.LineWidth+Params.FirstIndent,Params.LastDrawItem,
  1802.         True, ExtraSpaceBelowLine, Params.DontFSL, Params.FormatCanvas);
  1803.       if ItemNo>0 then
  1804.         inc(Params.prevdesc,GetDevY(RVStyle.ParaStyles[GetItemPara(ItemNo-1)].SpaceAfter));
  1805.       inc(Params.prevdesc, GetDevY(RVStyle.ParaStyles[GetItemPara(ItemNo)].SpaceBefore));
  1806.       if li.StyleNo=rvsBreak then begin
  1807.         inc(Params.prevdesc, GetDevY(RVStyle.ParaStyles[0].SpaceBefore));
  1808.         y5  := MulDiv(5, sad.ppiyDevice, sad.ppiyScreen);
  1809.         dli := TRVDrawLineInfo.CreateEx(sad.LeftMargin,
  1810.           Params.baseline + Params.prevdesc, TextWidth, y5+y5+1, ItemNo, True);
  1811.         end
  1812.       else begin
  1813.         Params.LineWidth := TextWidth - GetDevX(pi.LeftIndent+pi.RightIndent);
  1814.         y5 := sad.LeftMargin+GetDevX(pi.LeftIndent); //  y5 <- left
  1815.         if rvflAllowCustomDrawItems in Flags then
  1816.           dli := li.CreatePrintingDrawItem(Self,sad)
  1817.         else
  1818.           dli := TRVDrawLineInfo.Create;
  1819.         li.OnDocWidthChange(Params.LineWidth, dli, rvflPrinting in Flags,
  1820.           Params.FormatCanvas, Self, @sad, HShift, Desc, Params.NoCaching, Params.Reformatting);
  1821.         if li.GetBoolValue(rvbpDrawingChangesFont) then
  1822.           Params.LastTextStyle := -1;
  1823.         dli.SetSize(GetDevX(TRVFullLineItemInfo(li).Width),
  1824.                     GetDevY(TRVFullLineItemInfo(li).Height));
  1825.         case pi.Alignment of
  1826.           rvaRight:
  1827.             inc(y5, Params.LineWidth-dli.Width);
  1828.           rvaCenter:
  1829.             begin
  1830.               inc(y5, (Params.LineWidth-dli.Width) div 2);
  1831.               if y5<0 then y5 := 0;
  1832.             end;
  1833.         end;
  1834.         dli.SetData(y5+HShift, Params.baseline + Params.prevdesc, ItemNo,True);
  1835.       end;
  1836.       if not ShareItems then
  1837.         li.DrawItemNo := Params.LastDrawItem;
  1838.       DrawItems.Insert(Params.LastDrawItem, dli);
  1839.       if rvflUseJumps in Flags then
  1840.         li.BuildJumps(dli.Left, dli.Top, nJmps, jumps);
  1841.       //AdjustCP(li);
  1842.       inc(Params.LastDrawItem);
  1843.       if li.StyleNo=rvsBreak then begin
  1844.         inc (Params.baseline,Params.prevdesc+y5+1);
  1845.         Params.prevdesc  := y5;
  1846.         Params.prevabove := y5;
  1847.         end
  1848.       else begin
  1849.         inc (Params.baseline,Params.prevdesc+dli.Height);
  1850.         Params.prevabove := dli.Height;
  1851.         Params.prevdesc  := 0;
  1852.       end;
  1853.       end
  1854.       end
  1855.   else begin // text
  1856.      {$IFNDEF RVDONOTUSEUNICODE}
  1857.      IsUnicodeItem := rvioUnicode in li.ItemOptions;
  1858.      if IsUnicodeItem then begin
  1859.        sourceStrPtr := PChar(Text)+StartOffs*2;
  1860.        OrigSourceStrPtr := PChar(OrigText)++StartOffs*2;
  1861.        end
  1862.      else
  1863.      {$ENDIF}
  1864.      begin
  1865.        sourceStrPtr := PChar(Text)+StartOffs;
  1866.        OrigSourceStrPtr := PChar(OrigText)+StartOffs;
  1867.      end;
  1868.      sourceStrPtrLen := Len;
  1869.      ActualStyleNo := GetActualStyle(li);
  1870.      if ActualStyleNo<>Params.LastTextStyle then begin
  1871.        Params.FontInfoCache.LastTextStyle := Params.LastTextStyle;
  1872.        Params.FontInfoCache.CurParaBiDiMode := GetParaBiDiMode(GetItemPara(ItemNo));
  1873.        with Params.FontInfoCache[ActualStyleNo] do begin
  1874.          Params.LastTextStyle := ActualStyleNo;
  1875.          Params.TextMetric    := TextMetric;
  1876.          Params.VerticalOffs  := VerticalOffset;
  1877.          Params.FormatCanvas  := {Params.FontInfoCache[ActualStyleNo].}Canvas;
  1878.        end;
  1879.        Params.FormatCanvasHandle := Params.FormatCanvas.Handle;
  1880.        if (RVStyle.TextStyles[ActualStyleNo].CharSpacing<>0) and
  1881.           (sad.ppixScreen<>sad.ppixDevice) and
  1882.           (GetItemBiDiMode(ItemNo)=rvbdUnspecified) then
  1883.          SetTextCharacterExtra(Params.FormatCanvasHandle,
  1884.            GetDevX(RVStyle.TextStyles[ActualStyleNo].CharSpacing));
  1885.      end;
  1886.      if rvflUseExternalLeading in Flags then
  1887.        ExternalLeading := Params.TextMetric.tmExternalLeading
  1888.      else
  1889.        ExternalLeading := 0;
  1890.      AtStart := (StartOffs=0);
  1891.      if sourceStrPtrLen=0 then begin {empty string}
  1892.        sz.cy := Params.FontInfoCache[ActualStyleNo].EmptyLineHeight;
  1893.        sz.cx := 0;
  1894.        if not li.SameAsPrev then begin
  1895.          OnStartNewLine(li, False);
  1896.          Params.x :=0;
  1897.          inc(Params.baseline, ExtraSpaceBelowLine);
  1898.          y := Params.baseline+Params.prevDesc;
  1899.          Params.prevabove := ExternalLeading+Params.TextMetric.tmAscent+Params.VerticalOffs;
  1900.          inc(Params.baseline, Params.prevDesc+Params.prevabove);
  1901.          Params.prevDesc := Params.TextMetric.tmDescent-Params.VerticalOffs;
  1902.          end
  1903.        else begin
  1904.          AdjustLineHeight(ExternalLeading+Params.TextMetric.tmAscent+Params.VerticalOffs);
  1905.          y := Params.baseline - (ExternalLeading+Params.TextMetric.tmAscent+Params.VerticalOffs);
  1906.          if Params.prevDesc < Params.TextMetric.tmDescent-Params.VerticalOffs then
  1907.            Params.prevDesc := Params.TextMetric.tmDescent-Params.VerticalOffs;
  1908.        end;
  1909.        dli := TRVDrawLineInfo.CreateEx(Params.x+Params.FirstIndent,y, sz.cx, sz.cy,
  1910.          ItemNo, not li.SameAsPrev);
  1911.        dli.Offs := 1+StartOffs;
  1912.        inc(Params.x, sz.cx);
  1913.        if RVStyle.TextStyles[ActualStyleNo].Jump then
  1914.          TCustomRVItemInfo(Items.Objects[ItemNo]).JumpID := -3;
  1915.        dli.Length := 0;
  1916.        if AtStart and not ShareItems then
  1917.          li.DrawItemNo := Params.LastDrawItem;
  1918.        DrawItems.Insert(Params.LastDrawItem, dli);
  1919.        //AdjustCP(li);
  1920.        inc(Params.LastDrawItem);
  1921.        exit;
  1922.      end;
  1923.      newline := AtStart and not li.SameAsPrev;
  1924.      while sourceStrPtrLen>0 do begin
  1925.        if newline then begin
  1926.          OnStartNewLine(li, not Params.IsParaStart);
  1927.          Params.x:=0;
  1928.          if (rvflTrim in Flags) and not Params.SpaceEaten and
  1929.             not Params.IsParaStart and (sourceStrPtrLen>1) then
  1930.            {$IFNDEF RVDONOTUSEUNICODE}
  1931.            if IsUnicodeItem then begin
  1932.              if PWord(sourceStrPtr)^=ord(' ') then begin
  1933.                inc(sourceStrPtr,2);
  1934.                inc(OrigSourceStrPtr, 2);
  1935.                dec(sourceStrPtrLen);
  1936.              end;
  1937.              end
  1938.            else
  1939.            {$ENDIF}
  1940.            if sourceStrPtr^=' ' then begin
  1941.              inc(sourceStrPtr);
  1942.              inc(OrigSourceStrPtr);
  1943.              dec(sourceStrPtrLen);
  1944.            end;
  1945.          Params.SpaceEaten := False;
  1946.        end;
  1947.        SpaceAfter := Params.LineWidth-Params.x;
  1948.        if SpaceAfter<0 then SpaceAfter := 0;
  1949.        {$IFNDEF RVDONOTUSEUNICODE}
  1950.        if IsUnicodeItem then
  1951.          max := MaxFitW
  1952.        else
  1953.        {$ENDIF}
  1954.          max := MaxFitA;
  1955.        max2 := max;
  1956.        sourceStrPtr2 := sourceStrPtr;
  1957.        if max=0 then
  1958.          if newline
  1959.          {$IFNDEF RVDONOTUSELISTS}
  1960.          or (AtStart and (ItemNo>0) and (GetItemStyle(ItemNo-1)=rvsListMarker))
  1961.          {$ENDIF}
  1962.           then begin
  1963.              max := 1;
  1964.              {$IFNDEF RVDONOTUSEUNICODE}
  1965.              if RVNT and IsUnicodeItem then
  1966.                max := AdjustMaxFitR(max);
  1967.              {$ENDIF}
  1968.            end
  1969.          else begin
  1970.            Params.x:=0;
  1971.            Params.IsParaStart := False;
  1972.            newline := true;
  1973.            continue;
  1974.          end;
  1975.        if max<sourceStrPtrLen then begin
  1976.            {$IFNDEF RVDONOTUSEUNICODE}
  1977.            if IsUnicodeItem then begin
  1978.              strSpacePos := RVU_FindLineBreak(PRVWordArray(OrigSourceStrPtr), max,
  1979.                max+1=sourceStrPtrLen); // MyStrRScanW(sourceStrPtr,' ',max)
  1980.              if (strSpacePos<>nil) then
  1981.                strSpacePos := sourceStrPtr + (strSpacePos-OrigSourceStrPtr);
  1982.              { // commented Jun 24 2004
  1983.               if strSpacePos=sourceStrPtr+max*2 then
  1984.                 strSpacePos := nil;}
  1985.              end
  1986.            else
  1987.            {$ENDIF}
  1988.            begin
  1989.              if max+1=sourceStrPtrLen then
  1990.                strSpacePos := MyStrRScanA(sourceStrPtr,' ',max)
  1991.              else
  1992.                strSpacePos := MyStrRScanA(sourceStrPtr,' ',max+1);
  1993.            end;
  1994.            if (strSpacePos=nil) and (rvflTrim in Flags) and
  1995.               ((max+1<sourceStrPtrLen) or ((ItemNo+1<Items.Count) and not IsFromNewLine(ItemNo+1)))
  1996.              then begin
  1997.              {$IFNDEF RVDONOTUSEUNICODE}
  1998.              if IsUnicodeItem then begin
  1999.                if PRVWordArray(sourceStrPtr)[max]=UNI_Space then begin
  2000.                  strSpacePos := sourceStrPtr+max*2;
  2001.                  inc(max);
  2002.                end;
  2003.                end
  2004.              else
  2005.              {$ENDIF}
  2006.              begin
  2007.                if sourceStrPtr[max]=' ' then begin
  2008.                  strSpacePos := sourceStrPtr+max;
  2009.                  inc(max);
  2010.                end;
  2011.              end;
  2012.            end;
  2013.            if strSpacePos<>nil then begin
  2014.              {$IFNDEF RVDONOTUSEUNICODE}
  2015.              if IsUnicodeItem then begin
  2016.                if (rvflTrim in Flags) and (PRVWordArray(strSpacePos)[0]=UNI_Space) and
  2017.                  (strSpacePos<>sourceStrPtr) then begin
  2018.                  max := (strSpacePos-sourceStrPtr) div 2;
  2019.                  Params.SpaceEaten := True;
  2020.                  end
  2021.                else
  2022.                  max := (strSpacePos-sourceStrPtr) div 2+1;
  2023.                end
  2024.              else
  2025.              {$ENDIF}
  2026.              begin
  2027.                if (rvflTrim in Flags) and (strSpacePos<>sourceStrPtr) then begin
  2028.                  max := strSpacePos-sourceStrPtr;
  2029.                  Params.SpaceEaten := True;
  2030.                  end
  2031.                else
  2032.                  max := strSpacePos-sourceStrPtr+1;
  2033.              end;
  2034.              end
  2035.            else if not (newline
  2036.            {$IFNDEF RVDONOTUSELISTS}
  2037.            or (AtStart and (ItemNo>0) and (GetItemStyle(ItemNo-1)=rvsListMarker))
  2038.            {$ENDIF}
  2039.            )
  2040.            then begin
  2041.              Params.IsParaStart := False;
  2042.              newline := true;
  2043.              continue;
  2044.            end;
  2045.        end;
  2046.        {$IFNDEF RVDONOTUSEUNICODE}
  2047.        if IsUnicodeItem then begin
  2048.          Offs := (sourceStrPtr - PChar(Text)) div 2+1;
  2049.          StrForAdd := sourceStrPtr;
  2050.          inc(sourceStrPtr,max*2);
  2051.          inc(OrigSourceStrPtr, max*2);
  2052.          dec(sourceStrPtrLen,max);
  2053.          if Params.SpaceEaten then begin
  2054.            inc(sourceStrPtr, 2);
  2055.            inc(OrigSourceStrPtr, 2);
  2056.            dec(sourceStrPtrLen);
  2057.            Params.SpaceEaten := sourceStrPtrLen=0;
  2058.          end;
  2059.          end
  2060.        else
  2061.        {$ENDIF}
  2062.        begin
  2063.          Offs := sourceStrPtr - PChar(Text)+1;
  2064.          StrForAdd := sourceStrPtr;
  2065.          inc(sourceStrPtr,max);
  2066.          inc(OrigSourceStrPtr,max);
  2067.          dec(sourceStrPtrLen,max);
  2068.          if Params.SpaceEaten then begin
  2069.            inc(sourceStrPtr);
  2070.            inc(OrigsourceStrPtr);
  2071.            dec(sourceStrPtrLen);
  2072.            Params.SpaceEaten := sourceStrPtrLen=0;
  2073.          end;
  2074.        end;
  2075.        if (newline or (max<>0)) then begin
  2076.          dli := TRVDrawLineInfo.Create;
  2077.          dli.ItemNo := ItemNo;
  2078.          dli.Offs := Offs;
  2079.          if {(sourceStrPtrLen<>0) and} ((max<>max2) or (sourceStrPtr2<>sourceStrPtr) or (rvpaoNoWrap in pi.Options)) then
  2080.           {$IFNDEF RVDONOTUSEUNICODE}
  2081.            if IsUnicodeItem then
  2082.              RVU_GetTextExtentPoint32W(Params.FormatCanvas, Pointer(strForAdd), max, sz)
  2083.            else
  2084.            {$ENDIF}
  2085.              GetTextExtentPoint32(Params.FormatCanvasHandle,strForAdd,max,sz);
  2086.          if not newline then begin {continue line}
  2087.            AdjustLineHeight(ExternalLeading+Params.TextMetric.tmAscent+Params.VerticalOffs);
  2088.            y := Params.baseline - (ExternalLeading+Params.TextMetric.tmAscent+Params.VerticalOffs);
  2089.            dli.FromNewLine := False;
  2090.            end
  2091.          else  begin { new line }
  2092.            dli.FromNewLine := True;
  2093.            Params.x :=0;
  2094.            inc(Params.baseline, ExtraSpaceBelowLine);
  2095.            y := Params.baseline+Params.prevDesc;
  2096.            Params.prevabove := ExternalLeading+Params.TextMetric.tmAscent+Params.VerticalOffs;
  2097.            inc(Params.baseline, Params.prevDesc+Params.prevabove);
  2098.          end;
  2099.          dli.Left   :=Params.x+Params.FirstIndent;
  2100.          dli.Top    := y;
  2101.          dli.Width  := sz.cx;
  2102.          dli.Height := sz.cy;
  2103.          dli.Length := max;
  2104.          DrawItems.Insert(Params.LastDrawItem,dli);
  2105.          if AtStart and not ShareItems then
  2106.            li.DrawItemNo := Params.LastDrawItem;
  2107.          inc(Params.LastDrawItem);
  2108.          if (rvflUseJumps in Flags) and RVStyle.TextStyles[ActualStyleNo].Jump then begin
  2109.            jmpinfo := TRVJumpInfo.Create;
  2110.            jmpinfo.w := sz.cx;
  2111.            jmpinfo.h := sz.cy;
  2112.            jmpinfo.id := nJmps;
  2113.            if StartOffs>0 then dec(jmpinfo.id);
  2114.            jmpinfo.DrawItemNo := Params.LastDrawItem-1;
  2115.            jmpinfo.Cursor := RVStyle.TextStyles[ActualStyleNo].JumpCursor;
  2116.            jmpinfo.RVData := Self;
  2117.            jumps.Add(jmpinfo);
  2118.          end;
  2119.          if newline or (Params.prevDesc < Params.TextMetric.tmDescent-Params.VerticalOffs) then
  2120.            Params.prevDesc := Params.TextMetric.tmDescent-Params.VerticalOffs;
  2121.          inc(Params.x,sz.cx);
  2122.          newline := True;
  2123.          Params.IsParaStart := False;
  2124.          AtStart := False;
  2125.          end
  2126.        else
  2127.          newline := true;
  2128.      end; { while }
  2129.      if RVStyle.TextStyles[ActualStyleNo].Jump and (StartOffs=0) then begin
  2130.        TCustomRVItemInfo(Items.Objects[ItemNo]).JumpID := nJmps;
  2131.        inc(nJmps);
  2132.      end;
  2133.   end;
  2134. end;
  2135. {------------------------------------------------------------------------------}
  2136. procedure TCustomRVFormattedData.FormatWords(ItemNo: Integer; Canvas: TCanvas;
  2137.   var sad: TRVScreenAndDevice; var Params: TRVFormatParams);
  2138. var offs: Integer;
  2139.     LinesNo, TmpStr, SpacePos: PChar;
  2140.     Len, WordLen: Integer;
  2141.     {$IFNDEF RVDONOTUSEUNICODE}
  2142.     Unicode: Boolean;
  2143.     {$ENDIF}
  2144.     Text, OrigText: String;
  2145. begin
  2146.   Len := Length(Items[ItemNo]);
  2147.   if Len=0 then begin
  2148.     FormatLine( '', '', 0, Len, ItemNo, Canvas, sad, Params);
  2149.     exit;
  2150.   end;
  2151.   {$IFNDEF RVDONOTUSEUNICODE}
  2152.   Unicode := rvioUnicode in GetItemOptions(ItemNo);
  2153.   if Unicode then
  2154.     Len := Len div 2;
  2155.   {$ENDIF}
  2156.   offs := 0;
  2157.   OrigText := Items[ItemNo];
  2158.   Text := RV_ReturnProcessedString(OrigText,
  2159.     GetRVStyle.TextStyles[GetItemStyle(ItemNo)], False,
  2160.       rvoShowSpecialCharacters in Options, False);
  2161.   LinesNo := PChar(Text);
  2162.   while Len>0 do begin
  2163.     TmpStr := LinesNo;
  2164.     {$IFNDEF RVDONOTUSEUNICODE}
  2165.     if Unicode then begin
  2166.       if (PWord(TmpStr)^ = ord(' ')) then
  2167.         inc(PChar(TmpStr), 2);
  2168.       SpacePos := RVU_StrScanW(TmpStr, ord(' '), Len)
  2169.       end
  2170.     else
  2171.     {$ENDIF}
  2172.     begin
  2173.       if (TmpStr^ = ' ') then
  2174.         inc(TmpStr);
  2175.       SpacePos := StrScan(TmpStr, ' ');
  2176.     end;
  2177.     if SpacePos=nil then
  2178.       WordLen := Len
  2179.     else begin
  2180.       WordLen := SpacePos-LinesNo;
  2181.       {$IFNDEF RVDONOTUSEUNICODE}
  2182.       if Unicode then
  2183.         WordLen := WordLen div 2;
  2184.       {$ENDIF}
  2185.     end;
  2186.     FormatLine(Text, OrigText, Offs, WordLen, ItemNo, Canvas, sad, Params);
  2187.     inc(offs, WordLen);
  2188.     inc(LinesNo, WordLen);
  2189.     {$IFNDEF RVDONOTUSEUNICODE}
  2190.     if Unicode then
  2191.       inc(LinesNo, WordLen);
  2192.     {$ENDIF}
  2193.     dec(Len, WordLen);
  2194.   end;
  2195. end;
  2196. {------------------------------------------------------------------------------}
  2197. function TCustomRVFormattedData.GetHOffs: Integer;
  2198. begin
  2199.   Result := 0;
  2200. end;
  2201. {------------------------------------------------------------------------------}
  2202. function TCustomRVFormattedData.GetVOffs: Integer;
  2203. begin
  2204.   Result := 0;
  2205. end;
  2206. {------------------------------------------------------------------------------}
  2207. procedure TCustomRVFormattedData.Format(NoCaching: Boolean);
  2208. begin
  2209.   Format_(False, True, False, 0, GetCanvas, False, NoCaching, False);
  2210. end;
  2211. {------------------------------------------------------------------------------}
  2212. procedure TCustomRVFormattedData.ApplyZoom(Canvas: TCanvas);
  2213. begin
  2214.   {
  2215.   if ZoomPercent<>100 then begin
  2216.     SetMapMode(Canvas.Handle,MM_ANISOTROPIC);
  2217.     SetWindowExtEx(Canvas.Handle,100,100,nil);
  2218.     SetViewportExtEx(Canvas.Handle,ZoomPercent,ZoomPercent,nil);
  2219.   end;
  2220.   }
  2221. end;
  2222. {------------------------------------------------------------------------------}
  2223. procedure TCustomRVFormattedData.RestoreZoom(Canvas: TCanvas);
  2224. begin
  2225.   {
  2226.   if ZoomPercent<>100 then
  2227.     SetMapMode(Canvas.Handle,MM_TEXT);
  2228.   }
  2229. end;
  2230. {------------------------------------------------------------------------------}
  2231. procedure TCustomRVFormattedData.ZoomInt(var v: Integer);
  2232. begin
  2233.   v := v;
  2234.   //v := MulDiv(v,100,ZoomPercent);
  2235. end;
  2236. {------------------------------------------------------------------------------}
  2237. procedure TCustomRVFormattedData.ZoomRectDown(var r: TRect);
  2238. begin
  2239.   {
  2240.   with r do begin
  2241.     Left := MulDiv(Left,100,ZoomPercent);
  2242.     Top := MulDiv(Top,100,ZoomPercent);
  2243.     Right := MulDiv(Right,100,ZoomPercent);
  2244.     Bottom := MulDiv(Bottom,100,ZoomPercent);
  2245.   end;
  2246.   }
  2247. end;
  2248. {------------------------------------------------------------------------------}
  2249. procedure TCustomRVFormattedData.GetSADForFormatting(Canvas: TCanvas;
  2250.   var sad: TRVScreenAndDevice);
  2251. begin
  2252. //  ApplyZoom(Canvas);
  2253.   RV_InfoAboutSaD(sad, Canvas);
  2254. end;
  2255. {------------------------------------------------------------------------------}
  2256. procedure TCustomRVFormattedData.Format_(OnlyResized, ForceFormat,
  2257.   NoScroll: Boolean; depth: Integer; Canvas: TCanvas;
  2258.   OnlyTail, NoCaching, Reformatting: Boolean);
  2259. var i: Integer;
  2260.     oldtextwidth, olddocumentwidth, cw, ch: Integer;
  2261.     sad: TRVScreenAndDevice;
  2262.     StartLine: Integer;
  2263.     StartNo, EndNo, StartOffs, EndOffs: Integer;
  2264.     DevMinTextWidth, DevMaxTextWidth: Integer;
  2265.     FV, DeltaFV: Integer;
  2266.     RVStyle: TRVStyle;
  2267.     ExtraSpaceBelowLine: Integer;
  2268.     Params: TRVFormatParams;
  2269. begin
  2270.    if AlreadyFormatted then begin
  2271.      AlreadyFormatted := False;
  2272.      exit;
  2273.    end;
  2274.    if (depth>1) or (GetRVStyle=nil) or (rvstSkipformatting in State) then exit;
  2275.    if Canvas=nil then
  2276.      Canvas := GetCanvas;
  2277.    if depth=0 then begin
  2278.      StartFormatting;
  2279.    end;
  2280.    try
  2281.      Params.SpaceEaten := False;
  2282.      Params.LastTabDrawItemNo := -1;
  2283.      Params.NoCaching := NoCaching;
  2284.      Params.Reformatting := Reformatting;
  2285.      Params.FirstParaItemNo := -1;
  2286.      Params.LastTextStyle := -1;
  2287.      Params.IsParaStart := True;
  2288.      FV := -1;     { avoiding warings }
  2289.      DeltaFV := 0; { avoiding warings }
  2290.      if depth=0 then begin
  2291.         if OnlyResized then begin
  2292.           StoreSelBounds(StartNo, EndNo, StartOffs, EndOffs, False);
  2293.           if not NoScroll then begin
  2294.             FV := GetDrawItemNo(GetVOffs, gdinFirstVisible);
  2295.             if FV>=DrawItems.Count then FV:=DrawItems.Count-1;
  2296.             if FV<>-1 then  begin
  2297.               DeltaFV := GetVOffs-DrawItems[FV].Top;
  2298.               FV := DrawItems[FV].ItemNo;
  2299.             end;
  2300.           end;
  2301.         end;
  2302.         if OnlyTail then FV := GetVOffs;
  2303.      end;
  2304.      oldtextwidth := TextWidth;
  2305.      olddocumentwidth := DocumentWidth;
  2306.      GetSADForFormatting(Canvas, sad);
  2307.      sad.LeftMargin := MulDiv(GetLeftMargin,  sad.ppixDevice, sad.ppixScreen);
  2308.      sad.RightMargin := MulDiv(GetRightMargin,  sad.ppixDevice, sad.ppixScreen);