├── LICENSE ├── README.md └── Source └── PDFium.Control.pas /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright 2021-2023 Text Editor Pro 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # TPDFiumControl 2 | 3 | Page scrolling PDF control for Delphi. 4 | 5 | ## Requires 6 | 7 | Andy's [PdfiumLib](https://github.com/ahausladen/PdfiumLib) core classes - PdfiumCore.pas and PdfiumLib.pas. 8 | 9 | ## Supports 10 | 11 | - AlphaSkins (native) - https://www.alphaskins.com/ 12 | 13 | ## Defines 14 | 15 | Define | Description 16 | ------ | ----------- 17 | ALPHASKINS | Native AlphaSkins support 18 | 19 | ## License 20 | 21 | [MIT](https://github.com/TextEditorPro/TTextEditor/blob/main/LICENSE) 22 | 23 | ## Connect 24 | 25 | https://www.linkedin.com/in/lassemarkusrautiainen/ 26 | 27 | ## Donations 28 | 29 | https://ko-fi.com/texteditorpro -------------------------------------------------------------------------------- /Source/PDFium.Control.pas: -------------------------------------------------------------------------------- 1 | unit PDFium.Control; 2 | 3 | {.$DEFINE USE_LOAD_FROM_URL} 4 | 5 | interface 6 | 7 | uses 8 | Winapi.Messages, Winapi.Windows, System.Classes, System.Math, System.SysUtils, System.UITypes, System.Variants, 9 | Vcl.Controls, Vcl.Dialogs, Vcl.ExtCtrls, Vcl.Forms, Vcl.Graphics, Vcl.Grids, PDFiumCore, PDFiumLib 10 | {$IFDEF ALPHASKINS} 11 | , acSBUtils, sCommonData 12 | {$ENDIF}; 13 | 14 | const 15 | CDefaultDrawOptions = [proAnnotations]; 16 | 17 | type 18 | TPDFZoomMode = (zmActualSize, zmFitHeight, zmFitWidth, zmPercent); 19 | 20 | TPDFControlRectArray = array of TRect; 21 | TPDFControlPDFRectArray = TArray; 22 | 23 | TPDFControlClickLinkEvent = procedure(const ASender: TObject; const AURL: string) of object; 24 | TPDFControlScrollEvent = procedure(const ASender: TObject; const AScrollBar: TScrollBarKind) of object; 25 | TPDFLoadProtectedEvent = procedure(const ASender: TObject; var APassword: UTF8String) of object; 26 | 27 | TPageInfo = record 28 | Height: Single; 29 | Index: Integer; 30 | Rect: TRect; 31 | Rotation: TPDFPageRotation; 32 | SearchCurrentIndex: Integer; 33 | SearchRects: TPDFControlPDFRectArray; 34 | Visible: Integer; 35 | Width: Single; 36 | end; 37 | 38 | { Page is not a public property in core class } 39 | TPDFPageHelper = class helper for PDFiumCore.TPDFPage 40 | function Page: FPDF_PAGE; 41 | end; 42 | 43 | TCustomPDFiumControl = class(TScrollingWinControl) 44 | strict private 45 | FAllowFormFieldEdit: Boolean; 46 | FAllowTextSelection: Boolean; 47 | FChanged: Boolean; 48 | FDrawOptions: TPdfPageRenderOptions; 49 | FFilename: string; 50 | FFormFieldFocused: Boolean; 51 | FFormOutputSelectedRects: TPDFControlPDFRectArray; 52 | FHeight: Single; 53 | FMouseDownPoint: TPoint; 54 | FMousePressed: Boolean; 55 | FOnAfterLoad: TNotifyEvent; 56 | FOnClickLink: TPDFControlClickLinkEvent; 57 | FOnLoadProtected: TPDFLoadProtectedEvent; 58 | FOnPageChanged: TNotifyEvent; 59 | FOnPaint: TNotifyEvent; 60 | FOnScroll: TPDFControlScrollEvent; 61 | FPageBorderColor: TColor; 62 | FPageCount: Integer; 63 | FPageIndex: Integer; 64 | FPageInfo: TArray; 65 | FPageMargin: Integer; 66 | FPDFDocument: TPDFDocument; 67 | FPrintJobTitle: string; 68 | {$IFDEF ALPHASKINS} 69 | FScrollWnd: TacScrollWnd; 70 | {$ENDIF} 71 | FSearchCount: Integer; 72 | FSearchHighlightAll: Boolean; 73 | FSearchIndex: Integer; 74 | FSearchMatchCase: Boolean; 75 | FSearchText: string; 76 | FSearchWholeWords: Boolean; 77 | FSelectionActive: Boolean; 78 | FSelectionStartCharIndex: Integer; 79 | FSelectionStopCharIndex: Integer; 80 | {$IFDEF ALPHASKINS} 81 | FSkinData: TsScrollWndData; 82 | {$ENDIF} 83 | FWebLinksInfo: TPdfPageWebLinksInfo; 84 | FWidth: Single; 85 | FZoomMode: TPDFZoomMode; 86 | FZoomPercent: Single; 87 | function CreatePDFDocument: TPDFDocument; 88 | function DeviceToPage(const X, Y: Integer): TPDFPoint; 89 | function GetCurrentPage: TPDFPage; 90 | function GetPageIndexAt(const APoint: TPoint): Integer; 91 | function GetSelectionLength: Integer; 92 | function GetSelectionRects: TPDFControlRectArray; 93 | function GetSelectionStart: Integer; 94 | function GetSelectionText: string; 95 | function InternPageToDevice(const APage: TPDFPage; const APageRect: TPDFRect; const ARect: TRect): TRect; 96 | function IsAnnotationLinkAt(const X, Y: Integer; out AURL: string; out APageIndex: Integer; out ALinkRect: TRect): Boolean; 97 | function IsCurrentPageValid: Boolean; 98 | function IsWebLinkAt(const X, Y: Integer): Boolean; overload; 99 | function IsWebLinkAt(const X, Y: Integer; var AURL: string): Boolean; overload; 100 | function PageHeightZoomPercent: Single; 101 | function PageWidthZoomPercent: Single; 102 | function SelectWord(const ACharIndex: Integer): Boolean; 103 | function SetSelStopCharIndex(const X, Y: Integer): Boolean; 104 | procedure AdjustPageInfo; 105 | procedure AdjustScrollBar(const APageIndex: Integer); 106 | procedure AdjustZoom; 107 | procedure CMGesture(var AMessage: TCMGesture); message CM_GESTURE; 108 | procedure DoScroll(const AScrollBarKind: TScrollBarKind); 109 | procedure DoSizeChanged; 110 | procedure FormFieldFocus(ADocument: TPDFDocument; AValue: PWideChar; AValueLen: Integer; AFieldFocused: Boolean); 111 | procedure FormGetCurrentPage(ADocument: TPDFDocument; var APage: TPDFPage); 112 | procedure FormInvalidate(ADocument: TPDFDocument; APage: TPDFPage; const APageRect: TPDFRect); 113 | procedure FormOutputSelectedRect(ADocument: TPDFDocument; APage: TPDFPage; const APageRect: TPDFRect); 114 | procedure GetPageWebLinks; 115 | procedure HideHint; 116 | procedure InternalAfterLoad; 117 | procedure InvalidateRectDiffs(const AOldRects, ANewRects: TPDFControlRectArray); 118 | procedure PageChanged; 119 | procedure PaintAlphaSelection(ADC: HDC; const APage: TPDFPage; const ARects: TPDFControlPDFRectArray; const AIndex: Integer; 120 | const AColor: TColor = TColors.SysNone); 121 | procedure PaintPage(ADC: HDC; const APage: TPDFPage; const AIndex: Integer); overload; 122 | procedure PaintPageBorder(ADC: HDC; const ARect: TRect); 123 | procedure PaintPageSearchResults(ADC: HDC; const APage: TPDFPage; const AIndex: Integer); 124 | procedure PaintPageSelection(ADC: HDC; const APage: TPDFPage; const AIndex: Integer); 125 | procedure SetPageCount(const AValue: Integer); 126 | procedure SetPageIndex(const AValue: Integer); 127 | procedure SetPageNumber(const AValue: Integer); 128 | procedure SetScrollSize; 129 | procedure SetSearchHighlightAll(const AValue: Boolean); 130 | procedure SetSelection(const AActive: Boolean; const AStartIndex, AStopIndex: Integer); 131 | procedure SetZoomMode(const AValue: TPDFZoomMode); 132 | procedure SetZoomPercent(const AValue: Single); 133 | procedure ShowHint(const AHint: string; const ARect: TRect); 134 | procedure UpdatePageIndex; 135 | procedure WMChar(var AMessage: TWMChar); message WM_CHAR; 136 | procedure WMEraseBkGnd(var AMessage: TWMEraseBkgnd); message WM_ERASEBKGND; 137 | procedure WMGetDlgCode(var AMessage: TWMGetDlgCode); message WM_GETDLGCODE; 138 | procedure WMHScroll(var AMessage: TWMHScroll); message WM_HSCROLL; 139 | procedure WMKeyDown(var AMessage: TWMKeyDown); message WM_KEYDOWN; 140 | procedure WMKeyUp(var AMessage: TWMKeyUp); message WM_KEYUP; 141 | procedure WMKillFocus(var AMessage: TWMKillFocus); message WM_KILLFOCUS; 142 | procedure WMPaint(var AMessage: TWMPaint); message WM_PAINT; 143 | procedure WMVScroll(var AMessage: TWMVScroll); message WM_VSCROLL; 144 | protected 145 | function DoMouseWheel(AShift: TShiftState; AWheelDelta: Integer; AMousePos: TPoint): Boolean; override; 146 | function GetPageNumber: Integer; 147 | function GetPageTop(const APageIndex: Integer): Integer; 148 | function PageToScreen(const AValue: Single): Integer; inline; 149 | function ZoomToScreen: Single; 150 | procedure KeyDown(var Key: Word; Shift: TShiftState); override; 151 | {$IFDEF ALPHASKINS} 152 | procedure Loaded; override; 153 | {$ENDIF} 154 | procedure MouseDown(AButton: TMouseButton; AShift: TShiftState; X, Y: Integer); override; 155 | procedure MouseMove(AShift: TShiftState; X, Y: Integer); override; 156 | procedure MouseUp(AButton: TMouseButton; AShift: TShiftState; X, Y: Integer); override; 157 | procedure PaintWindow(ADC: HDC); override; 158 | procedure Resize; override; 159 | procedure ShowError(const AMessage: string); virtual; 160 | public 161 | constructor Create(AOwner: TComponent); override; 162 | destructor Destroy; override; 163 | function GetPage(const AIndex: Integer): TPDFPage; 164 | function FindNext: Integer; 165 | function FindPrevious: Integer; 166 | function IsPageIndexValid(const APageIndex: Integer): Boolean; 167 | function IsTextSelected: Boolean; 168 | function SearchAll: Integer; overload; 169 | function SearchAll(const ASearchText: string): Integer; overload; 170 | function SearchAll(const ASearchText: string; const AHighlightAll: Boolean; const AMatchCase: Boolean; 171 | const AWholeWords: Boolean; const AScrollIntoView: Boolean = True; const APageIndex: Integer = -1): Integer; overload; 172 | {$IFDEF ALPHASKINS} 173 | procedure AfterConstruction; override; 174 | {$ENDIF} 175 | procedure ClearSearch; 176 | procedure ClearSelection; 177 | procedure CloseDocument; 178 | procedure CopyFormTextToClipboard; 179 | procedure CopyToClipboard; 180 | procedure CreateParams(var AParams: TCreateParams); override; 181 | procedure CutFormTextToClipboard; 182 | procedure GotoNextPage; 183 | procedure GoToPage(const AIndex: Integer; const ASetScrollBar: Boolean = True); 184 | procedure GotoPreviousPage; 185 | procedure LoadFromFile(const AFilename: string); 186 | procedure LoadFromStream(const AStream: TStream); 187 | {$IFDEF USE_LOAD_FROM_URL} 188 | procedure LoadFromURL(const AURL: string); 189 | {$ENDIF} 190 | procedure PaintPage(ADC: HDC; const ARect: TRect; const AIndex: Integer); overload; 191 | procedure PasteFormTextFromClipboard; 192 | procedure Print; 193 | procedure RotatePageClockwise; 194 | procedure RotatePageCounterClockwise; 195 | procedure SaveToFile(const AFilename: string; const AOption: TPdfDocumentSaveOption = dsoRemoveSecurity; const AFileVersion: Integer = -1); 196 | procedure SaveToStream(const AStream: TStream; const AOption: TPdfDocumentSaveOption = dsoRemoveSecurity; const AFileVersion: Integer = -1); 197 | procedure SelectAll; 198 | procedure SelectAllFormText; 199 | procedure SelectText(const ACharIndex: Integer; const ACount: Integer); 200 | procedure SetFocus; override; 201 | {$IFDEF ALPHASKINS} 202 | procedure WndProc(var AMessage: TMessage); override; 203 | {$ENDIF} 204 | procedure ZoomToHeight; 205 | procedure ZoomToWidth; 206 | procedure Zoom(const APercent: Single); 207 | property Align; 208 | property AllowFormFieldEdit: Boolean read FAllowFormFieldEdit write FAllowFormFieldEdit default False; 209 | property AllowTextSelection: Boolean read FAllowTextSelection write FAllowTextSelection default True; 210 | property Color; 211 | property CurrentPage: TPDFPage read GetCurrentPage; 212 | property DrawOptions: TPdfPageRenderOptions read FDrawOptions write FDrawOptions default CDefaultDrawOptions; 213 | property Filename: string read FFilename write FFilename; 214 | property OnAfterLoad: TNotifyEvent read FOnAfterLoad write FOnAfterLoad; 215 | property OnClickLink: TPDFControlClickLinkEvent read FOnClickLink write FOnClickLink; 216 | property OnLoadProtected: TPDFLoadProtectedEvent read FOnLoadProtected write FOnLoadProtected; 217 | property OnPageChanged: TNotifyEvent read FOnPageChanged write FOnPageChanged; 218 | property OnPaint: TNotifyEvent read FOnPaint write FOnPaint; 219 | property OnScroll: TPDFControlScrollEvent read FOnScroll write FOnScroll; 220 | property PDFDocument: TPDFDocument read FPDFDocument; 221 | property PageBorderColor: TColor read FPageBorderColor write FPageBorderColor default TColors.Silver; 222 | property PageCount: Integer read FPageCount; 223 | property PageIndex: Integer read FPageIndex write SetPageIndex; 224 | property PageMargin: Integer read FPageMargin write FPageMargin default 6; 225 | property PageNumber: Integer read GetPageNumber write SetPageNumber; 226 | property PopupMenu; 227 | property PrintJobTitle: string read FPrintJobTitle write FPrintJobTitle; 228 | property SearchCount: Integer read FSearchCount write FSearchCount; 229 | property SearchHighlightAll: Boolean read FSearchHighlightAll write SetSearchHighlightAll; 230 | property SearchIndex: Integer read FSearchIndex write FSearchIndex; 231 | property SearchMatchCase: Boolean read FSearchMatchCase write FSearchMatchCase; 232 | property SearchText: string read FSearchText write FSearchText; 233 | property SearchWholeWords: Boolean read FSearchWholeWords write FSearchWholeWords; 234 | property SelectionLength: Integer read GetSelectionLength; 235 | property SelectionStart: Integer read GetSelectionStart; 236 | property SelectionText: string read GetSelectionText; 237 | {$IFDEF ALPHASKINS} 238 | property SkinData: TsScrollWndData read FSkinData write FSkinData; 239 | {$ENDIF} 240 | property Visible; 241 | property ZoomMode: TPDFZoomMode read FZoomMode write SetZoomMode default zmActualSize; 242 | property ZoomPercent: Single read FZoomPercent write SetZoomPercent; 243 | end; 244 | 245 | TPDFiumControl = class(TCustomPDFiumControl) 246 | published 247 | property Align; 248 | property AllowFormFieldEdit; 249 | property AllowTextSelection; 250 | property Color; 251 | property DrawOptions; 252 | property OnAfterLoad; 253 | property OnClickLink; 254 | property OnLoadProtected; 255 | property OnPageChanged; 256 | property OnPaint; 257 | property OnScroll; 258 | property PageBorderColor; 259 | property PageMargin; 260 | property PopupMenu; 261 | property PrintJobTitle; 262 | property SearchHighlightAll; 263 | property SearchMatchCase; 264 | property SearchWholeWords; 265 | property Visible; 266 | property ZoomMode; 267 | property ZoomPercent; 268 | end; 269 | 270 | TCustomPDFiumControlThumbnails = class(TDrawGrid) 271 | private 272 | FDefaultSizeSet: Boolean; 273 | FIsMousedown: Boolean; 274 | FPDFiumControl: TPDFiumControl; 275 | {$IFDEF ALPHASKINS} 276 | FScrollWnd: TacScrollWnd; 277 | FSkinData: TsScrollWndData; 278 | {$ENDIF} 279 | FTimerStarted: Boolean; 280 | procedure DoPDFiumControlAfterLoad(Sender: TObject); 281 | procedure DoPDFiumControlPageChanged(Sender: TObject); 282 | procedure SetDefaultSize; 283 | procedure SetPDFiumControl(const AValue: TPDFiumControl); 284 | protected 285 | function SelectCell(ACol, ARow: Longint): Boolean; override; 286 | procedure DrawCell(ACol, ARow: Longint; ARect: TRect; AState: TGridDrawState); override; 287 | {$IFDEF ALPHASKINS} 288 | procedure Loaded; override; 289 | {$ENDIF} 290 | procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X: Integer; Y: Integer); override; 291 | procedure MouseMove(Shift: TShiftState; X: Integer; Y: Integer); override; 292 | procedure Resize; override; 293 | property PDFiumControl: TPDFiumControl read FPDFiumControl write SetPDFiumControl; 294 | public 295 | constructor Create(AOwner: TComponent); override; 296 | {$IFDEF ALPHASKINS} 297 | destructor Destroy; override; 298 | procedure AfterConstruction; override; 299 | procedure WndProc(var AMessage: TMessage); override; 300 | property SkinData: TsScrollWndData read FSkinData write FSkinData; 301 | {$ENDIF} 302 | end; 303 | 304 | TPDFiumControlThumbnails = class(TCustomPDFiumControlThumbnails) 305 | published 306 | property PDFiumControl; 307 | end; 308 | 309 | TPDFDocumentVclPrinter = class(TPDFDocumentPrinter) 310 | private 311 | FBeginDocCalled: Boolean; 312 | FPagePrinted: Boolean; 313 | protected 314 | function GetPrinterDC: HDC; override; 315 | function PrinterStartDoc(const AJobTitle: string): Boolean; override; 316 | procedure PrinterEndDoc; override; 317 | procedure PrinterEndPage; override; 318 | procedure PrinterStartPage; override; 319 | public 320 | class function PrintDocument(const ADocument: TPDFDocument; const AJobTitle: string; 321 | const AShowPrintDialog: Boolean = True; const AAllowPageRange: Boolean = True; 322 | const AParentWnd: HWND = 0): Boolean; static; 323 | end; 324 | 325 | implementation 326 | 327 | uses 328 | System.Character, System.Generics.Collections, System.Generics.Defaults, System.Types, Vcl.Clipbrd, Vcl.Printers 329 | {$IFDEF USE_LOAD_FROM_URL} 330 | , System.Net.HttpClientComponent, System.Net.HttpClient 331 | {$ENDIF} 332 | {$IFDEF ALPHASKINS} 333 | , sConst, sDialogs, sMessages, sStyleSimply, sVCLUtils 334 | {$ENDIF}; 335 | 336 | var 337 | GHintWindow: THintWindow; 338 | 339 | function GetHintWindow: THintWindow; 340 | begin 341 | if not Assigned(GHintWindow) then 342 | begin 343 | GHintWindow := THintWindow.Create(Application); 344 | GHintWindow.DoubleBuffered := True; 345 | end; 346 | 347 | Result := GHintWindow; 348 | end; 349 | 350 | { TPDFPage } 351 | 352 | function TPDFPageHelper.Page: FPDF_PAGE; 353 | begin 354 | with Self do { Trick to get the private property } 355 | Result := FPage; 356 | end; 357 | 358 | { TCustomPDFiumControl } 359 | 360 | constructor TCustomPDFiumControl.Create(AOwner: TComponent); 361 | begin 362 | {$IFDEF ALPHASKINS} 363 | FSkinData := TsScrollWndData.Create(Self, True); 364 | FSkinData.COC := COC_TsMemo; 365 | FSkinData.CustomFont := True; 366 | StyleElements := [seBorder]; 367 | {$ENDIF} 368 | 369 | inherited Create(AOwner); 370 | 371 | ControlStyle := ControlStyle + [csOpaque]; 372 | FZoomMode := zmActualSize; 373 | FZoomPercent := 100; 374 | FPageIndex := 0; 375 | FPageMargin := 6; 376 | FPrintJobTitle := 'Print PDF'; 377 | FAllowFormFieldEdit := False; 378 | FAllowTextSelection := True; 379 | FDrawOptions := CDefaultDrawOptions; 380 | 381 | if not (csDesigning in ComponentState) then 382 | FPDFDocument := CreatePDFDocument; 383 | 384 | DoubleBuffered := True; 385 | ParentBackground := False; 386 | ParentColor := False; 387 | Color := clWhite; 388 | FPageBorderColor := TColors.Silver; 389 | TabStop := True; 390 | Width := 200; 391 | Height := 250; 392 | 393 | VertScrollBar.Smooth := True; 394 | VertScrollBar.Tracking := True; 395 | HorzScrollBar.Smooth := True; 396 | HorzScrollBar.Tracking := True; 397 | end; 398 | 399 | function TCustomPDFiumControl.CreatePDFDocument: TPDFDocument; 400 | begin 401 | Result := TPDFDocument.Create; 402 | Result.OnFormInvalidate := FormInvalidate; 403 | Result.OnFormFieldFocus := FormFieldFocus; 404 | Result.OnFormGetCurrentPage := FormGetCurrentPage; 405 | Result.OnFormOutputSelectedRect := FormOutputSelectedRect; 406 | end; 407 | 408 | procedure TCustomPDFiumControl.CreateParams(var AParams: TCreateParams); 409 | begin 410 | inherited CreateParams(AParams); 411 | 412 | with AParams.WindowClass do 413 | Style := Style and not (CS_HREDRAW or CS_VREDRAW); 414 | end; 415 | 416 | destructor TCustomPDFiumControl.Destroy; 417 | begin 418 | {$IFDEF ALPHASKINS} 419 | if Assigned(FScrollWnd) then 420 | begin 421 | FScrollWnd.Free; 422 | FScrollWnd := nil; 423 | end; 424 | 425 | if Assigned(FSkinData) then 426 | begin 427 | FSkinData.Free; 428 | FSkinData := nil; 429 | end; 430 | {$ENDIF} 431 | 432 | if Assigned(FWebLinksInfo) then 433 | FreeAndNil(FWebLinksInfo); 434 | 435 | if Assigned(FPDFDocument) then 436 | FPDFDocument.Free; 437 | 438 | inherited; 439 | end; 440 | 441 | {$IFDEF ALPHASKINS} 442 | procedure TCustomPDFiumControl.AfterConstruction; 443 | begin 444 | inherited AfterConstruction; 445 | 446 | if HandleAllocated then 447 | RefreshEditScrolls(SkinData, FScrollWnd); 448 | 449 | UpdateData(FSkinData); 450 | end; 451 | 452 | procedure TCustomPDFiumControl.Loaded; 453 | begin 454 | inherited Loaded; 455 | 456 | FSkinData.Loaded(False); 457 | end; 458 | 459 | procedure TCustomPDFiumControl.WndProc(var AMessage: TMessage); 460 | var 461 | LPaintStruct: TPaintStruct; 462 | begin 463 | if AMessage.Msg = SM_ALPHACMD then 464 | case AMessage.WParamHi of 465 | AC_CTRLHANDLED: 466 | begin 467 | AMessage.Result := 1; 468 | Exit; 469 | end; 470 | AC_SETNEWSKIN: 471 | if ACUInt(AMessage.LParam) = ACUInt(SkinData.SkinManager) then 472 | begin 473 | CommonMessage(AMessage, FSkinData); 474 | Exit; 475 | end; 476 | AC_REMOVESKIN: 477 | if ACUInt(AMessage.LParam) = ACUInt(SkinData.SkinManager) then 478 | begin 479 | if Assigned(FScrollWnd) then 480 | begin 481 | FreeAndNil(FScrollWnd); 482 | RecreateWnd; 483 | end; 484 | 485 | Exit; 486 | end; 487 | AC_REFRESH: 488 | if RefreshNeeded(SkinData, AMessage) then 489 | begin 490 | RefreshEditScrolls(SkinData, FScrollWnd); 491 | CommonMessage(AMessage, FSkinData); 492 | 493 | if HandleAllocated and Visible then 494 | RedrawWindow(Handle, nil, 0, RDWA_REPAINT); 495 | 496 | Exit; 497 | end; 498 | AC_GETDEFSECTION: 499 | begin 500 | AMessage.Result := 1; 501 | Exit; 502 | end; 503 | AC_GETDEFINDEX: 504 | begin 505 | if Assigned(FSkinData.SkinManager) then 506 | AMessage.Result := FSkinData.SkinManager.SkinCommonInfo.Sections[ssEdit] + 1; 507 | 508 | Exit; 509 | end; 510 | AC_SETGLASSMODE: 511 | begin 512 | CommonMessage(AMessage, FSkinData); 513 | Exit; 514 | end; 515 | end; 516 | 517 | if not ControlIsReady(Self) or not Assigned(FSkinData) or not FSkinData.Skinned then 518 | inherited 519 | else 520 | begin 521 | case AMessage.Msg of 522 | WM_ERASEBKGND: 523 | if (SkinData.SkinIndex >= 0) and InUpdating(FSkinData) then 524 | Exit; 525 | WM_PAINT: 526 | begin 527 | if InUpdating(FSkinData) then 528 | begin 529 | BeginPaint(Handle, LPaintStruct); 530 | EndPaint(Handle, LPaintStruct); 531 | end 532 | else 533 | inherited; 534 | 535 | Exit; 536 | end; 537 | end; 538 | 539 | if CommonWndProc(AMessage, FSkinData) then 540 | Exit; 541 | 542 | inherited; 543 | 544 | case AMessage.Msg of 545 | CM_SHOWINGCHANGED: 546 | RefreshEditScrolls(SkinData, FScrollWnd); 547 | CM_VISIBLECHANGED, CM_ENABLEDCHANGED, WM_SETFONT: 548 | FSkinData.Invalidate; 549 | CM_TEXTCHANGED, CM_CHANGED: 550 | if Assigned(FScrollWnd) then 551 | UpdateScrolls(FScrollWnd, True); 552 | end; 553 | end; 554 | end; 555 | {$ENDIF} 556 | 557 | procedure TCustomPDFiumControl.WMEraseBkgnd(var AMessage: TWMEraseBkgnd); 558 | begin 559 | AMessage.Result := 1; 560 | end; 561 | 562 | procedure TCustomPDFiumControl.WMGetDlgCode(var AMessage: TWMGetDlgCode); 563 | begin 564 | inherited; 565 | 566 | AMessage.Result := AMessage.Result or DLGC_WANTARROWS; 567 | end; 568 | 569 | function TCustomPDFiumControl.IsCurrentPageValid: Boolean; 570 | begin 571 | Result := IsPageIndexValid(PageIndex); 572 | end; 573 | 574 | function TCustomPDFiumControl.GetCurrentPage: TPDFPage; 575 | begin 576 | Result := GetPage(PageIndex); 577 | end; 578 | 579 | procedure TCustomPDFiumControl.DoScroll(const AScrollBarKind: TScrollBarKind); 580 | begin 581 | if Assigned(FOnScroll) then 582 | FOnScroll(Self, AScrollBarKind); 583 | end; 584 | 585 | function TCustomPDFiumControl.DoMouseWheel(AShift: TShiftState; AWheelDelta: Integer; AMousePos: TPoint): Boolean; 586 | begin 587 | FChanged := True; 588 | 589 | VertScrollBar.Position := VertScrollBar.Position - AWheelDelta; 590 | UpdatePageIndex; 591 | DoScroll(sbVertical); 592 | 593 | Result := True; 594 | end; 595 | 596 | procedure TCustomPDFiumControl.WMHScroll(var AMessage: TWMHScroll); 597 | begin 598 | FChanged := True; 599 | 600 | inherited; 601 | 602 | DoScroll(sbHorizontal); 603 | Invalidate; 604 | end; 605 | 606 | procedure TCustomPDFiumControl.WMKeyDown(var AMessage: TWMKeyDown); 607 | var 608 | LShiftState: TShiftState; 609 | begin 610 | if FAllowFormFieldEdit and IsCurrentPageValid then 611 | begin 612 | LShiftState := KeyDataToShiftState(AMessage.KeyData); 613 | 614 | if CurrentPage.FormEventKeyDown(AMessage.CharCode, LShiftState) then 615 | begin 616 | case AMessage.CharCode of 617 | Ord('C'), Ord('X'), Ord('V'), VK_INSERT, VK_DELETE: 618 | begin 619 | if LShiftState = [ssCtrl] then 620 | case AMessage.CharCode of 621 | Ord('C'), VK_INSERT: 622 | CopyFormTextToClipboard; 623 | Ord('X'): 624 | CutFormTextToClipboard; 625 | Ord('V'): 626 | PasteFormTextFromClipboard; 627 | end 628 | else 629 | if LShiftState = [ssShift] then 630 | case AMessage.CharCode of 631 | VK_INSERT: 632 | PasteFormTextFromClipboard; 633 | VK_DELETE: 634 | CutFormTextToClipboard; 635 | end; 636 | end; 637 | end; 638 | end; 639 | 640 | Exit; 641 | end; 642 | 643 | inherited; 644 | end; 645 | 646 | procedure TCustomPDFiumControl.WMKeyUp(var AMessage: TWMKeyUp); 647 | begin 648 | if FAllowFormFieldEdit and IsCurrentPageValid and CurrentPage.FormEventKeyUp(AMessage.CharCode, 649 | KeyDataToShiftState(AMessage.KeyData)) then 650 | Exit; 651 | 652 | inherited; 653 | end; 654 | 655 | procedure TCustomPDFiumControl.WMChar(var AMessage: TWMChar); 656 | begin 657 | if FAllowFormFieldEdit and IsCurrentPageValid and CurrentPage.FormEventKeyPress(AMessage.CharCode, 658 | KeyDataToShiftState(AMessage.KeyData)) then 659 | Exit; 660 | 661 | inherited; 662 | end; 663 | 664 | procedure TCustomPDFiumControl.WMKillFocus(var AMessage: TWMKillFocus); 665 | begin 666 | if FAllowFormFieldEdit and IsCurrentPageValid then 667 | CurrentPage.FormEventKillFocus; 668 | 669 | inherited; 670 | end; 671 | 672 | procedure TCustomPDFiumControl.UpdatePageIndex; 673 | var 674 | LIndex: Integer; 675 | LPageIndex: Integer; 676 | LTop: Integer; 677 | begin 678 | LTop := Height div 3; 679 | LPageIndex := FPageCount - 1; 680 | 681 | { Can't use binary search. Page info rect is not always up to date - see AdjustPageInfo. } 682 | for LIndex := 0 to FPageCount - 1 do 683 | if FPageInfo[LIndex].Rect.Top >= LTop then 684 | begin 685 | LPageIndex := LIndex - 1; 686 | Break; 687 | end; 688 | 689 | PageIndex := Max(LPageIndex, 0); 690 | end; 691 | 692 | procedure TCustomPDFiumControl.WMVScroll(var AMessage: TWMVScroll); 693 | begin 694 | FChanged := True; 695 | 696 | inherited; 697 | 698 | UpdatePageIndex; 699 | DoScroll(sbVertical); 700 | 701 | Invalidate; 702 | end; 703 | 704 | procedure TCustomPDFiumControl.LoadFromFile(const AFilename: string); 705 | var 706 | LPassword: UTF8String; 707 | begin 708 | FFilename := AFilename; 709 | try 710 | FPDFDocument.LoadFromFile(AFilename); 711 | except 712 | on E: Exception do 713 | if FPDF_GetLastError = FPDF_ERR_PASSWORD then 714 | begin 715 | SetPageCount(0); 716 | LPassword := ''; 717 | 718 | if Assigned(FOnLoadProtected) then 719 | FOnLoadProtected(Self, LPassword); 720 | 721 | try 722 | FPDFDocument.LoadFromFile(AFilename, LPassword); 723 | except 724 | on E: Exception do 725 | raise; 726 | end; 727 | end 728 | else 729 | raise; 730 | end; 731 | 732 | InternalAfterLoad; 733 | 734 | if Assigned(FOnAfterLoad) then 735 | FOnAfterLoad(Self); 736 | end; 737 | 738 | procedure TCustomPDFiumControl.LoadFromStream(const AStream: TStream); 739 | var 740 | LPassword: UTF8String; 741 | begin 742 | try 743 | FPDFDocument.LoadFromStream(AStream); 744 | except 745 | on E: Exception do 746 | if FPDF_GetLastError = FPDF_ERR_PASSWORD then 747 | begin 748 | SetPageCount(0); 749 | LPassword := ''; 750 | 751 | if Assigned(FOnLoadProtected) then 752 | FOnLoadProtected(Self, LPassword); 753 | 754 | try 755 | FPDFDocument.LoadFromStream(AStream, LPassword); 756 | except 757 | on E: Exception do 758 | raise; 759 | end; 760 | end 761 | else 762 | raise; 763 | end; 764 | 765 | InternalAfterLoad; 766 | 767 | if Assigned(FOnAfterLoad) then 768 | FOnAfterLoad(Self); 769 | end; 770 | 771 | {$IFDEF USE_LOAD_FROM_URL} 772 | function CreateNetHTTPClient: TNetHTTPClient; 773 | const 774 | DefaultTimeout = 60000; 775 | begin 776 | Result := TNetHTTPClient.Create(nil); 777 | 778 | with Result do 779 | begin 780 | HandleRedirects := True; 781 | SecureProtocols := [THTTPSecureProtocol.TLS11, THTTPSecureProtocol.TLS12, THTTPSecureProtocol.TLS13]; 782 | ConnectionTimeout := DefaultTimeout; 783 | ResponseTimeout := DefaultTimeout; 784 | SendTimeout := DefaultTimeout; 785 | end; 786 | end; 787 | 788 | procedure TCustomPDFiumControl.LoadFromURL(const AURL: string); 789 | var 790 | LStream: TMemoryStream; 791 | LHTTPClient: TNetHTTPClient; 792 | begin 793 | LHTTPClient := CreateNetHTTPClient; 794 | try 795 | LStream := TMemoryStream.Create; 796 | try 797 | LHTTPClient.Get(AURL, LStream); 798 | LStream.Position := 0; 799 | LoadFromStream(LStream); 800 | finally 801 | FreeAndNil(LStream); 802 | end; 803 | finally 804 | LHTTPClient.Free; 805 | end; 806 | end; 807 | {$ENDIF} 808 | 809 | procedure TCustomPDFiumControl.InternalAfterLoad; 810 | begin 811 | ClearSearch; 812 | 813 | if Assigned(FPDFDocument) then 814 | begin 815 | SetPageCount(FPDFDocument.PageCount); 816 | GetPageWebLinks; 817 | end; 818 | 819 | FChanged := True; 820 | 821 | Invalidate; 822 | end; 823 | 824 | procedure TCustomPDFiumControl.CMGesture(var AMessage: TCMGesture); 825 | begin 826 | inherited; 827 | 828 | FChanged := True; 829 | Invalidate; 830 | end; 831 | 832 | function TCustomPDFiumControl.ZoomToScreen: Single; 833 | begin 834 | Result := FZoomPercent / 100 * Screen.PixelsPerInch / 72; 835 | end; 836 | 837 | procedure TCustomPDFiumControl.SetPageCount(const AValue: Integer); 838 | var 839 | LIndex: Integer; 840 | LPage: TPDFPage; 841 | begin 842 | FPageCount := AValue; 843 | FPageIndex := 0; 844 | FWidth := 0; 845 | FHeight := 0; 846 | 847 | if FPageCount > 0 then 848 | begin 849 | SetLength(FPageInfo, FPageCount); 850 | 851 | for LIndex := 0 to FPageCount - 1 do 852 | begin 853 | LPage := FPDFDocument.Pages[LIndex]; 854 | 855 | with FPageInfo[LIndex] do 856 | begin 857 | Width := LPage.Width; 858 | Height := LPage.Height; 859 | Rotation := prNormal; 860 | SearchCurrentIndex := -1; 861 | end; 862 | 863 | if LPage.Width > FWidth then 864 | FWidth := LPage.Width; 865 | 866 | FHeight := FHeight + LPage.Height; 867 | end; 868 | end; 869 | 870 | HorzScrollBar.Position := 0; 871 | VertScrollBar.Position := 0; 872 | SetScrollSize; 873 | end; 874 | 875 | procedure TCustomPDFiumControl.SetPageNumber(const AValue: Integer); 876 | var 877 | LValue: Integer; 878 | begin 879 | LValue := AValue - 1; 880 | 881 | if IsPageIndexValid(LValue) and (FPageIndex <> LValue) then 882 | begin 883 | FPageIndex := LValue; 884 | FChanged := True; 885 | VertScrollBar.Position := GetPageTop(FPageIndex); 886 | PageChanged; 887 | end; 888 | end; 889 | 890 | procedure TCustomPDFiumControl.SetPageIndex(const AValue: Integer); 891 | begin 892 | if FPageIndex <> AValue then 893 | begin 894 | FPageIndex := AValue; 895 | PageChanged; 896 | 897 | if Assigned(FOnPageChanged) then 898 | FOnPageChanged(Self); 899 | end; 900 | end; 901 | 902 | procedure TCustomPDFiumControl.PageChanged; 903 | begin 904 | FSelectionStartCharIndex := 0; 905 | FSelectionStopCharIndex := 0; 906 | FSelectionActive := False; 907 | 908 | GetPageWebLinks; 909 | end; 910 | 911 | procedure TCustomPDFiumControl.SetScrollSize; 912 | type 913 | TScrollInfo = record 914 | Position: Int64; 915 | Range: Int64; 916 | end; 917 | 918 | procedure SetScrollInfo(var AScrollInfo: TScrollInfo; const AScrollBar: TControlScrollBar); 919 | begin 920 | AScrollInfo.Position := AScrollBar.Position; 921 | AScrollInfo.Range := AScrollBar.Range; 922 | end; 923 | 924 | procedure SetPosition(const AScrollInfo: TScrollInfo; const AScrollBar: TControlScrollBar); 925 | begin 926 | if AScrollInfo.Range > 0 then 927 | AScrollBar.Position := AScrollBar.Range * AScrollInfo.Position div AScrollInfo.Range; 928 | end; 929 | 930 | var 931 | LZoom: Single; 932 | LHorzScrollInfo: TScrollInfo; 933 | LVertScrollInfo: TScrollInfo; 934 | begin 935 | SetScrollInfo(LHorzScrollInfo, HorzScrollBar); 936 | SetScrollInfo(LVertScrollInfo, VertScrollBar); 937 | 938 | LZoom := FZoomPercent / 100 * Screen.PixelsPerInch / 72; 939 | 940 | HorzScrollBar.Range := Round(FWidth * LZoom) + FPageMargin * 2; 941 | VertScrollBar.Range := Round(FHeight * LZoom) + FPageMargin * (FPageCount + 1); 942 | 943 | SetPosition(LHorzScrollInfo, HorzScrollBar); 944 | SetPosition(LVertScrollInfo, VertScrollBar); 945 | end; 946 | 947 | procedure TCustomPDFiumControl.SetSearchHighlightAll(const AValue: Boolean); 948 | begin 949 | FSearchHighlightAll := AValue; 950 | 951 | Invalidate; 952 | end; 953 | 954 | procedure TCustomPDFiumControl.SetZoomPercent(const AValue: Single); 955 | var 956 | LValue: Single; 957 | begin 958 | LValue := AValue; 959 | 960 | if LValue < 0.65 then 961 | LValue := 0.65 962 | else 963 | if LValue > 6400 then 964 | LValue := 6400; 965 | 966 | FZoomPercent := LValue; 967 | SetScrollSize; 968 | DoSizeChanged; 969 | end; 970 | 971 | procedure TCustomPDFiumControl.Zoom(const APercent: Single); 972 | begin 973 | FZoomMode := zmPercent; 974 | SetZoomPercent(APercent); 975 | end; 976 | 977 | procedure TCustomPDFiumControl.DoSizeChanged; 978 | begin 979 | FChanged := True; 980 | Invalidate; 981 | 982 | if Assigned(OnResize) then 983 | OnResize(Self); 984 | end; 985 | 986 | procedure TCustomPDFiumControl.SetZoomMode(const AValue: TPDFZoomMode); 987 | begin 988 | FZoomMode := AValue; 989 | AdjustZoom; 990 | end; 991 | 992 | procedure TCustomPDFiumControl.AdjustZoom; 993 | begin 994 | case FZoomMode of 995 | zmPercent: 996 | Exit; 997 | zmActualSize: 998 | SetZoomPercent(100); 999 | zmFitHeight: 1000 | SetZoomPercent(PageHeightZoomPercent); 1001 | zmFitWidth: 1002 | SetZoomPercent(PageWidthZoomPercent); 1003 | end; 1004 | end; 1005 | 1006 | procedure TCustomPDFiumControl.ClearSelection; 1007 | begin 1008 | SetSelection(False, 0, 0); 1009 | end; 1010 | 1011 | function TCustomPDFiumControl.SearchAll: Integer; 1012 | begin 1013 | Result := SearchAll(FSearchText, FSearchHighlightAll, FSearchMatchCase, FSearchWholeWords); 1014 | end; 1015 | 1016 | function TCustomPDFiumControl.SearchAll(const ASearchText: string): Integer; 1017 | begin 1018 | Result := SearchAll(ASearchText, FSearchHighlightAll, FSearchMatchCase, FSearchWholeWords); 1019 | end; 1020 | 1021 | procedure TCustomPDFiumControl.AdjustScrollBar(const APageIndex: Integer); 1022 | var 1023 | LRect: TRect; 1024 | LPageRect: TRect; 1025 | begin 1026 | with FPageInfo[APageIndex] do 1027 | begin 1028 | LPageRect := System.Types.Rect(0, 0, Round(Width), Round(Height)); 1029 | LRect := InternPageToDevice(FPDFDocument.Pages[APageIndex], SearchRects[SearchCurrentIndex], LPageRect); 1030 | VertScrollBar.Position := GetPageTop(APageIndex) + Round( (VertScrollBar.Range / PageCount) * 1031 | LRect.Top / LPageRect.Height ) - 2 * LRect.Height; 1032 | end; 1033 | 1034 | FChanged := True; 1035 | end; 1036 | 1037 | function TCustomPDFiumControl.SearchAll(const ASearchText: string; const AHighlightAll: Boolean; const AMatchCase: Boolean; 1038 | const AWholeWords: Boolean; const AScrollIntoView: Boolean = True; const APageIndex: Integer = -1): Integer; 1039 | var 1040 | LCount, LRectCount: Integer; 1041 | LCharIndex, LCharCount: Integer; 1042 | LIndex, LPageIndex: Integer; 1043 | LPage: TPDFPage; 1044 | LSearchText: string; 1045 | LFromPage, LToPage: Integer; 1046 | begin 1047 | Result := 0; 1048 | 1049 | FSearchText := ASearchText; 1050 | FSearchHighlightAll := AHighlightAll; 1051 | FSearchMatchCase := AMatchCase; 1052 | FSearchWholeWords := AWholeWords; 1053 | 1054 | ClearSearch; 1055 | FSearchIndex := 0; 1056 | 1057 | if IsCurrentPageValid then 1058 | begin 1059 | LFromPage := IfThen(APageIndex = -1, 0, APageIndex); 1060 | LToPage := IfThen(APageIndex = -1, FPageCount - 1, APageIndex); 1061 | 1062 | for LPageIndex := LFromPage to LToPage do 1063 | with FPageInfo[LPageIndex] do 1064 | begin 1065 | LPage := FPDFDocument.Pages[LPageIndex]; 1066 | 1067 | LCount := 0; 1068 | 1069 | if not FSearchText.IsEmpty then 1070 | begin 1071 | LSearchText := FSearchText; 1072 | 1073 | if not FSearchMatchCase then 1074 | LSearchText := LSearchText.ToLower; { Bug in PDFium } 1075 | 1076 | if LPage.BeginFind(LSearchText, FSearchMatchCase, FSearchWholeWords, False) then 1077 | try 1078 | while LPage.FindNext(LCharIndex, LCharCount) do 1079 | begin 1080 | LRectCount := LPage.GetTextRectCount(LCharIndex, LCharCount); 1081 | 1082 | if LCount + LRectCount > Length(SearchRects) then 1083 | SetLength(SearchRects, (LCount + LRectCount) * 2); 1084 | 1085 | for LIndex := 0 to LRectCount - 1 do 1086 | begin 1087 | SearchRects[LCount] := LPage.GetTextRect(LIndex); 1088 | Inc(LCount); 1089 | end; 1090 | 1091 | Inc(Result); 1092 | end; 1093 | finally 1094 | LPage.EndFind; 1095 | end; 1096 | 1097 | if LCount <> Length(SearchRects) then 1098 | SetLength(SearchRects, LCount); 1099 | 1100 | if Length(SearchRects) > 0 then 1101 | TArray.Sort(SearchRects, TComparer.Construct( 1102 | function (const ALeft, ARight: TPDFRect): Integer 1103 | begin 1104 | Result := Trunc(ARight.Top) - Trunc(ALeft.Top); 1105 | 1106 | if Result = 0 then 1107 | Result := Trunc(ALeft.Left) - Trunc(ARight.Left); 1108 | end) 1109 | ); 1110 | end; 1111 | end; 1112 | 1113 | for LPageIndex := LFromPage to LToPage do 1114 | with FPageInfo[LPageIndex] do 1115 | if Length(SearchRects) > 0 then 1116 | begin 1117 | SearchCurrentIndex := 0; 1118 | 1119 | if AScrollIntoView then 1120 | begin 1121 | GoToPage(LPageIndex, False); 1122 | AdjustScrollBar(LPageIndex); 1123 | end; 1124 | 1125 | Break; 1126 | end; 1127 | end; 1128 | 1129 | FSearchCount := Result; 1130 | 1131 | Invalidate; 1132 | end; 1133 | 1134 | function TCustomPDFiumControl.GetPage(const AIndex: Integer): TPDFPage; 1135 | begin 1136 | if IsPageIndexValid(AIndex) then 1137 | Result := FPDFDocument.Pages[AIndex] 1138 | else 1139 | Result := nil; 1140 | end; 1141 | 1142 | function TCustomPDFiumControl.FindNext: Integer; 1143 | var 1144 | LPageIndex: Integer; 1145 | LNextPage: Boolean; 1146 | begin 1147 | Result := FSearchIndex; 1148 | 1149 | if FSearchIndex + 1 >= FSearchCount then 1150 | Exit; 1151 | 1152 | Inc(FSearchIndex); 1153 | 1154 | LNextPage := False; 1155 | 1156 | for LPageIndex := 0 to FPageCount - 1 do 1157 | with FPageInfo[LPageIndex] do 1158 | begin 1159 | if LNextPage and (Length(SearchRects) > 0) then 1160 | begin 1161 | SearchCurrentIndex := 0; 1162 | Break; 1163 | end 1164 | else 1165 | if SearchCurrentIndex <> -1 then 1166 | begin 1167 | if SearchCurrentIndex + 1 < Length(SearchRects) then 1168 | begin 1169 | Inc(SearchCurrentIndex); 1170 | Break; 1171 | end 1172 | else 1173 | begin 1174 | SearchCurrentIndex := -1; 1175 | LNextPage := True; 1176 | end; 1177 | end; 1178 | end; 1179 | 1180 | GoToPage(LPageIndex, False); 1181 | AdjustScrollBar(LPageIndex); 1182 | 1183 | Result := FSearchIndex; 1184 | 1185 | Invalidate; 1186 | end; 1187 | 1188 | function TCustomPDFiumControl.FindPrevious: Integer; 1189 | var 1190 | LPageIndex: Integer; 1191 | LPreviousPage: Boolean; 1192 | begin 1193 | Result := FSearchIndex; 1194 | 1195 | if FSearchIndex - 1 < 0 then 1196 | Exit; 1197 | 1198 | Dec(FSearchIndex); 1199 | 1200 | LPreviousPage := False; 1201 | 1202 | for LPageIndex := FPageCount - 1 downto 0 do 1203 | with FPageInfo[LPageIndex] do 1204 | begin 1205 | if LPreviousPage and (Length(SearchRects) > 0) then 1206 | begin 1207 | SearchCurrentIndex := Length(SearchRects) - 1; 1208 | Break; 1209 | end 1210 | else 1211 | if SearchCurrentIndex <> -1 then 1212 | begin 1213 | if SearchCurrentIndex - 1 >= 0 then 1214 | begin 1215 | Dec(SearchCurrentIndex); 1216 | Break; 1217 | end 1218 | else 1219 | begin 1220 | SearchCurrentIndex := -1; 1221 | LPreviousPage := True; 1222 | end; 1223 | end; 1224 | end; 1225 | 1226 | GoToPage(LPageIndex, False); 1227 | AdjustScrollBar(LPageIndex); 1228 | 1229 | Result := FSearchIndex; 1230 | 1231 | Invalidate; 1232 | end; 1233 | 1234 | procedure TCustomPDFiumControl.ClearSearch; 1235 | var 1236 | LIndex: Integer; 1237 | begin 1238 | SearchCount := 0; 1239 | SearchIndex := 0; 1240 | 1241 | if IsCurrentPageValid then 1242 | for LIndex := 0 to FPageCount - 1 do 1243 | begin 1244 | SetLength(FPageInfo[LIndex].SearchRects, 0); 1245 | FPageInfo[LIndex].SearchCurrentIndex := -1; 1246 | end; 1247 | end; 1248 | 1249 | procedure TCustomPDFiumControl.SaveToFile(const AFilename: string; const AOption: TPdfDocumentSaveOption = dsoRemoveSecurity; const AFileVersion: Integer = -1); 1250 | begin 1251 | FPDFDocument.SaveToFile(AFilename, AOption, AFileVersion); 1252 | end; 1253 | 1254 | procedure TCustomPDFiumControl.SaveToStream(const AStream: TStream; const AOption: TPdfDocumentSaveOption = dsoRemoveSecurity; const AFileVersion: Integer = -1); 1255 | begin 1256 | FPDFDocument.SaveToStream(AStream, AOption, AFileVersion); 1257 | end; 1258 | 1259 | procedure TCustomPDFiumControl.SelectAll; 1260 | begin 1261 | SelectText(0, -1); 1262 | end; 1263 | 1264 | procedure TCustomPDFiumControl.SelectAllFormText; 1265 | begin 1266 | if FFormFieldFocused and IsCurrentPageValid then 1267 | CurrentPage.FormSelectAllText; 1268 | end; 1269 | 1270 | procedure TCustomPDFiumControl.SelectText(const ACharIndex: Integer; const ACount: Integer); 1271 | begin 1272 | if (ACount = 0) or not IsCurrentPageValid then 1273 | ClearSelection 1274 | else 1275 | begin 1276 | if ACount = -1 then 1277 | SetSelection(True, 0, CurrentPage.GetCharCount - 1) 1278 | else 1279 | SetSelection(True, ACharIndex, Min(ACharIndex + ACount - 1, CurrentPage.GetCharCount - 1)); 1280 | end; 1281 | end; 1282 | 1283 | procedure TCustomPDFiumControl.CloseDocument; 1284 | begin 1285 | FPDFDocument.Close; 1286 | SetPageCount(0); 1287 | FFormFieldFocused := False; 1288 | Invalidate; 1289 | end; 1290 | 1291 | procedure TCustomPDFiumControl.CopyFormTextToClipboard; 1292 | var 1293 | LText: string; 1294 | begin 1295 | if FFormFieldFocused and IsCurrentPageValid then 1296 | begin 1297 | LText := CurrentPage.FormGetSelectedText; 1298 | if not LText.IsEmpty then 1299 | Clipboard.AsText := LText; 1300 | end; 1301 | end; 1302 | 1303 | procedure TCustomPDFiumControl.CutFormTextToClipboard; 1304 | begin 1305 | if FFormFieldFocused and IsCurrentPageValid then 1306 | begin 1307 | CopyFormTextToClipboard; 1308 | CurrentPage.FormReplaceSelection(''); 1309 | end; 1310 | end; 1311 | procedure TCustomPDFiumControl.PasteFormTextFromClipboard; 1312 | begin 1313 | if FFormFieldFocused and IsCurrentPageValid then 1314 | begin 1315 | Clipboard.Open; 1316 | try 1317 | if Clipboard.HasFormat(CF_UNICODETEXT) or Clipboard.HasFormat(CF_TEXT) then 1318 | CurrentPage.FormReplaceSelection(Clipboard.AsText); 1319 | finally 1320 | Clipboard.Close; 1321 | end; 1322 | end; 1323 | end; 1324 | 1325 | procedure TCustomPDFiumControl.CopyToClipboard; 1326 | begin 1327 | Clipboard.AsText := GetSelectionText; 1328 | end; 1329 | 1330 | function TCustomPDFiumControl.GetPageNumber: Integer; 1331 | begin 1332 | Result := FPageIndex + 1; 1333 | end; 1334 | 1335 | function TCustomPDFiumControl.PageToScreen(const AValue: Single): Integer; 1336 | begin 1337 | Result := Round(AValue * ZoomToScreen); 1338 | end; 1339 | 1340 | function TCustomPDFiumControl.GetPageTop(const APageIndex: Integer): Integer; 1341 | var 1342 | LY: Double; 1343 | LPageIndex: Integer; 1344 | begin 1345 | LPageIndex := APageIndex; 1346 | LY := 0; 1347 | 1348 | Result := LPageIndex * FPageMargin; 1349 | 1350 | while LPageIndex > 0 do 1351 | begin 1352 | Dec(LPageIndex); 1353 | LY := LY + FPageInfo[LPageIndex].Height; 1354 | end; 1355 | 1356 | Inc(Result, PageToScreen(LY)); 1357 | end; 1358 | 1359 | procedure TCustomPDFiumControl.GoToPage(const AIndex: Integer; const ASetScrollBar: Boolean = True); 1360 | begin 1361 | if FPageIndex = AIndex then 1362 | Exit; 1363 | 1364 | if IsPageIndexValid(AIndex) then 1365 | begin 1366 | PageIndex := AIndex; 1367 | FChanged := True; 1368 | 1369 | if ASetScrollBar then 1370 | VertScrollBar.Position := GetPageTop(AIndex); 1371 | 1372 | DoScroll(sbVertical); 1373 | end; 1374 | end; 1375 | 1376 | procedure TCustomPDFiumControl.AdjustPageInfo; 1377 | var 1378 | LIndex: Integer; 1379 | LTop: Double; 1380 | LScale: Double; 1381 | LClient: TRect; 1382 | LRect: TRect; 1383 | LMargin: Integer; 1384 | begin 1385 | for LIndex := 0 to FPageCount - 1 do 1386 | FPageInfo[LIndex].Visible := 0; 1387 | 1388 | LClient := ClientRect; 1389 | LTop := 0; 1390 | LMargin := FPageMargin; 1391 | LScale := FZoomPercent / 100 * Screen.PixelsPerInch / 72; 1392 | 1393 | for LIndex := 0 to FPageCount - 1 do 1394 | begin 1395 | LRect.Top := Round(LTop * LScale) + LMargin - VertScrollBar.Position; 1396 | LRect.Left := FPageMargin + Round((FWidth - FPageInfo[LIndex].Width) / 2 * LScale) - HorzScrollBar.Position; 1397 | LRect.Width := Round(FPageInfo[LIndex].Width * LScale); 1398 | LRect.Height := Round(FPageInfo[LIndex].Height * LScale); 1399 | 1400 | if LRect.Width < LClient.Width - 2 * FPageMargin then 1401 | LRect.Offset((LClient.Width - LRect.Width) shr 1 - LRect.Left, 0); 1402 | 1403 | FPageInfo[LIndex].Rect := LRect; 1404 | 1405 | if LRect.IntersectsWith(LClient) then 1406 | FPageInfo[LIndex].Visible := 1; 1407 | 1408 | if LRect.Top > LClient.Bottom then 1409 | Break; 1410 | 1411 | LTop := LTop + FPageInfo[LIndex].Height; 1412 | Inc(LMargin, FPageMargin); 1413 | end; 1414 | end; 1415 | 1416 | function TCustomPDFiumControl.GetSelectionText: string; 1417 | begin 1418 | if FSelectionActive and IsCurrentPageValid then 1419 | Result := CurrentPage.ReadText(SelectionStart, SelectionLength) 1420 | else 1421 | Result := ''; 1422 | end; 1423 | 1424 | function TCustomPDFiumControl.GetSelectionLength: Integer; 1425 | begin 1426 | if FSelectionActive and IsCurrentPageValid then 1427 | Result := Abs(FSelectionStartCharIndex - FSelectionStopCharIndex) + 1 1428 | else 1429 | Result := 0; 1430 | end; 1431 | 1432 | function TCustomPDFiumControl.GetSelectionStart: Integer; 1433 | begin 1434 | if FSelectionActive and IsCurrentPageValid then 1435 | Result := Min(FSelectionStartCharIndex, FSelectionStopCharIndex) 1436 | else 1437 | Result := 0; 1438 | end; 1439 | 1440 | function TCustomPDFiumControl.GetSelectionRects: TPDFControlRectArray; 1441 | var 1442 | LCount: Integer; 1443 | LIndex: Integer; 1444 | LPage: TPDFPage; 1445 | begin 1446 | if FSelectionActive and HandleAllocated then 1447 | begin 1448 | LPage := CurrentPage; 1449 | 1450 | if Assigned(LPage) then 1451 | begin 1452 | LCount := CurrentPage.GetTextRectCount(SelectionStart, SelectionLength); 1453 | SetLength(Result, LCount); 1454 | 1455 | for LIndex := 0 to LCount - 1 do 1456 | Result[LIndex] := InternPageToDevice(LPage, LPage.GetTextRect(LIndex), FPageInfo[FPageIndex].Rect); 1457 | 1458 | Exit; 1459 | end; 1460 | end; 1461 | 1462 | Result := nil; 1463 | end; 1464 | 1465 | procedure TCustomPDFiumControl.InvalidateRectDiffs(const AOldRects, ANewRects: TPDFControlRectArray); 1466 | 1467 | function ContainsRect(const Rects: TPDFControlRectArray; const ARect: TRect): Boolean; 1468 | var 1469 | LIndex: Integer; 1470 | begin 1471 | Result := True; 1472 | 1473 | for LIndex := 0 to Length(Rects) - 1 do 1474 | if EqualRect(Rects[LIndex], ARect) then 1475 | Exit; 1476 | 1477 | Result := False; 1478 | end; 1479 | 1480 | var 1481 | LIndex: Integer; 1482 | begin 1483 | if HandleAllocated then 1484 | begin 1485 | for LIndex := 0 to Length(AOldRects) - 1 do 1486 | if not ContainsRect(ANewRects, AOldRects[LIndex]) then 1487 | InvalidateRect(Handle, @AOldRects[LIndex], True); 1488 | 1489 | for LIndex := 0 to Length(ANewRects) - 1 do 1490 | if not ContainsRect(AOldRects, ANewRects[LIndex]) then 1491 | InvalidateRect(Handle, @ANewRects[LIndex], True); 1492 | end; 1493 | end; 1494 | 1495 | procedure TCustomPDFiumControl.SetSelection(const AActive: Boolean; const AStartIndex, AStopIndex: Integer); 1496 | var 1497 | LOldRects, LNewRects: TPDFControlRectArray; 1498 | begin 1499 | if (AActive <> FSelectionActive) or (AStartIndex <> FSelectionStartCharIndex) or (AStopIndex <> FSelectionStopCharIndex) then 1500 | begin 1501 | LOldRects := GetSelectionRects; 1502 | 1503 | FSelectionStartCharIndex := AStartIndex; 1504 | FSelectionStopCharIndex := AStopIndex; 1505 | FSelectionActive := AActive and (FSelectionStartCharIndex >= 0) and (FSelectionStopCharIndex >= 0); 1506 | 1507 | LNewRects := GetSelectionRects; 1508 | 1509 | InvalidateRectDiffs(LOldRects, LNewRects); 1510 | end; 1511 | end; 1512 | 1513 | function TCustomPDFiumControl.SelectWord(const ACharIndex: Integer): Boolean; 1514 | var 1515 | LChar: Char; 1516 | LStartCharIndex, LStopCharIndex, LCharCount: Integer; 1517 | LPage: TPDFPage; 1518 | LCharIndex: Integer; 1519 | begin 1520 | Result := False; 1521 | 1522 | LPage := CurrentPage; 1523 | if Assigned(LPage) then 1524 | begin 1525 | ClearSelection; 1526 | LCharCount := LPage.GetCharCount; 1527 | LCharIndex := ACharIndex; 1528 | 1529 | if (LCharIndex >= 0) and (LCharIndex < LCharCount) then 1530 | begin 1531 | while (LCharIndex < LCharCount) and CurrentPage.ReadChar(LCharIndex).IsWhiteSpace do 1532 | Inc(LCharIndex); 1533 | 1534 | if LCharIndex < LCharCount then 1535 | begin 1536 | LStartCharIndex := LCharIndex - 1; 1537 | 1538 | while LStartCharIndex >= 0 do 1539 | begin 1540 | LChar := CurrentPage.ReadChar(LStartCharIndex); 1541 | 1542 | if LChar.IsWhiteSpace then 1543 | Break; 1544 | 1545 | Dec(LStartCharIndex); 1546 | end; 1547 | 1548 | Inc(LStartCharIndex); 1549 | 1550 | LStopCharIndex := LCharIndex + 1; 1551 | while LStopCharIndex < LCharCount do 1552 | begin 1553 | LChar := CurrentPage.ReadChar(LStopCharIndex); 1554 | 1555 | if LChar.IsWhiteSpace then 1556 | Break; 1557 | 1558 | Inc(LStopCharIndex); 1559 | end; 1560 | 1561 | Dec(LStopCharIndex); 1562 | 1563 | SetSelection(True, LStartCharIndex, LStopCharIndex); 1564 | Result := True; 1565 | end; 1566 | end; 1567 | end; 1568 | end; 1569 | 1570 | procedure TCustomPDFiumControl.MouseDown(AButton: TMouseButton; AShift: TShiftState; X, Y: Integer); 1571 | var 1572 | LPoint: TPDFPoint; 1573 | LCharIndex: Integer; 1574 | LPage: TPdfPage; 1575 | begin 1576 | inherited MouseDown(AButton, AShift, X, Y); 1577 | 1578 | if AButton = mbLeft then 1579 | begin 1580 | SetFocus; 1581 | 1582 | FMousePressed := True; 1583 | FMouseDownPoint := Point(X, Y); // used to find out if the selection must be cleared or not 1584 | end; 1585 | 1586 | if IsCurrentPageValid then 1587 | begin 1588 | LPage := CurrentPage; 1589 | 1590 | if FAllowFormFieldEdit then 1591 | begin 1592 | LPoint := DeviceToPage(X, Y); 1593 | if AButton = mbLeft then 1594 | begin 1595 | if LPage.FormEventLButtonDown(AShift, LPoint.X, LPoint.Y) then 1596 | Exit; 1597 | end 1598 | else 1599 | if AButton = mbRight then 1600 | begin 1601 | if LPage.FormEventFocus(AShift, LPoint.X, LPoint.Y) then 1602 | Exit; 1603 | 1604 | if LPage.FormEventRButtonDown(AShift, LPoint.X, LPoint.Y) then 1605 | Exit; 1606 | end; 1607 | end; 1608 | 1609 | if AllowTextSelection and not FFormFieldFocused and (AButton = mbLeft) then 1610 | begin 1611 | LPoint := DeviceToPage(X, Y); 1612 | LCharIndex := LPage.GetCharIndexAt(LPoint.X, LPoint.Y, MAXWORD, MAXWORD); 1613 | 1614 | if ssDouble in AShift then 1615 | begin 1616 | FMousePressed := False; 1617 | SelectWord(LCharIndex); 1618 | end 1619 | else 1620 | SetSelection(False, LCharIndex, LCharIndex); 1621 | end; 1622 | end; 1623 | end; 1624 | 1625 | function TCustomPDFiumControl.GetPageIndexAt(const APoint: TPoint): Integer; 1626 | var 1627 | LIndex: Integer; 1628 | begin 1629 | Result := FPageIndex; 1630 | 1631 | if APoint.Y > 5 then 1632 | for LIndex := 0 to FPageCount - 1 do 1633 | if FPageInfo[LIndex].Rect.Contains(APoint) then 1634 | Exit(LIndex); 1635 | end; 1636 | 1637 | procedure TCustomPDFiumControl.MouseMove(AShift: TShiftState; X, Y: Integer); 1638 | var 1639 | LPoint: TPDFPoint; 1640 | LPage: TPdfPage; 1641 | LCursor: TCursor; 1642 | LPageIndex: Integer; 1643 | LURL: string; 1644 | LRect: TRect; 1645 | begin 1646 | inherited MouseMove(AShift, X, Y); 1647 | 1648 | if not Assigned(FPDFDocument) or not FPDFDocument.Active then 1649 | Exit; 1650 | 1651 | LPageIndex := GetPageIndexAt(Point(X, Y)); 1652 | 1653 | if LPageIndex <> FPageIndex then 1654 | PageIndex := LPageIndex; 1655 | 1656 | LCursor := Cursor; 1657 | try 1658 | if FAllowFormFieldEdit and IsCurrentPageValid then 1659 | begin 1660 | LPoint := DeviceToPage(X, Y); 1661 | LPage := CurrentPage; 1662 | 1663 | if LPage.FormEventMouseMove(AShift, LPoint.X, LPoint.Y) then 1664 | case LPage.HasFormFieldAtPoint(LPoint.X, LPoint.Y) of 1665 | fftTextField: 1666 | LCursor := crIBeam; 1667 | fftComboBox, fftSignature: 1668 | LCursor := crHandPoint; 1669 | else 1670 | LCursor := crDefault; 1671 | end; 1672 | end; 1673 | 1674 | if AllowTextSelection and not FFormFieldFocused then 1675 | begin 1676 | if FMousePressed then 1677 | begin 1678 | if SetSelStopCharIndex(X, Y) then 1679 | if LCursor <> crIBeam then 1680 | begin 1681 | LCursor := crIBeam; 1682 | Cursor := LCursor; 1683 | SetCursor(Screen.Cursors[Cursor]); { Show the mouse cursor change immediately } 1684 | end; 1685 | end 1686 | else 1687 | if IsCurrentPageValid then 1688 | begin 1689 | LPoint := DeviceToPage(X, Y); 1690 | 1691 | if Assigned(FOnClickLink) and IsWebLinkAt(X, Y) then 1692 | LCursor := crHandPoint 1693 | else 1694 | if Assigned(FOnClickLink) and IsAnnotationLinkAt(X, Y, LURL, LPageIndex, LRect) then 1695 | begin 1696 | LCursor := crHandPoint; 1697 | 1698 | if not LURL.IsEmpty then 1699 | ShowHint(LURL, LRect); 1700 | end 1701 | else 1702 | if CurrentPage.GetCharIndexAt(LPoint.X, LPoint.Y, 5, 5) >= 0 then 1703 | LCursor := crIBeam 1704 | else 1705 | if Cursor <> crDefault then 1706 | begin 1707 | LCursor := crDefault; 1708 | HideHint; 1709 | end; 1710 | end; 1711 | end; 1712 | finally 1713 | if LCursor <> Cursor then 1714 | Cursor := LCursor; 1715 | end; 1716 | end; 1717 | 1718 | procedure TCustomPDFiumControl.MouseUp(AButton: TMouseButton; AShift: TShiftState; X, Y: Integer); 1719 | var 1720 | LPage: TPdfPage; 1721 | LPoint: TPDFPoint; 1722 | LURL: string; 1723 | LRect: TRect; 1724 | LPageIndex: Integer; 1725 | begin 1726 | inherited MouseUp(AButton, AShift, X, Y); 1727 | 1728 | if FAllowFormFieldEdit and IsCurrentPageValid then 1729 | begin 1730 | LPoint := DeviceToPage(X, Y); 1731 | LPage := CurrentPage; 1732 | 1733 | if (AButton = mbLeft) and LPage.FormEventLButtonUp(AShift, LPoint.X, LPoint.Y) then 1734 | begin 1735 | if FMousePressed and (AButton = mbLeft) then 1736 | FMousePressed := False; 1737 | 1738 | Exit; 1739 | end; 1740 | 1741 | if (AButton = mbRight) and LPage.FormEventRButtonUp(AShift, LPoint.X, LPoint.Y) then 1742 | Exit; 1743 | end; 1744 | 1745 | if FMousePressed and (AButton = mbLeft) then 1746 | begin 1747 | FMousePressed := False; 1748 | 1749 | if AllowTextSelection and not FFormFieldFocused then 1750 | SetSelStopCharIndex(X, Y); 1751 | 1752 | if not FSelectionActive then 1753 | if Assigned(FOnClickLink) then 1754 | begin 1755 | if IsAnnotationLinkAt(X, Y, LURL, LPageIndex, LRect) then 1756 | begin 1757 | if LPageIndex = -1 then 1758 | FOnClickLink(Self, LURL) 1759 | else 1760 | GoToPage(LPageIndex); 1761 | end 1762 | else 1763 | if IsWebLinkAt(X, Y, LURL) then 1764 | FOnClickLink(Self, LURL); 1765 | end; 1766 | end; 1767 | end; 1768 | 1769 | function TCustomPDFiumControl.DeviceToPage(const X, Y: Integer): TPDFPoint; 1770 | var 1771 | LPage: TPDFPage; 1772 | begin 1773 | LPage := CurrentPage; 1774 | 1775 | if Assigned(LPage) then 1776 | with FPageInfo[FPageIndex] do 1777 | Result := LPage.DeviceToPage(Rect.Left, Rect.Top, Rect.Width, Rect.Height, X, Y, Rotation) 1778 | else 1779 | Result := TPDFPoint.Empty; 1780 | end; 1781 | 1782 | procedure TCustomPDFiumControl.GetPageWebLinks; 1783 | var 1784 | LPage: TPDFPage; 1785 | begin 1786 | if Assigned(FWebLinksInfo) then 1787 | FreeAndNil(FWebLinksInfo); 1788 | 1789 | LPage := CurrentPage; 1790 | 1791 | if Assigned(LPage) then 1792 | FWebLinksInfo := TPdfPageWebLinksInfo.Create(LPage); 1793 | end; 1794 | 1795 | function TCustomPDFiumControl.IsWebLinkAt(const X, Y: Integer): Boolean; 1796 | var 1797 | LPoint: TPdfPoint; 1798 | begin 1799 | if Assigned(FWebLinksInfo) then 1800 | begin 1801 | LPoint := DeviceToPage(X, Y); 1802 | Result := FWebLinksInfo.IsWebLinkAt(LPoint.X, LPoint.Y); 1803 | end 1804 | else 1805 | Result := False; 1806 | end; 1807 | 1808 | { Note! There is an issue with multiline URLs in PDF - PDFium.dll returns the url using a hyphen as a word wrap separator. 1809 | The hyphen is a valid character in the url, so it can't just be removed. } 1810 | function TCustomPDFiumControl.IsWebLinkAt(const X, Y: Integer; var AURL: string): Boolean; 1811 | var 1812 | LPoint: TPDFPoint; 1813 | begin 1814 | AURL := ''; 1815 | 1816 | if Assigned(CurrentPage) and Assigned(FWebLinksInfo) then 1817 | begin 1818 | LPoint := DeviceToPage(X, Y); 1819 | Result := FWebLinksInfo.IsWebLinkAt(LPoint.X, LPoint.Y, AURL); 1820 | end 1821 | else 1822 | Result := False; 1823 | end; 1824 | 1825 | function TCustomPDFiumControl.IsAnnotationLinkAt(const X, Y: Integer; out AURL: string; out APageIndex: Integer; out ALinkRect: TRect): Boolean; 1826 | var 1827 | LPage: TPDFPage; 1828 | LPoint: TPdfPoint; 1829 | LAnnotation: TPdfAnnotation; 1830 | LLinkGotoDestination: TPdfLinkGotoDestination; 1831 | begin 1832 | Result := False; 1833 | 1834 | LPage := CurrentPage; 1835 | 1836 | APageIndex := -1; 1837 | AURL := ''; 1838 | ALinkRect := TRect.Empty; 1839 | 1840 | if Assigned(LPage) then 1841 | begin 1842 | LPoint := DeviceToPage(X, Y); 1843 | LAnnotation := LPage.GetLinkAtPoint(LPoint.X, LPoint.Y); 1844 | 1845 | if Assigned(LAnnotation) then 1846 | begin 1847 | if LAnnotation.LinkType = altGoto then 1848 | begin 1849 | if LAnnotation.GetLinkGotoDestination(LLinkGotoDestination) then 1850 | try 1851 | APageIndex := LLinkGotoDestination.PageIndex; 1852 | finally 1853 | LLinkGotoDestination.Free; 1854 | end; 1855 | end 1856 | else 1857 | AURL := LAnnotation.LinkUri; 1858 | 1859 | ALinkRect := InternPageToDevice(LPage, LAnnotation.AnnotationRect, FPageInfo[FPageIndex].Rect); 1860 | end 1861 | else 1862 | Exit; 1863 | end 1864 | else 1865 | Exit; 1866 | 1867 | Result := True; 1868 | end; 1869 | 1870 | procedure TCustomPDFiumControl.ShowHint(const AHint: string; const ARect: TRect); 1871 | var 1872 | LHintWindow: THintWindow; 1873 | LRect: TRect; 1874 | LPoint: TPoint; 1875 | begin 1876 | LHintWindow := GetHintWindow; 1877 | LRect := LHintWindow.CalcHintRect(200, AHint, nil); 1878 | LPoint := ClientToScreen(Point(ARect.Left, ARect.Bottom)); 1879 | OffsetRect(LRect, LPoint.X, LPoint.Y); 1880 | LHintWindow.ActivateHint(LRect, AHint); 1881 | LHintWindow.Update; 1882 | end; 1883 | 1884 | procedure TCustomPDFiumControl.HideHint; 1885 | begin 1886 | if Assigned(GHintWindow) then 1887 | ShowWindow(GHintWindow.Handle, SW_HIDE); 1888 | end; 1889 | 1890 | procedure TCustomPDFiumControl.GotoNextPage; 1891 | begin 1892 | GoToPage(FPageIndex + 1); 1893 | end; 1894 | 1895 | procedure TCustomPDFiumControl.WMPaint(var AMessage: TWMPaint); 1896 | begin 1897 | ControlState := ControlState + [csCustomPaint]; 1898 | 1899 | inherited; 1900 | 1901 | ControlState := ControlState - [csCustomPaint]; 1902 | end; 1903 | 1904 | function TCustomPDFiumControl.PageHeightZoomPercent: Single; 1905 | var 1906 | LScale: Single; 1907 | LZoom1, LZoom2: Single; 1908 | begin 1909 | if not IsPageIndexValid(FPageIndex) then 1910 | Exit(100); 1911 | 1912 | LScale := 72 / Screen.PixelsPerInch; 1913 | LZoom1 := (ClientWidth - 2 * FPageMargin) * LScale / FPageInfo[FPageIndex].Width; 1914 | LZoom2 := (ClientHeight - 2 * FPageMargin) * LScale / FPageInfo[FPageIndex].Height; 1915 | 1916 | if LZoom1 > LZoom2 then 1917 | LZoom1 := LZoom2; 1918 | 1919 | Result := 100 * LZoom1; 1920 | end; 1921 | 1922 | function TCustomPDFiumControl.PageWidthZoomPercent: Single; 1923 | var 1924 | LScale: Single; 1925 | begin 1926 | if not IsPageIndexValid(FPageIndex) then 1927 | Exit(100); 1928 | 1929 | LScale := 72 / Screen.PixelsPerInch; 1930 | Result := 100 * (ClientWidth - 2 * FPageMargin) * LScale / Max(FWidth, 1); 1931 | end; 1932 | 1933 | function TCustomPDFiumControl.SetSelStopCharIndex(const X, Y: Integer): Boolean; 1934 | var 1935 | LPoint: TPDFPoint; 1936 | LCharIndex: Integer; 1937 | LActive: Boolean; 1938 | LRect: TRect; 1939 | begin 1940 | if not Assigned(CurrentPage) then 1941 | Exit(False); 1942 | 1943 | LPoint := DeviceToPage(X, Y); 1944 | LCharIndex := CurrentPage.GetCharIndexAt(LPoint.X, LPoint.Y, MAXWORD, MAXWORD); 1945 | 1946 | Result := LCharIndex >= 0; 1947 | 1948 | if not Result then 1949 | LCharIndex := FSelectionStopCharIndex; 1950 | 1951 | if FSelectionStartCharIndex <> LCharIndex then 1952 | LActive := True 1953 | else 1954 | begin 1955 | LRect := InternPageToDevice(CurrentPage, CurrentPage.GetCharBox(FSelectionStartCharIndex), FPageInfo[FPageIndex].Rect); 1956 | LActive := PtInRect(LRect, FMouseDownPoint) xor PtInRect(LRect, Point(X, Y)); 1957 | end; 1958 | 1959 | SetSelection(LActive, FSelectionStartCharIndex, LCharIndex); 1960 | end; 1961 | 1962 | procedure TCustomPDFiumControl.SetFocus; 1963 | begin 1964 | if CanFocus then 1965 | begin 1966 | Winapi.Windows.SetFocus(Handle); 1967 | 1968 | inherited; 1969 | end; 1970 | end; 1971 | 1972 | procedure TCustomPDFiumControl.PaintWindow(ADC: HDC); 1973 | var 1974 | LIndex: Integer; 1975 | LPage: TPDFPage; 1976 | LBrush: HBrush; 1977 | begin 1978 | LBrush := CreateSolidBrush(Color); 1979 | try 1980 | FillRect(ADC, ClientRect, LBrush); 1981 | 1982 | if not Assigned(FPDFDocument) or (FPageCount = 0) then 1983 | Exit; 1984 | 1985 | if FChanged or (FPageCount = 0) then 1986 | begin 1987 | AdjustPageInfo; 1988 | FChanged := False; 1989 | end; 1990 | 1991 | for LIndex := 0 to FPageCount - 1 do 1992 | with FPageInfo[LIndex] do 1993 | if Visible > 0 then 1994 | begin 1995 | LPage := FPDFDocument.Pages[LIndex]; 1996 | 1997 | FillRect(ADC, Rect, LBrush); 1998 | PaintPage(ADC, LPage, LIndex); 1999 | 2000 | { Selections are drawn only to selected page without rotation. } 2001 | if (LIndex = FPageIndex) and (Rotation = prNormal) then 2002 | begin 2003 | if FSelectionActive then 2004 | PaintPageSelection(ADC, LPage, LIndex); 2005 | PaintAlphaSelection(ADC, LPage, FFormOutputSelectedRects, LIndex); 2006 | end; 2007 | 2008 | PaintPageSearchResults(ADC, LPage, LIndex); 2009 | 2010 | {$IFDEF ALPHASKINS} 2011 | if IsLightStyleColor(Color) then 2012 | {$ENDIF} 2013 | PaintPageBorder(ADC, Rect); 2014 | end; 2015 | 2016 | if Assigned(FOnPaint) then 2017 | FOnPaint(Self); 2018 | finally 2019 | DeleteObject(LBrush); 2020 | end; 2021 | end; 2022 | 2023 | procedure TCustomPDFiumControl.PaintPage(ADC: HDC; const APage: TPDFPage; const AIndex: Integer); 2024 | var 2025 | LRect: TRect; 2026 | LPoint: TPoint; 2027 | begin 2028 | with FPageInfo[AIndex] do 2029 | if (Rect.Left <> 0) or (Rect.Top <> 0) then 2030 | begin 2031 | LRect := TRect.Create(0, 0, Rect.Width, Rect.Height); 2032 | SetViewportOrgEx(ADC, Rect.Left, Rect.Top, @LPoint); 2033 | APage.Draw(ADC, LRect.Left, LRect.Top, LRect.Width, LRect.Height, Rotation, FDrawOptions); 2034 | SetViewportOrgEx(ADC, LPoint.X, LPoint.Y, nil); 2035 | end 2036 | else 2037 | FPDF_RenderPage(ADC, APage.Handle, Rect.Left, Rect.Top, Rect.Width, Rect.Height, Ord(Rotation), 0); 2038 | end; 2039 | 2040 | procedure TCustomPDFiumControl.PaintPageSelection(ADC: HDC; const APage: TPDFPage; const AIndex: Integer); 2041 | var 2042 | LCount: Integer; 2043 | LIndex: Integer; 2044 | LRects: TPDFControlPDFRectArray; 2045 | begin 2046 | LCount := APage.GetTextRectCount(SelectionStart, SelectionLength); 2047 | 2048 | if LCount > 0 then 2049 | begin 2050 | SetLength(LRects, LCount); 2051 | 2052 | for LIndex := 0 to LCount - 1 do 2053 | LRects[LIndex] := APage.GetTextRect(LIndex); 2054 | 2055 | PaintAlphaSelection(ADC, APage, LRects, AIndex); 2056 | end; 2057 | end; 2058 | 2059 | procedure TCustomPDFiumControl.PaintPage(ADC: HDC; const ARect: TRect; const AIndex: Integer); 2060 | var 2061 | LPage: TPDFPage; 2062 | begin 2063 | if FPDFDocument.Active and (AIndex < FPDFDocument.PageCount) then 2064 | begin 2065 | LPage := FPDFDocument.Pages[AIndex]; 2066 | LPage.Draw(ADC, ARect.Left, ARect.Top, ARect.Width, ARect.Height, FPageInfo[AIndex].Rotation, FDrawOptions); 2067 | end; 2068 | end; 2069 | 2070 | procedure TCustomPDFiumControl.PaintPageSearchResults(ADC: HDC; const APage: TPDFPage; const AIndex: Integer); 2071 | begin 2072 | if Length(FPageInfo[AIndex].SearchRects) > 0 then 2073 | PaintAlphaSelection(ADC, APage, FPageInfo[AIndex].SearchRects, AIndex, RGB(204, 224, 204)); 2074 | end; 2075 | 2076 | function TCustomPDFiumControl.InternPageToDevice(const APage: TPDFPage; const APageRect: TPDFRect; const ARect: TRect): TRect; 2077 | begin 2078 | Result := APage.PageToDevice(ARect.Left, ARect.Top, ARect.Width, ARect.Height, APageRect, APage.Rotation); 2079 | end; 2080 | 2081 | procedure TCustomPDFiumControl.PaintAlphaSelection(ADC: HDC; const APage: TPDFPage; const ARects: TPDFControlPDFRectArray; 2082 | const AIndex: Integer; const AColor: TColor = TColors.SysNone); 2083 | var 2084 | LCount: Integer; 2085 | LIndex: Integer; 2086 | LRect: TRect; 2087 | LDC: HDC; 2088 | LBitmap: TBitmap; 2089 | LBlendFunction: TBlendFunction; 2090 | LSearchColors: Boolean; 2091 | 2092 | function SetBrushColor: Boolean; 2093 | var 2094 | LColor: TColor; 2095 | begin 2096 | Result := True; 2097 | 2098 | LColor := AColor; 2099 | 2100 | if not LSearchColors then 2101 | LColor := RGB(204, 204, 255) 2102 | else 2103 | if FPageInfo[AIndex].SearchCurrentIndex = LIndex then 2104 | LColor := RGB(240, 204, 238) 2105 | else 2106 | if not FSearchHighlightAll then 2107 | Result := False; 2108 | 2109 | if Result and (LColor <> LBitmap.Canvas.Brush.Color) then 2110 | begin 2111 | LBitmap.Canvas.Brush.Color := LColor; 2112 | LBitmap.SetSize(100, 0); 2113 | LBitmap.SetSize(100, 50); 2114 | LDC := LBitmap.Canvas.Handle; 2115 | end; 2116 | end; 2117 | begin 2118 | LCount := Length(ARects); 2119 | 2120 | if LCount > 0 then 2121 | begin 2122 | LBitmap := TBitmap.Create; 2123 | try 2124 | LSearchColors := AColor <> TColors.SysNone; 2125 | 2126 | LBlendFunction.BlendOp := AC_SRC_OVER; 2127 | LBlendFunction.BlendFlags := 0; 2128 | LBlendFunction.SourceConstantAlpha := 128; 2129 | LBlendFunction.AlphaFormat := 0; 2130 | 2131 | for LIndex := 0 to LCount - 1 do 2132 | begin 2133 | if not SetBrushColor then 2134 | Continue; 2135 | 2136 | LRect := InternPageToDevice(APage, ARects[LIndex], FPageInfo[AIndex].Rect); 2137 | 2138 | if RectVisible(ADC, LRect) then 2139 | AlphaBlend(ADC, LRect.Left, LRect.Top, LRect.Width, LRect.Height, LDC, 0, 0, LBitmap.Width, LBitmap.Height, 2140 | LBlendFunction); 2141 | end; 2142 | finally 2143 | LBitmap.Free; 2144 | end; 2145 | end; 2146 | end; 2147 | 2148 | procedure TCustomPDFiumControl.PaintPageBorder(ADC: HDC; const ARect: TRect); 2149 | var 2150 | LPen: HPen; 2151 | begin 2152 | LPen := CreatePen(PS_SOLID, 1, FPageBorderColor); 2153 | try 2154 | SelectObject(ADC, LPen); 2155 | MoveToEx(ADC, ARect.Left, ARect.Top, nil); 2156 | LineTo(ADC, ARect.Left + ARect.Width - 1, ARect.Top); 2157 | LineTo(ADC, ARect.Left + ARect.Width - 1, ARect.Top + ARect.Height - 1); 2158 | LineTo(ADC, ARect.Left, ARect.Top + ARect.Height - 1); 2159 | LineTo(ADC, ARect.Left, ARect.top); 2160 | finally 2161 | DeleteObject(LPen); 2162 | end; 2163 | end; 2164 | 2165 | procedure TCustomPDFiumControl.GotoPreviousPage; 2166 | begin 2167 | GoToPage(FPageIndex - 1); 2168 | end; 2169 | 2170 | procedure TCustomPDFiumControl.Print; 2171 | begin 2172 | try 2173 | TPDFDocumentVclPrinter.PrintDocument(FPDFDocument, PrintJobTitle); 2174 | except 2175 | on E: Exception do 2176 | ShowError(E.Message); 2177 | end; 2178 | end; 2179 | 2180 | procedure TCustomPDFiumControl.Resize; 2181 | begin 2182 | inherited; 2183 | 2184 | AdjustZoom; 2185 | FChanged := True; 2186 | Invalidate; 2187 | end; 2188 | 2189 | function TCustomPDFiumControl.IsPageIndexValid(const APageIndex: Integer): Boolean; 2190 | begin 2191 | Result := FPDFDocument.Active and (APageIndex >= 0) and (APageIndex < FPageCount); 2192 | end; 2193 | 2194 | function TCustomPDFiumControl.IsTextSelected: Boolean; 2195 | begin 2196 | Result := SelectionLength <> 0; 2197 | end; 2198 | 2199 | procedure TCustomPDFiumControl.RotatePageClockwise; 2200 | var 2201 | LPage: TPDFPage; 2202 | begin 2203 | if FPageIndex = -1 then 2204 | Exit; 2205 | 2206 | LPage := FPDFDocument.Pages[FPageIndex]; 2207 | 2208 | with FPageInfo[FPageIndex] do 2209 | begin 2210 | Inc(Rotation); 2211 | 2212 | if Ord(Rotation) > Ord(pr90CounterClockwide) then 2213 | Rotation := prNormal; 2214 | 2215 | if Rotation in [prNormal, pr180] then 2216 | begin 2217 | Height := LPage.Height; 2218 | Width := LPage.Width; 2219 | end 2220 | else 2221 | begin 2222 | Height := LPage.Width; 2223 | Width := LPage.Height; 2224 | end; 2225 | end; 2226 | 2227 | DoSizeChanged; 2228 | end; 2229 | 2230 | procedure TCustomPDFiumControl.RotatePageCounterClockwise; 2231 | var 2232 | LPage: TPDFPage; 2233 | begin 2234 | if FPageIndex = -1 then 2235 | Exit; 2236 | 2237 | LPage := FPDFDocument.Pages[FPageIndex]; 2238 | 2239 | with FPageInfo[FPageIndex] do 2240 | begin 2241 | Dec(Rotation); 2242 | 2243 | if Ord(Rotation) < Ord(prNormal) then 2244 | Rotation := pr90CounterClockwide; 2245 | 2246 | if Rotation in [prNormal, pr180] then 2247 | begin 2248 | Height := LPage.Height; 2249 | Width := LPage.Width; 2250 | end 2251 | else 2252 | begin 2253 | Height := LPage.Width; 2254 | Width := LPage.Height; 2255 | end; 2256 | end; 2257 | 2258 | DoSizeChanged; 2259 | end; 2260 | 2261 | procedure TCustomPDFiumControl.ZoomToHeight; 2262 | begin 2263 | ZoomMode := zmFitHeight; 2264 | DoSizeChanged; 2265 | end; 2266 | 2267 | procedure TCustomPDFiumControl.ZoomToWidth; 2268 | begin 2269 | ZoomMode := zmFitWidth; 2270 | DoSizeChanged; 2271 | end; 2272 | 2273 | procedure TCustomPDFiumControl.FormOutputSelectedRect(ADocument: TPDFDocument; APage: TPDFPage; const APageRect: TPDFRect); 2274 | begin 2275 | if HandleAllocated then 2276 | begin 2277 | SetLength(FFormOutputSelectedRects, Length(FFormOutputSelectedRects) + 1); 2278 | FFormOutputSelectedRects[Length(FFormOutputSelectedRects) - 1] := APageRect; 2279 | end; 2280 | end; 2281 | 2282 | procedure TCustomPDFiumControl.FormGetCurrentPage(ADocument: TPDFDocument; var APage: TPDFPage); 2283 | begin 2284 | APage := CurrentPage; 2285 | end; 2286 | 2287 | procedure TCustomPDFiumControl.FormInvalidate(ADocument: TPdfDocument; APage: TPdfPage; const APageRect: TPdfRect); 2288 | var 2289 | LRect: TRect; 2290 | begin 2291 | FFormOutputSelectedRects := nil; 2292 | 2293 | if HandleAllocated then 2294 | begin 2295 | LRect := InternPageToDevice(APage, APageRect, FPageInfo[FPageIndex].Rect); 2296 | InvalidateRect(Handle, @LRect, True); 2297 | end; 2298 | end; 2299 | 2300 | procedure TCustomPDFiumControl.FormFieldFocus(ADocument: TPDFDocument; AValue: PWideChar; AValueLen: Integer; AFieldFocused: Boolean); 2301 | begin 2302 | ClearSelection; 2303 | FFormFieldFocused := AFieldFocused; 2304 | end; 2305 | 2306 | procedure TCustomPDFiumControl.ShowError(const AMessage: string); 2307 | begin 2308 | {$IFDEF ALPHASKINS} 2309 | sMessageDlg(AMessage, mtError, [mbOK], 0); 2310 | {$ELSE} 2311 | MessageDlg(AMessage, mtError, [mbOK], 0); 2312 | {$ENDIF} 2313 | end; 2314 | 2315 | procedure TCustomPDFiumControl.KeyDown(var Key: Word; Shift: TShiftState); 2316 | const 2317 | DefaultScrollOffset = 50; 2318 | begin 2319 | inherited KeyDown(Key, Shift); 2320 | 2321 | case Key of 2322 | VK_RIGHT, VK_LEFT, VK_UP, VK_DOWN: 2323 | FChanged := True; 2324 | end; 2325 | 2326 | case Key of 2327 | Ord('C'), VK_INSERT: 2328 | if AllowTextSelection and (Shift = [ssCtrl]) then 2329 | begin 2330 | if FSelectionActive then 2331 | CopyToClipboard; 2332 | 2333 | Key := 0; 2334 | end; 2335 | Ord('A'): 2336 | if AllowTextSelection and (Shift = [ssCtrl]) then 2337 | begin 2338 | SelectAll; 2339 | SelectAllFormText; 2340 | 2341 | Key := 0; 2342 | end; 2343 | VK_RIGHT: 2344 | HorzScrollBar.Position := HorzScrollBar.Position - DefaultScrollOffset; 2345 | VK_LEFT: 2346 | HorzScrollBar.Position := HorzScrollBar.Position + DefaultScrollOffset; 2347 | VK_UP: 2348 | VertScrollBar.Position := VertScrollBar.Position - DefaultScrollOffset; 2349 | VK_DOWN: 2350 | VertScrollBar.Position := VertScrollBar.Position + DefaultScrollOffset; 2351 | VK_PRIOR: 2352 | GotoPreviousPage; 2353 | VK_NEXT: 2354 | GotoNextPage; 2355 | VK_HOME: 2356 | GoToPage(0); 2357 | VK_END: 2358 | GoToPage(PageCount - 1); 2359 | end; 2360 | 2361 | case Key of 2362 | VK_UP, VK_DOWN: 2363 | UpdatePageIndex; 2364 | end; 2365 | 2366 | case Key of 2367 | VK_UP, VK_DOWN, VK_PRIOR, VK_NEXT, VK_HOME, VK_END: 2368 | if Assigned(OnScroll) then 2369 | OnScroll(Self, sbVertical); 2370 | end; 2371 | end; 2372 | 2373 | { TCustomPDFiumControlThumbnails } 2374 | 2375 | constructor TCustomPDFiumControlThumbnails.Create(AOwner: TComponent); 2376 | begin 2377 | inherited Create(AOwner); 2378 | 2379 | {$IFDEF ALPHASKINS} 2380 | FSkinData := TsScrollWndData.Create(Self, True); 2381 | FSkinData.COC := COC_TsDBGrid; 2382 | FSkinData.CustomFont := True; 2383 | StyleElements := [seBorder]; 2384 | {$ENDIF} 2385 | BorderStyle := bsNone; 2386 | ColCount := 1; 2387 | Color := TColors.SysWindow; 2388 | DefaultDrawing := False; 2389 | DoubleBuffered := True; 2390 | FDefaultSizeSet := False; 2391 | FixedCols := 0; 2392 | FixedRows := 0; 2393 | Options := [goFixedVertLine, goFixedHorzLine, goVertLine, goRowSelect, goThumbTracking]; 2394 | ScrollBars := System.UITypes.TScrollStyle.ssVertical; 2395 | Width := 180; 2396 | end; 2397 | 2398 | {$IFDEF ALPHASKINS} 2399 | destructor TCustomPDFiumControlThumbnails.Destroy; 2400 | begin 2401 | if Assigned(FScrollWnd) then 2402 | begin 2403 | FScrollWnd.Free; 2404 | FScrollWnd := nil; 2405 | end; 2406 | 2407 | if Assigned(FSkinData) then 2408 | begin 2409 | FSkinData.Free; 2410 | FSkinData := nil; 2411 | end; 2412 | 2413 | inherited; 2414 | end; 2415 | 2416 | procedure TCustomPDFiumControlThumbnails.AfterConstruction; 2417 | begin 2418 | inherited AfterConstruction; 2419 | 2420 | if HandleAllocated then 2421 | RefreshEditScrolls(SkinData, FScrollWnd); 2422 | 2423 | UpdateData(FSkinData); 2424 | end; 2425 | 2426 | procedure TCustomPDFiumControlThumbnails.Loaded; 2427 | begin 2428 | inherited Loaded; 2429 | 2430 | FSkinData.Loaded(False); 2431 | end; 2432 | 2433 | procedure TCustomPDFiumControlThumbnails.WndProc(var AMessage: TMessage); 2434 | var 2435 | LPaintStruct: TPaintStruct; 2436 | begin 2437 | if AMessage.Msg = SM_ALPHACMD then 2438 | case AMessage.WParamHi of 2439 | AC_CTRLHANDLED: 2440 | begin 2441 | AMessage.Result := 1; 2442 | Exit; 2443 | end; 2444 | AC_SETNEWSKIN: 2445 | if ACUInt(AMessage.LParam) = ACUInt(SkinData.SkinManager) then 2446 | begin 2447 | CommonMessage(AMessage, FSkinData); 2448 | Exit; 2449 | end; 2450 | AC_REMOVESKIN: 2451 | if ACUInt(AMessage.LParam) = ACUInt(SkinData.SkinManager) then 2452 | begin 2453 | if Assigned(FScrollWnd) then 2454 | begin 2455 | FreeAndNil(FScrollWnd); 2456 | RecreateWnd; 2457 | end; 2458 | Exit; 2459 | end; 2460 | AC_REFRESH: 2461 | if RefreshNeeded(SkinData, AMessage) then 2462 | begin 2463 | RefreshEditScrolls(SkinData, FScrollWnd); 2464 | CommonMessage(AMessage, FSkinData); 2465 | if HandleAllocated and Visible then 2466 | RedrawWindow(Handle, nil, 0, RDWA_REPAINT); 2467 | Exit; 2468 | end; 2469 | AC_GETDEFSECTION: 2470 | begin 2471 | AMessage.Result := 1; 2472 | Exit; 2473 | end; 2474 | AC_GETDEFINDEX: 2475 | begin 2476 | if Assigned(FSkinData.SkinManager) then 2477 | AMessage.Result := FSkinData.SkinManager.SkinCommonInfo.Sections[ssEdit] + 1; 2478 | Exit; 2479 | end; 2480 | AC_SETGLASSMODE: 2481 | begin 2482 | CommonMessage(AMessage, FSkinData); 2483 | Exit; 2484 | end; 2485 | end; 2486 | 2487 | if not ControlIsReady(Self) or not Assigned(FSkinData) or not FSkinData.Skinned then 2488 | inherited 2489 | else 2490 | begin 2491 | case AMessage.Msg of 2492 | WM_ERASEBKGND: 2493 | if (SkinData.SkinIndex >= 0) and InUpdating(FSkinData) then 2494 | Exit; 2495 | WM_PAINT: 2496 | begin 2497 | if InUpdating(FSkinData) then 2498 | begin 2499 | BeginPaint(Handle, LPaintStruct); 2500 | EndPaint(Handle, LPaintStruct); 2501 | end 2502 | else 2503 | inherited; 2504 | 2505 | Exit; 2506 | end; 2507 | end; 2508 | 2509 | if CommonWndProc(AMessage, FSkinData) then 2510 | Exit; 2511 | 2512 | inherited; 2513 | 2514 | case AMessage.Msg of 2515 | CM_SHOWINGCHANGED: 2516 | RefreshEditScrolls(SkinData, FScrollWnd); 2517 | CM_VISIBLECHANGED, CM_ENABLEDCHANGED, WM_SETFONT: 2518 | FSkinData.Invalidate; 2519 | CM_TEXTCHANGED, CM_CHANGED: 2520 | if Assigned(FScrollWnd) then 2521 | UpdateScrolls(FScrollWnd, True); 2522 | end; 2523 | end; 2524 | end; 2525 | {$ENDIF} 2526 | 2527 | procedure TCustomPDFiumControlThumbnails.DrawCell(ACol, ARow: Longint; ARect: TRect; AState: TGridDrawState); 2528 | var 2529 | LRect: TRect; 2530 | begin 2531 | if not Assigned(PDFiumControl) or (gdSelected in AState) and (ARow <> PDFiumControl.PageIndex) then 2532 | Exit; 2533 | 2534 | RowCount := PDFiumControl.PageCount; 2535 | 2536 | if (RowCount > 0) and not FDefaultSizeSet then 2537 | begin 2538 | SetDefaultSize; 2539 | FDefaultSizeSet := True; 2540 | end; 2541 | 2542 | if gdSelected in AState then 2543 | begin 2544 | {$IFDEF ALPHASKINS} 2545 | if FSkinData.SkinManager.Active then 2546 | begin 2547 | Canvas.Brush.Color := FSkinData.SkinManager.GetHighLightColor; 2548 | Canvas.Font.Color := FSkinData.SkinManager.GetHighLightFontColor; 2549 | end 2550 | else 2551 | begin 2552 | {$ENDIF} 2553 | Canvas.Brush.Color := TColors.SysHighlight; 2554 | Canvas.Font.Color := TColors.SysHighlightText; 2555 | {$IFDEF ALPHASKINS} 2556 | end; 2557 | {$ENDIF} 2558 | end 2559 | else 2560 | begin 2561 | {$IFDEF ALPHASKINS} 2562 | if FSkinData.SkinManager.Active then 2563 | begin 2564 | Canvas.Brush.Color := FSkinData.SkinManager.GetActiveEditColor; 2565 | Canvas.Font.Color := FSkinData.SkinManager.GetActiveEditFontColor; 2566 | end 2567 | else 2568 | begin 2569 | {$ENDIF} 2570 | Canvas.Brush.Color := TColors.SysWindow; 2571 | Canvas.Font.Color := TColors.SysWindowText; 2572 | {$IFDEF ALPHASKINS} 2573 | end; 2574 | {$ENDIF} 2575 | end; 2576 | 2577 | Canvas.FillRect(ARect); 2578 | 2579 | LRect := ARect; 2580 | InflateRect(LRect, -9, -9); 2581 | Inc(LRect.Left, 8); 2582 | 2583 | {$IFDEF ALPHASKINS} 2584 | if IsLightStyleColor(Color) then 2585 | begin 2586 | {$ENDIF} 2587 | Canvas.Pen.Color := TColors.Silver; 2588 | Canvas.Rectangle(LRect); 2589 | 2590 | InflateRect(LRect, -1, -1); 2591 | {$IFDEF ALPHASKINS} 2592 | end; 2593 | {$ENDIF} 2594 | 2595 | PDFiumControl.PaintPage(Canvas.Handle, LRect, ARow); 2596 | 2597 | Canvas.Pen.Color := TColors.Black; 2598 | Canvas.Brush.Color := TColors.SysBtnFace; 2599 | SetBkMode(Canvas.Handle, TRANSPARENT); 2600 | Canvas.Textout(ARect.Left + 2, ARect.Top, IntToStr(ARow + 1)); 2601 | SetBkMode(Canvas.Handle, OPAQUE); 2602 | end; 2603 | 2604 | { https://quality.embarcadero.com/browse/RSP-18542 } 2605 | procedure TCustomPDFiumControlThumbnails.MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); 2606 | begin 2607 | FTimerStarted := False; 2608 | 2609 | FIsMousedown := True; 2610 | try 2611 | inherited; 2612 | finally 2613 | FIsMousedown := False; 2614 | end; 2615 | 2616 | if FGridState = gsSelecting then 2617 | KillTimer(Handle, 1); 2618 | end; 2619 | 2620 | procedure TCustomPDFiumControlThumbnails.MouseMove(Shift: TShiftState; X, Y: Integer); 2621 | begin 2622 | if not FTimerStarted and (FGridState = gsSelecting) then 2623 | begin 2624 | SetTimer(Handle, 1, 60, nil); 2625 | FTimerStarted := True; 2626 | end; 2627 | 2628 | inherited; 2629 | end; 2630 | 2631 | procedure TCustomPDFiumControlThumbnails.Resize; 2632 | begin 2633 | inherited Resize; 2634 | 2635 | SetDefaultSize; 2636 | end; 2637 | 2638 | procedure TCustomPDFiumControlThumbnails.SetDefaultSize; 2639 | var 2640 | LPage: TPDFPage; 2641 | LHeigth: Integer; 2642 | begin 2643 | if not Assigned(PDFiumControl) then 2644 | Exit; 2645 | 2646 | if DefaultColWidth <> ClientWidth then 2647 | DefaultColWidth := ClientWidth; 2648 | 2649 | LPage := PDFiumControl.GetPage(0); 2650 | 2651 | if Assigned(LPage) then 2652 | begin 2653 | LHeigth := Round(((DefaultColWidth - 8) / LPage.Width) * LPage.Height); 2654 | 2655 | if DefaultRowHeight <> LHeigth then 2656 | DefaultRowHeight := LHeigth; 2657 | end; 2658 | end; 2659 | 2660 | procedure TCustomPDFiumControlThumbnails.DoPDFiumControlPageChanged(Sender: TObject); 2661 | begin 2662 | if Visible then 2663 | begin 2664 | Row := PDFiumControl.PageIndex; 2665 | Invalidate; 2666 | end; 2667 | end; 2668 | 2669 | procedure TCustomPDFiumControlThumbnails.DoPDFiumControlAfterLoad(Sender: TObject); 2670 | begin 2671 | FDefaultSizeSet := False; 2672 | end; 2673 | 2674 | procedure TCustomPDFiumControlThumbnails.SetPDFiumControl(const AValue: TPDFiumControl); 2675 | begin 2676 | FPDFiumControl := AValue; 2677 | FPDFiumControl.OnPageChanged := DoPDFiumControlPageChanged; 2678 | FPDFiumControl.OnAfterLoad := DoPDFiumControlAfterLoad; 2679 | end; 2680 | 2681 | function TCustomPDFiumControlThumbnails.SelectCell(ACol, ARow: Longint): Boolean; 2682 | begin 2683 | Result := inherited; 2684 | 2685 | if Result and FIsMousedown then 2686 | begin 2687 | FIsMousedown := False; 2688 | try 2689 | MoveColRow(ACol, ARow, True, False); 2690 | finally 2691 | FIsMousedown := True; 2692 | end; 2693 | 2694 | Result := False; 2695 | end; 2696 | 2697 | if Result and Assigned(PDFiumControl) then 2698 | PDFiumControl.GoToPage(ARow); 2699 | end; 2700 | 2701 | { TPDFDocumentVclPrinter } 2702 | 2703 | function VclAbortProc(Prn: HDC; Error: Integer): Bool; stdcall; 2704 | begin 2705 | Application.ProcessMessages; 2706 | 2707 | Result := not Printer.Aborted; 2708 | end; 2709 | 2710 | function FastVclAbortProc(Prn: HDC; Error: Integer): Bool; stdcall; 2711 | begin 2712 | Result := not Printer.Aborted; 2713 | end; 2714 | 2715 | function TPDFDocumentVclPrinter.PrinterStartDoc(const AJobTitle: string): Boolean; 2716 | begin 2717 | Result := False; 2718 | 2719 | FPagePrinted := False; 2720 | 2721 | if not Printer.Printing then 2722 | begin 2723 | if AJobTitle <> '' then 2724 | Printer.Title := AJobTitle; 2725 | 2726 | Printer.BeginDoc; 2727 | FBeginDocCalled := Printer.Printing; 2728 | Result := FBeginDocCalled; 2729 | end; 2730 | 2731 | if Result then 2732 | SetAbortProc(GetPrinterDC, @FastVclAbortProc); 2733 | end; 2734 | 2735 | procedure TPDFDocumentVclPrinter.PrinterEndDoc; 2736 | begin 2737 | if Printer.Printing and FBeginDocCalled then 2738 | Printer.EndDoc; 2739 | 2740 | SetAbortProc(GetPrinterDC, @VclAbortProc); 2741 | end; 2742 | 2743 | procedure TPDFDocumentVclPrinter.PrinterStartPage; 2744 | begin 2745 | if (Printer.PageNumber > 1) or FPagePrinted then 2746 | Printer.NewPage; 2747 | end; 2748 | 2749 | procedure TPDFDocumentVclPrinter.PrinterEndPage; 2750 | begin 2751 | FPagePrinted := True; 2752 | end; 2753 | 2754 | function TPDFDocumentVclPrinter.GetPrinterDC: HDC; 2755 | begin 2756 | Result := Printer.Handle; 2757 | end; 2758 | 2759 | class function TPDFDocumentVclPrinter.PrintDocument(const ADocument: TPDFDocument; 2760 | const AJobTitle: string; const AShowPrintDialog: Boolean = True; const AAllowPageRange: Boolean = True; 2761 | const AParentWnd: HWND = 0): Boolean; 2762 | var 2763 | LPDFDocumentVclPrinter: TPDFDocumentVclPrinter; 2764 | LPrintDialog: TPrintDialog; 2765 | LFromPage, LToPage: Integer; 2766 | begin 2767 | Result := False; 2768 | 2769 | if not Assigned(ADocument) then 2770 | Exit; 2771 | 2772 | LFromPage := 1; 2773 | LToPage := ADocument.PageCount; 2774 | 2775 | if AShowPrintDialog then 2776 | begin 2777 | LPrintDialog := TPrintDialog.Create(nil); 2778 | try 2779 | if AAllowPageRange then 2780 | begin 2781 | LPrintDialog.Options := LPrintDialog.Options + [poPageNums]; 2782 | LPrintDialog.MinPage := 1; 2783 | LPrintDialog.MaxPage := ADocument.PageCount; 2784 | LPrintDialog.ToPage := ADocument.PageCount; 2785 | end; 2786 | 2787 | if (AParentWnd = 0) or not IsWindow(AParentWnd) then 2788 | Result := LPrintDialog.Execute 2789 | else 2790 | Result := LPrintDialog.Execute(AParentWnd); 2791 | 2792 | if not Result then 2793 | Exit; 2794 | 2795 | if AAllowPageRange and (LPrintDialog.PrintRange = prPageNums) then 2796 | begin 2797 | LFromPage := LPrintDialog.FromPage; 2798 | LToPage := LPrintDialog.ToPage; 2799 | end; 2800 | { Note! Copies and collate won't work. Andy's core class needs to be fixed to get it working. 2801 | Capture here the variables and pass them to following Print function. 2802 | 2803 | LCopies := LPrintDialog.Copies; 2804 | LCollate := LPrintDialog.Collate; } 2805 | finally 2806 | LPrintDialog.Free; 2807 | end; 2808 | end; 2809 | 2810 | { Note! If the document has pages in portrait and landscape orientation, this will not work properly. The problem is 2811 | that the orientation of the printer can be changed only when outside BeginDoc and EndDoc. If there is a need for 2812 | that, then Andy's core class needs to be fixed. } 2813 | if ADocument.PageCount > 0 then 2814 | if ADocument.Pages[0].Height > ADocument.Pages[0].Width then 2815 | Printer.Orientation := poPortrait 2816 | else 2817 | Printer.Orientation := poLandscape; 2818 | 2819 | LPDFDocumentVclPrinter := TPDFDocumentVclPrinter.Create; 2820 | try 2821 | if LPDFDocumentVclPrinter.BeginPrint(AJobTitle) then 2822 | try 2823 | Result := LPDFDocumentVclPrinter.Print(ADocument, LFromPage - 1, LToPage - 1); 2824 | finally 2825 | LPDFDocumentVclPrinter.EndPrint; 2826 | end; 2827 | finally 2828 | LPDFDocumentVclPrinter.Free; 2829 | end; 2830 | end; 2831 | 2832 | end. 2833 | --------------------------------------------------------------------------------