Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(28)

Side by Side Diff: xfa/fwl/core/ifwl_edit.cpp

Issue 2524173002: Merge IFWL and CFWL classes. (Closed)
Patch Set: make chrome build happy Created 4 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2014 PDFium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6
7 #include "xfa/fwl/core/ifwl_edit.h"
8
9 #include <algorithm>
10 #include <memory>
11 #include <utility>
12 #include <vector>
13
14 #include "third_party/base/ptr_util.h"
15 #include "third_party/base/stl_util.h"
16 #include "xfa/fde/cfde_txtedtengine.h"
17 #include "xfa/fde/fde_gedevice.h"
18 #include "xfa/fde/fde_render.h"
19 #include "xfa/fde/ifde_txtedtpage.h"
20 #include "xfa/fgas/font/cfgas_gefont.h"
21 #include "xfa/fwl/core/cfwl_app.h"
22 #include "xfa/fwl/core/cfwl_caret.h"
23 #include "xfa/fwl/core/cfwl_evtcheckword.h"
24 #include "xfa/fwl/core/cfwl_evttextchanged.h"
25 #include "xfa/fwl/core/cfwl_evttextfull.h"
26 #include "xfa/fwl/core/cfwl_evtvalidate.h"
27 #include "xfa/fwl/core/cfwl_msgkey.h"
28 #include "xfa/fwl/core/cfwl_msgmouse.h"
29 #include "xfa/fwl/core/cfwl_themebackground.h"
30 #include "xfa/fwl/core/cfwl_themepart.h"
31 #include "xfa/fwl/core/cfwl_widgetmgr.h"
32 #include "xfa/fwl/core/ifwl_themeprovider.h"
33 #include "xfa/fxfa/xfa_ffdoc.h"
34 #include "xfa/fxfa/xfa_ffwidget.h"
35 #include "xfa/fxgraphics/cfx_path.h"
36
37 namespace {
38
39 const int kEditMargin = 3;
40
41 bool FX_EDIT_ISLATINWORD(FX_WCHAR c) {
42 return c == 0x2D || (c <= 0x005A && c >= 0x0041) ||
43 (c <= 0x007A && c >= 0x0061) || (c <= 0x02AF && c >= 0x00C0) ||
44 c == 0x0027;
45 }
46
47 void AddSquigglyPath(CFX_Path* pPathData,
48 FX_FLOAT fStartX,
49 FX_FLOAT fEndX,
50 FX_FLOAT fY,
51 FX_FLOAT fStep) {
52 pPathData->MoveTo(fStartX, fY);
53 int i = 1;
54 for (FX_FLOAT fx = fStartX + fStep; fx < fEndX; fx += fStep, ++i)
55 pPathData->LineTo(fx, fY + (i & 1) * fStep);
56 }
57
58 } // namespace
59
60 IFWL_Edit::IFWL_Edit(const CFWL_App* app,
61 std::unique_ptr<CFWL_WidgetProperties> properties,
62 IFWL_Widget* pOuter)
63 : IFWL_Widget(app, std::move(properties), pOuter),
64 m_fVAlignOffset(0.0f),
65 m_fScrollOffsetX(0.0f),
66 m_fScrollOffsetY(0.0f),
67 m_bLButtonDown(false),
68 m_nSelStart(0),
69 m_nLimit(-1),
70 m_fFontSize(0),
71 m_bSetRange(false),
72 m_iMax(0xFFFFFFF),
73 m_iCurRecord(-1),
74 m_iMaxRecord(128) {
75 m_rtClient.Reset();
76 m_rtEngine.Reset();
77 m_rtStatic.Reset();
78
79 InitCaret();
80 }
81
82 IFWL_Edit::~IFWL_Edit() {
83 if (m_pProperties->m_dwStates & FWL_WGTSTATE_Focused)
84 ShowCaret(false);
85 ClearRecord();
86 }
87
88 FWL_Type IFWL_Edit::GetClassID() const {
89 return FWL_Type::Edit;
90 }
91
92 void IFWL_Edit::GetWidgetRect(CFX_RectF& rect, bool bAutoSize) {
93 if (!bAutoSize) {
94 rect = m_pProperties->m_rtWidget;
95 if (m_pProperties->m_dwStyleExes & FWL_STYLEEXT_EDT_OuterScrollbar) {
96 if (IsShowScrollBar(true)) {
97 FX_FLOAT* pfWidth = static_cast<FX_FLOAT*>(
98 GetThemeCapacity(CFWL_WidgetCapacity::ScrollBarWidth));
99 rect.width += *pfWidth;
100 rect.width += kEditMargin;
101 }
102 if (IsShowScrollBar(false)) {
103 FX_FLOAT* pfWidth = static_cast<FX_FLOAT*>(
104 GetThemeCapacity(CFWL_WidgetCapacity::ScrollBarWidth));
105 rect.height += *pfWidth;
106 rect.height += kEditMargin;
107 }
108 }
109 return;
110 }
111
112 rect.Set(0, 0, 0, 0);
113
114 int32_t iTextLen = m_EdtEngine.GetTextLength();
115 if (iTextLen > 0) {
116 CFX_WideString wsText;
117 m_EdtEngine.GetText(wsText, 0);
118 CFX_SizeF sz = CalcTextSize(
119 wsText, m_pProperties->m_pThemeProvider,
120 !!(m_pProperties->m_dwStyleExes & FWL_STYLEEXT_EDT_MultiLine));
121 rect.Set(0, 0, sz.x, sz.y);
122 }
123 IFWL_Widget::GetWidgetRect(rect, true);
124 }
125
126 void IFWL_Edit::SetStates(uint32_t dwStates, bool bSet) {
127 if ((m_pProperties->m_dwStates & FWL_WGTSTATE_Invisible) ||
128 (m_pProperties->m_dwStates & FWL_WGTSTATE_Disabled)) {
129 ShowCaret(false);
130 }
131 IFWL_Widget::SetStates(dwStates, bSet);
132 }
133
134 void IFWL_Edit::Update() {
135 if (IsLocked())
136 return;
137 if (!m_pProperties->m_pThemeProvider)
138 m_pProperties->m_pThemeProvider = GetAvailableTheme();
139
140 Layout();
141 if (m_rtClient.IsEmpty())
142 return;
143
144 UpdateEditEngine();
145 UpdateVAlignment();
146 UpdateScroll();
147 InitCaret();
148 }
149
150 FWL_WidgetHit IFWL_Edit::HitTest(FX_FLOAT fx, FX_FLOAT fy) {
151 if (m_pProperties->m_dwStyleExes & FWL_STYLEEXT_EDT_OuterScrollbar) {
152 if (IsShowScrollBar(true)) {
153 CFX_RectF rect;
154 m_pVertScrollBar->GetWidgetRect(rect);
155 if (rect.Contains(fx, fy))
156 return FWL_WidgetHit::VScrollBar;
157 }
158 if (IsShowScrollBar(false)) {
159 CFX_RectF rect;
160 m_pHorzScrollBar->GetWidgetRect(rect);
161 if (rect.Contains(fx, fy))
162 return FWL_WidgetHit::HScrollBar;
163 }
164 }
165 if (m_rtClient.Contains(fx, fy))
166 return FWL_WidgetHit::Edit;
167 return FWL_WidgetHit::Unknown;
168 }
169
170 void IFWL_Edit::AddSpellCheckObj(CFX_Path& PathData,
171 int32_t nStart,
172 int32_t nCount,
173 FX_FLOAT fOffSetX,
174 FX_FLOAT fOffSetY) {
175 FX_FLOAT fStartX = 0.0f;
176 FX_FLOAT fEndX = 0.0f;
177 FX_FLOAT fY = 0.0f;
178 FX_FLOAT fStep = 0.0f;
179 IFDE_TxtEdtPage* pPage = m_EdtEngine.GetPage(0);
180 CFX_RectFArray rectArray;
181 CFX_RectF rectText;
182 const FDE_TXTEDTPARAMS* txtEdtParams = m_EdtEngine.GetEditParams();
183 FX_FLOAT fAsent = static_cast<FX_FLOAT>(txtEdtParams->pFont->GetAscent()) *
184 txtEdtParams->fFontSize / 1000;
185 pPage->CalcRangeRectArray(nStart, nCount, rectArray);
186
187 for (int i = 0; i < rectArray.GetSize(); i++) {
188 rectText = rectArray.GetAt(i);
189 fY = rectText.top + fAsent + fOffSetY;
190 fStep = txtEdtParams->fFontSize / 16.0f;
191 fStartX = rectText.left + fOffSetX;
192 fEndX = fStartX + rectText.Width();
193 AddSquigglyPath(&PathData, fStartX, fEndX, fY, fStep);
194 }
195 }
196
197 void IFWL_Edit::DrawSpellCheck(CFX_Graphics* pGraphics,
198 const CFX_Matrix* pMatrix) {
199 pGraphics->SaveGraphState();
200 if (pMatrix)
201 pGraphics->ConcatMatrix(const_cast<CFX_Matrix*>(pMatrix));
202
203 CFX_Color crLine(0xFFFF0000);
204 CFWL_EvtCheckWord checkWordEvent;
205 checkWordEvent.m_pSrcTarget = this;
206
207 CFX_ByteString sLatinWord;
208 CFX_Path pathSpell;
209 pathSpell.Create();
210
211 int32_t nStart = 0;
212 FX_FLOAT fOffSetX = m_rtEngine.left - m_fScrollOffsetX;
213 FX_FLOAT fOffSetY = m_rtEngine.top - m_fScrollOffsetY + m_fVAlignOffset;
214
215 CFX_WideString wsSpell;
216 GetText(wsSpell);
217 int32_t nContentLen = wsSpell.GetLength();
218 for (int i = 0; i < nContentLen; i++) {
219 if (FX_EDIT_ISLATINWORD(wsSpell[i])) {
220 if (sLatinWord.IsEmpty())
221 nStart = i;
222 sLatinWord += (FX_CHAR)wsSpell[i];
223 continue;
224 }
225 checkWordEvent.bsWord = sLatinWord;
226 checkWordEvent.bCheckWord = true;
227 DispatchEvent(&checkWordEvent);
228
229 if (!sLatinWord.IsEmpty() && !checkWordEvent.bCheckWord) {
230 AddSpellCheckObj(pathSpell, nStart, sLatinWord.GetLength(), fOffSetX,
231 fOffSetY);
232 }
233 sLatinWord.clear();
234 }
235
236 checkWordEvent.bsWord = sLatinWord;
237 checkWordEvent.bCheckWord = true;
238 DispatchEvent(&checkWordEvent);
239
240 if (!sLatinWord.IsEmpty() && !checkWordEvent.bCheckWord) {
241 AddSpellCheckObj(pathSpell, nStart, sLatinWord.GetLength(), fOffSetX,
242 fOffSetY);
243 }
244 if (!pathSpell.IsEmpty()) {
245 CFX_RectF rtClip = m_rtEngine;
246 CFX_Matrix mt;
247 mt.Set(1, 0, 0, 1, fOffSetX, fOffSetY);
248 if (pMatrix) {
249 pMatrix->TransformRect(rtClip);
250 mt.Concat(*pMatrix);
251 }
252 pGraphics->SetClipRect(rtClip);
253 pGraphics->SetStrokeColor(&crLine);
254 pGraphics->SetLineWidth(0);
255 pGraphics->StrokePath(&pathSpell, nullptr);
256 }
257 pGraphics->RestoreGraphState();
258 }
259
260 void IFWL_Edit::DrawWidget(CFX_Graphics* pGraphics, const CFX_Matrix* pMatrix) {
261 if (!pGraphics)
262 return;
263 if (!m_pProperties->m_pThemeProvider)
264 return;
265 if (m_rtClient.IsEmpty())
266 return;
267
268 IFWL_ThemeProvider* pTheme = m_pProperties->m_pThemeProvider;
269 if (!m_pWidgetMgr->IsFormDisabled())
270 DrawTextBk(pGraphics, pTheme, pMatrix);
271 DrawContent(pGraphics, pTheme, pMatrix);
272
273 if ((m_pProperties->m_dwStates & FWL_WGTSTATE_Focused) &&
274 !(m_pProperties->m_dwStyleExes & FWL_STYLEEXT_EDT_ReadOnly)) {
275 DrawSpellCheck(pGraphics, pMatrix);
276 }
277 if (HasBorder())
278 DrawBorder(pGraphics, CFWL_Part::Border, pTheme, pMatrix);
279 if (HasEdge())
280 DrawEdge(pGraphics, CFWL_Part::Edge, pTheme, pMatrix);
281 }
282
283 void IFWL_Edit::SetThemeProvider(IFWL_ThemeProvider* pThemeProvider) {
284 if (!pThemeProvider)
285 return;
286 if (m_pHorzScrollBar)
287 m_pHorzScrollBar->SetThemeProvider(pThemeProvider);
288 if (m_pVertScrollBar)
289 m_pVertScrollBar->SetThemeProvider(pThemeProvider);
290 if (m_pCaret)
291 m_pCaret->SetThemeProvider(pThemeProvider);
292 m_pProperties->m_pThemeProvider = pThemeProvider;
293 }
294
295 void IFWL_Edit::SetText(const CFX_WideString& wsText) {
296 m_EdtEngine.SetText(wsText);
297 }
298
299 int32_t IFWL_Edit::GetTextLength() const {
300 return m_EdtEngine.GetTextLength();
301 }
302
303 void IFWL_Edit::GetText(CFX_WideString& wsText,
304 int32_t nStart,
305 int32_t nCount) const {
306 m_EdtEngine.GetText(wsText, nStart, nCount);
307 }
308
309 void IFWL_Edit::ClearText() {
310 m_EdtEngine.ClearText();
311 }
312
313 void IFWL_Edit::AddSelRange(int32_t nStart, int32_t nCount) {
314 m_EdtEngine.AddSelRange(nStart, nCount);
315 }
316
317 int32_t IFWL_Edit::CountSelRanges() const {
318 return m_EdtEngine.CountSelRanges();
319 }
320
321 int32_t IFWL_Edit::GetSelRange(int32_t nIndex, int32_t& nStart) const {
322 return m_EdtEngine.GetSelRange(nIndex, nStart);
323 }
324
325 void IFWL_Edit::ClearSelections() {
326 m_EdtEngine.ClearSelection();
327 }
328
329 int32_t IFWL_Edit::GetLimit() const {
330 return m_nLimit;
331 }
332
333 void IFWL_Edit::SetLimit(int32_t nLimit) {
334 m_nLimit = nLimit;
335 m_EdtEngine.SetLimit(nLimit);
336 }
337
338 void IFWL_Edit::SetAliasChar(FX_WCHAR wAlias) {
339 m_EdtEngine.SetAliasChar(wAlias);
340 }
341
342 bool IFWL_Edit::Copy(CFX_WideString& wsCopy) {
343 int32_t nCount = m_EdtEngine.CountSelRanges();
344 if (nCount == 0)
345 return false;
346
347 wsCopy.clear();
348 CFX_WideString wsTemp;
349 int32_t nStart, nLength;
350 for (int32_t i = 0; i < nCount; i++) {
351 nLength = m_EdtEngine.GetSelRange(i, nStart);
352 m_EdtEngine.GetText(wsTemp, nStart, nLength);
353 wsCopy += wsTemp;
354 wsTemp.clear();
355 }
356 return true;
357 }
358
359 bool IFWL_Edit::Cut(CFX_WideString& wsCut) {
360 int32_t nCount = m_EdtEngine.CountSelRanges();
361 if (nCount == 0)
362 return false;
363
364 wsCut.clear();
365 CFX_WideString wsTemp;
366 int32_t nStart, nLength;
367 for (int32_t i = 0; i < nCount; i++) {
368 nLength = m_EdtEngine.GetSelRange(i, nStart);
369 m_EdtEngine.GetText(wsTemp, nStart, nLength);
370 wsCut += wsTemp;
371 wsTemp.clear();
372 }
373 m_EdtEngine.Delete(0);
374 return true;
375 }
376
377 bool IFWL_Edit::Paste(const CFX_WideString& wsPaste) {
378 int32_t nCaret = m_EdtEngine.GetCaretPos();
379 int32_t iError =
380 m_EdtEngine.Insert(nCaret, wsPaste.c_str(), wsPaste.GetLength());
381 if (iError < 0) {
382 ProcessInsertError(iError);
383 return false;
384 }
385 return true;
386 }
387
388 bool IFWL_Edit::Redo(const IFDE_TxtEdtDoRecord* pRecord) {
389 if (m_pProperties->m_dwStyleExes & FWL_STYLEEXT_EDT_NoRedoUndo)
390 return true;
391 return m_EdtEngine.Redo(pRecord);
392 }
393
394 bool IFWL_Edit::Undo(const IFDE_TxtEdtDoRecord* pRecord) {
395 if (m_pProperties->m_dwStyleExes & FWL_STYLEEXT_EDT_NoRedoUndo)
396 return true;
397 return m_EdtEngine.Undo(pRecord);
398 }
399
400 bool IFWL_Edit::Undo() {
401 if (!CanUndo())
402 return false;
403 return Undo(m_DoRecords[m_iCurRecord--].get());
404 }
405
406 bool IFWL_Edit::Redo() {
407 if (!CanRedo())
408 return false;
409 return Redo(m_DoRecords[++m_iCurRecord].get());
410 }
411
412 bool IFWL_Edit::CanUndo() {
413 return m_iCurRecord >= 0;
414 }
415
416 bool IFWL_Edit::CanRedo() {
417 return m_iCurRecord < pdfium::CollectionSize<int32_t>(m_DoRecords) - 1;
418 }
419
420 void IFWL_Edit::SetOuter(IFWL_Widget* pOuter) {
421 m_pOuter = pOuter;
422 }
423
424 void IFWL_Edit::On_CaretChanged(CFDE_TxtEdtEngine* pEdit,
425 int32_t nPage,
426 bool bVisible) {
427 if (m_rtEngine.IsEmpty())
428 return;
429 if ((m_pProperties->m_dwStates & FWL_WGTSTATE_Focused) == 0)
430 return;
431
432 bool bRepaintContent = UpdateOffset();
433 UpdateCaret();
434 CFX_RectF rtInvalid;
435 rtInvalid.Set(0, 0, 0, 0);
436 bool bRepaintScroll = false;
437 if (m_pProperties->m_dwStyleExes & FWL_STYLEEXT_EDT_MultiLine) {
438 CFWL_ScrollBar* pScroll = UpdateScroll();
439 if (pScroll) {
440 pScroll->GetWidgetRect(rtInvalid);
441 bRepaintScroll = true;
442 }
443 }
444 if (bRepaintContent || bRepaintScroll) {
445 if (bRepaintContent)
446 rtInvalid.Union(m_rtEngine);
447 Repaint(&rtInvalid);
448 }
449 }
450
451 void IFWL_Edit::On_TextChanged(CFDE_TxtEdtEngine* pEdit,
452 FDE_TXTEDT_TEXTCHANGE_INFO& ChangeInfo) {
453 if (m_pProperties->m_dwStyleExes & FWL_STYLEEXT_EDT_VAlignMask)
454 UpdateVAlignment();
455
456 CFX_RectF rtTemp;
457 GetClientRect(rtTemp);
458
459 CFWL_EvtTextChanged event;
460 event.m_pSrcTarget = this;
461 event.nChangeType = ChangeInfo.nChangeType;
462 event.wsInsert = ChangeInfo.wsInsert;
463 event.wsDelete = ChangeInfo.wsDelete;
464 event.wsPrevText = ChangeInfo.wsPrevText;
465 DispatchEvent(&event);
466
467 LayoutScrollBar();
468 Repaint(&rtTemp);
469 }
470
471 void IFWL_Edit::On_SelChanged(CFDE_TxtEdtEngine* pEdit) {
472 CFX_RectF rtTemp;
473 GetClientRect(rtTemp);
474 Repaint(&rtTemp);
475 }
476
477 bool IFWL_Edit::On_PageLoad(CFDE_TxtEdtEngine* pEdit,
478 int32_t nPageIndex,
479 int32_t nPurpose) {
480 IFDE_TxtEdtPage* pPage = m_EdtEngine.GetPage(nPageIndex);
481 if (!pPage)
482 return false;
483
484 pPage->LoadPage(nullptr, nullptr);
485 return true;
486 }
487
488 bool IFWL_Edit::On_PageUnload(CFDE_TxtEdtEngine* pEdit,
489 int32_t nPageIndex,
490 int32_t nPurpose) {
491 IFDE_TxtEdtPage* pPage = m_EdtEngine.GetPage(nPageIndex);
492 if (!pPage)
493 return false;
494
495 pPage->UnloadPage(nullptr);
496 return true;
497 }
498
499 void IFWL_Edit::On_AddDoRecord(CFDE_TxtEdtEngine* pEdit,
500 IFDE_TxtEdtDoRecord* pRecord) {
501 AddDoRecord(pRecord);
502 }
503
504 bool IFWL_Edit::On_Validate(CFDE_TxtEdtEngine* pEdit, CFX_WideString& wsText) {
505 IFWL_Widget* pDst = GetOuter();
506 if (!pDst)
507 pDst = this;
508
509 CFWL_EvtValidate event;
510 event.pDstWidget = pDst;
511 event.m_pSrcTarget = this;
512 event.wsInsert = wsText;
513 event.bValidate = true;
514 DispatchEvent(&event);
515 return event.bValidate;
516 }
517
518 void IFWL_Edit::SetScrollOffset(FX_FLOAT fScrollOffset) {
519 m_fScrollOffsetY = fScrollOffset;
520 }
521
522 void IFWL_Edit::DrawTextBk(CFX_Graphics* pGraphics,
523 IFWL_ThemeProvider* pTheme,
524 const CFX_Matrix* pMatrix) {
525 CFWL_ThemeBackground param;
526 param.m_pWidget = this;
527 param.m_iPart = CFWL_Part::Background;
528 param.m_bStaticBackground = false;
529 param.m_dwStates = m_pProperties->m_dwStyleExes & FWL_STYLEEXT_EDT_ReadOnly
530 ? CFWL_PartState_ReadOnly
531 : CFWL_PartState_Normal;
532 uint32_t dwStates = (m_pProperties->m_dwStates & FWL_WGTSTATE_Disabled);
533 if (dwStates)
534 param.m_dwStates = CFWL_PartState_Disabled;
535 param.m_pGraphics = pGraphics;
536 param.m_matrix = *pMatrix;
537 param.m_rtPart = m_rtClient;
538 pTheme->DrawBackground(&param);
539
540 if (!IsShowScrollBar(true) || !IsShowScrollBar(false))
541 return;
542
543 CFX_RectF rtScorll;
544 m_pHorzScrollBar->GetWidgetRect(rtScorll);
545
546 CFX_RectF rtStatic;
547 rtStatic.Set(m_rtClient.right() - rtScorll.height,
548 m_rtClient.bottom() - rtScorll.height, rtScorll.height,
549 rtScorll.height);
550 param.m_bStaticBackground = true;
551 param.m_bMaximize = true;
552 param.m_rtPart = rtStatic;
553 pTheme->DrawBackground(&param);
554 }
555
556 void IFWL_Edit::DrawContent(CFX_Graphics* pGraphics,
557 IFWL_ThemeProvider* pTheme,
558 const CFX_Matrix* pMatrix) {
559 IFDE_TxtEdtPage* pPage = m_EdtEngine.GetPage(0);
560 if (!pPage)
561 return;
562
563 pGraphics->SaveGraphState();
564 if (m_pProperties->m_dwStyleExes & FWL_STYLEEXT_EDT_CombText)
565 pGraphics->SaveGraphState();
566
567 CFX_RectF rtClip = m_rtEngine;
568 FX_FLOAT fOffSetX = m_rtEngine.left - m_fScrollOffsetX;
569 FX_FLOAT fOffSetY = m_rtEngine.top - m_fScrollOffsetY + m_fVAlignOffset;
570 CFX_Matrix mt;
571 mt.Set(1, 0, 0, 1, fOffSetX, fOffSetY);
572 if (pMatrix) {
573 pMatrix->TransformRect(rtClip);
574 mt.Concat(*pMatrix);
575 }
576
577 bool bShowSel = (m_pProperties->m_dwStyleExes & FWL_STYLEEXT_EDT_NoHideSel) ||
578 (m_pProperties->m_dwStates & FWL_WGTSTATE_Focused);
579 if (bShowSel) {
580 IFWL_Widget* pForm = m_pWidgetMgr->GetSystemFormWidget(this);
581 if (pForm) {
582 bShowSel = (pForm->GetStates() & FWL_WGTSTATE_Deactivated) !=
583 FWL_WGTSTATE_Deactivated;
584 }
585 }
586
587 int32_t nSelCount = m_EdtEngine.CountSelRanges();
588 if (bShowSel && nSelCount > 0) {
589 int32_t nPageCharStart = pPage->GetCharStart();
590 int32_t nPageCharCount = pPage->GetCharCount();
591 int32_t nPageCharEnd = nPageCharStart + nPageCharCount - 1;
592 int32_t nCharCount;
593 int32_t nCharStart;
594 CFX_RectFArray rectArr;
595 int32_t i = 0;
596 for (i = 0; i < nSelCount; i++) {
597 nCharCount = m_EdtEngine.GetSelRange(i, nCharStart);
598 int32_t nCharEnd = nCharStart + nCharCount - 1;
599 if (nCharEnd < nPageCharStart || nCharStart > nPageCharEnd)
600 continue;
601
602 int32_t nBgn = std::max(nCharStart, nPageCharStart);
603 int32_t nEnd = std::min(nCharEnd, nPageCharEnd);
604 pPage->CalcRangeRectArray(nBgn - nPageCharStart, nEnd - nBgn + 1,
605 rectArr);
606 }
607
608 int32_t nCount = rectArr.GetSize();
609 CFX_Path path;
610 path.Create();
611 for (i = 0; i < nCount; i++) {
612 rectArr[i].left += fOffSetX;
613 rectArr[i].top += fOffSetY;
614 path.AddRectangle(rectArr[i].left, rectArr[i].top, rectArr[i].width,
615 rectArr[i].height);
616 }
617 pGraphics->SetClipRect(rtClip);
618
619 CFWL_ThemeBackground param;
620 param.m_pGraphics = pGraphics;
621 param.m_matrix = *pMatrix;
622 param.m_pWidget = this;
623 param.m_iPart = CFWL_Part::Background;
624 param.m_pPath = &path;
625 pTheme->DrawBackground(&param);
626 }
627
628 CFX_RenderDevice* pRenderDev = pGraphics->GetRenderDevice();
629 if (!pRenderDev)
630 return;
631
632 std::unique_ptr<CFDE_RenderDevice> pRenderDevice(
633 new CFDE_RenderDevice(pRenderDev, false));
634 std::unique_ptr<CFDE_RenderContext> pRenderContext(new CFDE_RenderContext);
635 pRenderDevice->SetClipRect(rtClip);
636 pRenderContext->StartRender(pRenderDevice.get(), pPage, mt);
637 pRenderContext->DoRender(nullptr);
638
639 if (m_pProperties->m_dwStyleExes & FWL_STYLEEXT_EDT_CombText) {
640 pGraphics->RestoreGraphState();
641 CFX_Path path;
642 path.Create();
643 int32_t iLimit = m_nLimit > 0 ? m_nLimit : 1;
644 FX_FLOAT fStep = m_rtEngine.width / iLimit;
645 FX_FLOAT fLeft = m_rtEngine.left + 1;
646 for (int32_t i = 1; i < iLimit; i++) {
647 fLeft += fStep;
648 path.AddLine(fLeft, m_rtClient.top, fLeft, m_rtClient.bottom());
649 }
650
651 CFWL_ThemeBackground param;
652 param.m_pGraphics = pGraphics;
653 param.m_matrix = *pMatrix;
654 param.m_pWidget = this;
655 param.m_iPart = CFWL_Part::CombTextLine;
656 param.m_pPath = &path;
657 pTheme->DrawBackground(&param);
658 }
659 pGraphics->RestoreGraphState();
660 }
661
662 void IFWL_Edit::UpdateEditEngine() {
663 UpdateEditParams();
664 UpdateEditLayout();
665 if (m_nLimit > -1)
666 m_EdtEngine.SetLimit(m_nLimit);
667 }
668
669 void IFWL_Edit::UpdateEditParams() {
670 FDE_TXTEDTPARAMS params;
671 params.nHorzScale = 100;
672 params.fPlateWidth = m_rtEngine.width;
673 params.fPlateHeight = m_rtEngine.height;
674 if (m_pProperties->m_dwStyles & FWL_WGTSTYLE_RTLLayout)
675 params.dwLayoutStyles |= FDE_TEXTEDITLAYOUT_RTL;
676 if (m_pProperties->m_dwStyleExes & FWL_STYLEEXT_EDT_VerticalLayout)
677 params.dwLayoutStyles |= FDE_TEXTEDITLAYOUT_DocVertical;
678 if (m_pProperties->m_dwStyleExes & FWL_STYLEEXT_EDT_VerticalChars)
679 params.dwLayoutStyles |= FDE_TEXTEDITLAYOUT_CharVertial;
680 if (m_pProperties->m_dwStyleExes & FWL_STYLEEXT_EDT_ReverseLine)
681 params.dwLayoutStyles |= FDE_TEXTEDITLAYOUT_LineReserve;
682 if (m_pProperties->m_dwStyleExes & FWL_STYLEEXT_EDT_ArabicShapes)
683 params.dwLayoutStyles |= FDE_TEXTEDITLAYOUT_ArabicShapes;
684 if (m_pProperties->m_dwStyleExes & FWL_STYLEEXT_EDT_ExpandTab)
685 params.dwLayoutStyles |= FDE_TEXTEDITLAYOUT_ExpandTab;
686 if (m_pProperties->m_dwStyleExes & FWL_STYLEEXT_EDT_CombText)
687 params.dwLayoutStyles |= FDE_TEXTEDITLAYOUT_CombText;
688 if (m_pProperties->m_dwStyleExes & FWL_STYLEEXT_EDT_LastLineHeight)
689 params.dwLayoutStyles |= FDE_TEXTEDITLAYOUT_LastLineHeight;
690 if (m_pProperties->m_dwStyleExes & FWL_STYLEEXT_EDT_Validate)
691 params.dwMode |= FDE_TEXTEDITMODE_Validate;
692 if (m_pProperties->m_dwStyleExes & FWL_STYLEEXT_EDT_Password)
693 params.dwMode |= FDE_TEXTEDITMODE_Password;
694
695 switch (m_pProperties->m_dwStyleExes & FWL_STYLEEXT_EDT_HAlignMask) {
696 case FWL_STYLEEXT_EDT_HNear: {
697 params.dwAlignment |= FDE_TEXTEDITALIGN_Left;
698 break;
699 }
700 case FWL_STYLEEXT_EDT_HCenter: {
701 params.dwAlignment |= FDE_TEXTEDITALIGN_Center;
702 break;
703 }
704 case FWL_STYLEEXT_EDT_HFar: {
705 params.dwAlignment |= FDE_TEXTEDITALIGN_Right;
706 break;
707 }
708 default:
709 break;
710 }
711 switch (m_pProperties->m_dwStyleExes & FWL_STYLEEXT_EDT_HAlignModeMask) {
712 case FWL_STYLEEXT_EDT_Justified: {
713 params.dwAlignment |= FDE_TEXTEDITALIGN_Justified;
714 break;
715 }
716 case FWL_STYLEEXT_EDT_Distributed: {
717 params.dwAlignment |= FDE_TEXTEDITALIGN_Distributed;
718 break;
719 }
720 default: {
721 params.dwAlignment |= FDE_TEXTEDITALIGN_Normal;
722 break;
723 }
724 }
725 if (m_pProperties->m_dwStyleExes & FWL_STYLEEXT_EDT_MultiLine) {
726 params.dwMode |= FDE_TEXTEDITMODE_MultiLines;
727 if ((m_pProperties->m_dwStyles & FWL_WGTSTYLE_HScroll) == 0 &&
728 (m_pProperties->m_dwStyleExes & FWL_STYLEEXT_EDT_AutoHScroll) == 0) {
729 params.dwMode |=
730 FDE_TEXTEDITMODE_AutoLineWrap | FDE_TEXTEDITMODE_LimitArea_Horz;
731 }
732 if ((m_pProperties->m_dwStyles & FWL_WGTSTYLE_VScroll) == 0 &&
733 (m_pProperties->m_dwStyleExes & FWL_STYLEEXT_EDT_AutoVScroll) == 0) {
734 params.dwMode |= FDE_TEXTEDITMODE_LimitArea_Vert;
735 } else {
736 params.fPlateHeight = 0x00FFFFFF;
737 }
738 } else if ((m_pProperties->m_dwStyleExes & FWL_STYLEEXT_EDT_AutoHScroll) ==
739 0) {
740 params.dwMode |= FDE_TEXTEDITMODE_LimitArea_Horz;
741 }
742 if ((m_pProperties->m_dwStyleExes & FWL_STYLEEXT_EDT_ReadOnly) ||
743 (m_pProperties->m_dwStates & FWL_WGTSTATE_Disabled)) {
744 params.dwMode |= FDE_TEXTEDITMODE_ReadOnly;
745 }
746
747 FX_FLOAT* pFontSize =
748 static_cast<FX_FLOAT*>(GetThemeCapacity(CFWL_WidgetCapacity::FontSize));
749 if (!pFontSize)
750 return;
751
752 m_fFontSize = *pFontSize;
753 uint32_t* pFontColor =
754 static_cast<uint32_t*>(GetThemeCapacity(CFWL_WidgetCapacity::TextColor));
755 if (!pFontColor)
756 return;
757
758 params.dwFontColor = *pFontColor;
759 FX_FLOAT* pLineHeight =
760 static_cast<FX_FLOAT*>(GetThemeCapacity(CFWL_WidgetCapacity::LineHeight));
761 if (!pLineHeight)
762 return;
763
764 params.fLineSpace = *pLineHeight;
765 CFGAS_GEFont* pFont =
766 static_cast<CFGAS_GEFont*>(GetThemeCapacity(CFWL_WidgetCapacity::Font));
767 if (!pFont)
768 return;
769
770 params.pFont = pFont;
771 params.fFontSize = m_fFontSize;
772 params.nLineCount = (int32_t)(params.fPlateHeight / params.fLineSpace);
773 if (params.nLineCount <= 0)
774 params.nLineCount = 1;
775 params.fTabWidth = params.fFontSize * 1;
776 params.bTabEquidistant = true;
777 params.wLineBreakChar = L'\n';
778 params.nCharRotation = 0;
779 params.pEventSink = this;
780 m_EdtEngine.SetEditParams(params);
781 }
782
783 void IFWL_Edit::UpdateEditLayout() {
784 if (m_EdtEngine.GetTextLength() <= 0)
785 m_EdtEngine.SetTextByStream(nullptr);
786
787 IFDE_TxtEdtPage* pPage = m_EdtEngine.GetPage(0);
788 if (pPage)
789 pPage->UnloadPage(nullptr);
790
791 m_EdtEngine.StartLayout();
792 m_EdtEngine.DoLayout(nullptr);
793 m_EdtEngine.EndLayout();
794 pPage = m_EdtEngine.GetPage(0);
795 if (pPage)
796 pPage->LoadPage(nullptr, nullptr);
797 }
798
799 bool IFWL_Edit::UpdateOffset() {
800 CFX_RectF rtCaret;
801 m_EdtEngine.GetCaretRect(rtCaret);
802 FX_FLOAT fOffSetX = m_rtEngine.left - m_fScrollOffsetX;
803 FX_FLOAT fOffSetY = m_rtEngine.top - m_fScrollOffsetY + m_fVAlignOffset;
804 rtCaret.Offset(fOffSetX, fOffSetY);
805 const CFX_RectF& rtEidt = m_rtEngine;
806 if (rtEidt.Contains(rtCaret)) {
807 IFDE_TxtEdtPage* pPage = m_EdtEngine.GetPage(0);
808 if (!pPage)
809 return false;
810
811 CFX_RectF rtFDE = pPage->GetContentsBox();
812 rtFDE.Offset(fOffSetX, fOffSetY);
813 if (rtFDE.right() < rtEidt.right() && m_fScrollOffsetX > 0) {
814 m_fScrollOffsetX += rtFDE.right() - rtEidt.right();
815 m_fScrollOffsetX = std::max(m_fScrollOffsetX, 0.0f);
816 }
817 if (rtFDE.bottom() < rtEidt.bottom() && m_fScrollOffsetY > 0) {
818 m_fScrollOffsetY += rtFDE.bottom() - rtEidt.bottom();
819 m_fScrollOffsetY = std::max(m_fScrollOffsetY, 0.0f);
820 }
821 return false;
822 }
823
824 FX_FLOAT offsetX = 0.0;
825 FX_FLOAT offsetY = 0.0;
826 if (rtCaret.left < rtEidt.left)
827 offsetX = rtCaret.left - rtEidt.left;
828 if (rtCaret.right() > rtEidt.right())
829 offsetX = rtCaret.right() - rtEidt.right();
830 if (rtCaret.top < rtEidt.top)
831 offsetY = rtCaret.top - rtEidt.top;
832 if (rtCaret.bottom() > rtEidt.bottom())
833 offsetY = rtCaret.bottom() - rtEidt.bottom();
834 m_fScrollOffsetX += offsetX;
835 m_fScrollOffsetY += offsetY;
836 if (m_fFontSize > m_rtEngine.height)
837 m_fScrollOffsetY = 0;
838 return true;
839 }
840
841 bool IFWL_Edit::UpdateOffset(CFWL_ScrollBar* pScrollBar, FX_FLOAT fPosChanged) {
842 if (pScrollBar == m_pHorzScrollBar.get())
843 m_fScrollOffsetX += fPosChanged;
844 else
845 m_fScrollOffsetY += fPosChanged;
846 return true;
847 }
848
849 void IFWL_Edit::UpdateVAlignment() {
850 IFDE_TxtEdtPage* pPage = m_EdtEngine.GetPage(0);
851 if (!pPage)
852 return;
853
854 const CFX_RectF& rtFDE = pPage->GetContentsBox();
855 FX_FLOAT fOffsetY = 0.0f;
856 FX_FLOAT fSpaceAbove = 0.0f;
857 FX_FLOAT fSpaceBelow = 0.0f;
858 CFX_SizeF* pSpace = static_cast<CFX_SizeF*>(
859 GetThemeCapacity(CFWL_WidgetCapacity::SpaceAboveBelow));
860 if (pSpace) {
861 fSpaceAbove = pSpace->x;
862 fSpaceBelow = pSpace->y;
863 }
864 if (fSpaceAbove < 0.1f)
865 fSpaceAbove = 0;
866 if (fSpaceBelow < 0.1f)
867 fSpaceBelow = 0;
868
869 if (m_pProperties->m_dwStyleExes & FWL_STYLEEXT_EDT_VCenter) {
870 fOffsetY = (m_rtEngine.height - rtFDE.height) / 2;
871 if (fOffsetY < (fSpaceAbove + fSpaceBelow) / 2 &&
872 fSpaceAbove < fSpaceBelow) {
873 return;
874 }
875 fOffsetY += (fSpaceAbove - fSpaceBelow) / 2;
876 } else if (m_pProperties->m_dwStyleExes & FWL_STYLEEXT_EDT_VFar) {
877 fOffsetY = (m_rtEngine.height - rtFDE.height);
878 fOffsetY -= fSpaceBelow;
879 } else {
880 fOffsetY += fSpaceAbove;
881 }
882 m_fVAlignOffset = std::max(fOffsetY, 0.0f);
883 }
884
885 void IFWL_Edit::UpdateCaret() {
886 CFX_RectF rtFDE;
887 m_EdtEngine.GetCaretRect(rtFDE);
888
889 rtFDE.Offset(m_rtEngine.left - m_fScrollOffsetX,
890 m_rtEngine.top - m_fScrollOffsetY + m_fVAlignOffset);
891 CFX_RectF rtCaret;
892 rtCaret.Set(rtFDE.left, rtFDE.top, rtFDE.width, rtFDE.height);
893
894 CFX_RectF rtClient;
895 GetClientRect(rtClient);
896 rtCaret.Intersect(rtClient);
897
898 if (rtCaret.left > rtClient.right()) {
899 FX_FLOAT right = rtCaret.right();
900 rtCaret.left = rtClient.right() - 1;
901 rtCaret.width = right - rtCaret.left;
902 }
903
904 bool bShow =
905 m_pProperties->m_dwStates & FWL_WGTSTATE_Focused && !rtCaret.IsEmpty();
906 ShowCaret(bShow, &rtCaret);
907 }
908
909 CFWL_ScrollBar* IFWL_Edit::UpdateScroll() {
910 bool bShowHorz =
911 m_pHorzScrollBar &&
912 ((m_pHorzScrollBar->GetStates() & FWL_WGTSTATE_Invisible) == 0);
913 bool bShowVert =
914 m_pVertScrollBar &&
915 ((m_pVertScrollBar->GetStates() & FWL_WGTSTATE_Invisible) == 0);
916 if (!bShowHorz && !bShowVert)
917 return nullptr;
918
919 IFDE_TxtEdtPage* pPage = m_EdtEngine.GetPage(0);
920 if (!pPage)
921 return nullptr;
922
923 const CFX_RectF& rtFDE = pPage->GetContentsBox();
924 CFWL_ScrollBar* pRepaint = nullptr;
925 if (bShowHorz) {
926 CFX_RectF rtScroll;
927 m_pHorzScrollBar->GetWidgetRect(rtScroll);
928 if (rtScroll.width < rtFDE.width) {
929 m_pHorzScrollBar->LockUpdate();
930 FX_FLOAT fRange = rtFDE.width - rtScroll.width;
931 m_pHorzScrollBar->SetRange(0.0f, fRange);
932
933 FX_FLOAT fPos = std::min(std::max(m_fScrollOffsetX, 0.0f), fRange);
934 m_pHorzScrollBar->SetPos(fPos);
935 m_pHorzScrollBar->SetTrackPos(fPos);
936 m_pHorzScrollBar->SetPageSize(rtScroll.width);
937 m_pHorzScrollBar->SetStepSize(rtScroll.width / 10);
938 m_pHorzScrollBar->SetStates(FWL_WGTSTATE_Disabled, false);
939 m_pHorzScrollBar->UnlockUpdate();
940 m_pHorzScrollBar->Update();
941 pRepaint = m_pHorzScrollBar.get();
942 } else if ((m_pHorzScrollBar->GetStates() & FWL_WGTSTATE_Disabled) == 0) {
943 m_pHorzScrollBar->LockUpdate();
944 m_pHorzScrollBar->SetRange(0, -1);
945 m_pHorzScrollBar->SetStates(FWL_WGTSTATE_Disabled, true);
946 m_pHorzScrollBar->UnlockUpdate();
947 m_pHorzScrollBar->Update();
948 pRepaint = m_pHorzScrollBar.get();
949 }
950 }
951
952 if (bShowVert) {
953 CFX_RectF rtScroll;
954 m_pVertScrollBar->GetWidgetRect(rtScroll);
955 if (rtScroll.height < rtFDE.height) {
956 m_pVertScrollBar->LockUpdate();
957 FX_FLOAT fStep = m_EdtEngine.GetEditParams()->fLineSpace;
958 FX_FLOAT fRange = std::max(rtFDE.height - m_rtEngine.height, fStep);
959
960 m_pVertScrollBar->SetRange(0.0f, fRange);
961 FX_FLOAT fPos = std::min(std::max(m_fScrollOffsetY, 0.0f), fRange);
962 m_pVertScrollBar->SetPos(fPos);
963 m_pVertScrollBar->SetTrackPos(fPos);
964 m_pVertScrollBar->SetPageSize(rtScroll.height);
965 m_pVertScrollBar->SetStepSize(fStep);
966 m_pVertScrollBar->SetStates(FWL_WGTSTATE_Disabled, false);
967 m_pVertScrollBar->UnlockUpdate();
968 m_pVertScrollBar->Update();
969 pRepaint = m_pVertScrollBar.get();
970 } else if ((m_pVertScrollBar->GetStates() & FWL_WGTSTATE_Disabled) == 0) {
971 m_pVertScrollBar->LockUpdate();
972 m_pVertScrollBar->SetRange(0, -1);
973 m_pVertScrollBar->SetStates(FWL_WGTSTATE_Disabled, true);
974 m_pVertScrollBar->UnlockUpdate();
975 m_pVertScrollBar->Update();
976 pRepaint = m_pVertScrollBar.get();
977 }
978 }
979 return pRepaint;
980 }
981
982 bool IFWL_Edit::IsShowScrollBar(bool bVert) {
983 bool bShow =
984 (m_pProperties->m_dwStyleExes & FWL_STYLEEXT_EDT_ShowScrollbarFocus)
985 ? (m_pProperties->m_dwStates & FWL_WGTSTATE_Focused) ==
986 FWL_WGTSTATE_Focused
987 : true;
988 if (bVert) {
989 return bShow && (m_pProperties->m_dwStyles & FWL_WGTSTYLE_VScroll) &&
990 (m_pProperties->m_dwStyleExes & FWL_STYLEEXT_EDT_MultiLine) &&
991 IsContentHeightOverflow();
992 }
993 return bShow && (m_pProperties->m_dwStyles & FWL_WGTSTYLE_HScroll) &&
994 (m_pProperties->m_dwStyleExes & FWL_STYLEEXT_EDT_MultiLine);
995 }
996
997 bool IFWL_Edit::IsContentHeightOverflow() {
998 IFDE_TxtEdtPage* pPage = m_EdtEngine.GetPage(0);
999 if (!pPage)
1000 return false;
1001 return pPage->GetContentsBox().height > m_rtEngine.height + 1.0f;
1002 }
1003
1004 int32_t IFWL_Edit::AddDoRecord(IFDE_TxtEdtDoRecord* pRecord) {
1005 int32_t nCount = pdfium::CollectionSize<int32_t>(m_DoRecords);
1006 if (m_iCurRecord == nCount - 1) {
1007 if (nCount == m_iMaxRecord) {
1008 m_DoRecords.pop_front();
1009 m_iCurRecord--;
1010 }
1011 } else {
1012 m_DoRecords.erase(m_DoRecords.begin() + m_iCurRecord + 1,
1013 m_DoRecords.end());
1014 }
1015
1016 m_DoRecords.push_back(std::unique_ptr<IFDE_TxtEdtDoRecord>(pRecord));
1017 m_iCurRecord = pdfium::CollectionSize<int32_t>(m_DoRecords) - 1;
1018 return m_iCurRecord;
1019 }
1020
1021 void IFWL_Edit::Layout() {
1022 GetClientRect(m_rtClient);
1023 m_rtEngine = m_rtClient;
1024 FX_FLOAT* pfWidth = static_cast<FX_FLOAT*>(
1025 GetThemeCapacity(CFWL_WidgetCapacity::ScrollBarWidth));
1026 if (!pfWidth)
1027 return;
1028
1029 FX_FLOAT fWidth = *pfWidth;
1030 if (!m_pOuter) {
1031 CFX_RectF* pUIMargin = static_cast<CFX_RectF*>(
1032 GetThemeCapacity(CFWL_WidgetCapacity::UIMargin));
1033 if (pUIMargin) {
1034 m_rtEngine.Deflate(pUIMargin->left, pUIMargin->top, pUIMargin->width,
1035 pUIMargin->height);
1036 }
1037 } else if (m_pOuter->GetClassID() == FWL_Type::DateTimePicker) {
1038 CFWL_ThemePart part;
1039 part.m_pWidget = m_pOuter;
1040 CFX_RectF* pUIMargin =
1041 static_cast<CFX_RectF*>(m_pOuter->GetThemeProvider()->GetCapacity(
1042 &part, CFWL_WidgetCapacity::UIMargin));
1043 if (pUIMargin) {
1044 m_rtEngine.Deflate(pUIMargin->left, pUIMargin->top, pUIMargin->width,
1045 pUIMargin->height);
1046 }
1047 }
1048
1049 bool bShowVertScrollbar = IsShowScrollBar(true);
1050 bool bShowHorzScrollbar = IsShowScrollBar(false);
1051 if (bShowVertScrollbar) {
1052 InitScrollBar();
1053
1054 CFX_RectF rtVertScr;
1055 if (m_pProperties->m_dwStyleExes & FWL_STYLEEXT_EDT_OuterScrollbar) {
1056 rtVertScr.Set(m_rtClient.right() + kEditMargin, m_rtClient.top, fWidth,
1057 m_rtClient.height);
1058 } else {
1059 rtVertScr.Set(m_rtClient.right() - fWidth, m_rtClient.top, fWidth,
1060 m_rtClient.height);
1061 if (bShowHorzScrollbar)
1062 rtVertScr.height -= fWidth;
1063 m_rtEngine.width -= fWidth;
1064 }
1065
1066 m_pVertScrollBar->SetWidgetRect(rtVertScr);
1067 m_pVertScrollBar->SetStates(FWL_WGTSTATE_Invisible, false);
1068 m_pVertScrollBar->Update();
1069 } else if (m_pVertScrollBar) {
1070 m_pVertScrollBar->SetStates(FWL_WGTSTATE_Invisible, true);
1071 }
1072
1073 if (bShowHorzScrollbar) {
1074 InitScrollBar(false);
1075
1076 CFX_RectF rtHoriScr;
1077 if (m_pProperties->m_dwStyleExes & FWL_STYLEEXT_EDT_OuterScrollbar) {
1078 rtHoriScr.Set(m_rtClient.left, m_rtClient.bottom() + kEditMargin,
1079 m_rtClient.width, fWidth);
1080 } else {
1081 rtHoriScr.Set(m_rtClient.left, m_rtClient.bottom() - fWidth,
1082 m_rtClient.width, fWidth);
1083 if (bShowVertScrollbar)
1084 rtHoriScr.width -= fWidth;
1085 m_rtEngine.height -= fWidth;
1086 }
1087 m_pHorzScrollBar->SetWidgetRect(rtHoriScr);
1088 m_pHorzScrollBar->SetStates(FWL_WGTSTATE_Invisible, false);
1089 m_pHorzScrollBar->Update();
1090 } else if (m_pHorzScrollBar) {
1091 m_pHorzScrollBar->SetStates(FWL_WGTSTATE_Invisible, true);
1092 }
1093 }
1094
1095 void IFWL_Edit::LayoutScrollBar() {
1096 if ((m_pProperties->m_dwStyleExes & FWL_STYLEEXT_EDT_ShowScrollbarFocus) ==
1097 0) {
1098 return;
1099 }
1100
1101 FX_FLOAT* pfWidth = nullptr;
1102 bool bShowVertScrollbar = IsShowScrollBar(true);
1103 bool bShowHorzScrollbar = IsShowScrollBar(false);
1104 if (bShowVertScrollbar) {
1105 if (!m_pVertScrollBar) {
1106 pfWidth = static_cast<FX_FLOAT*>(
1107 GetThemeCapacity(CFWL_WidgetCapacity::ScrollBarWidth));
1108 FX_FLOAT fWidth = pfWidth ? *pfWidth : 0;
1109 InitScrollBar();
1110 CFX_RectF rtVertScr;
1111 if (m_pProperties->m_dwStyleExes & FWL_STYLEEXT_EDT_OuterScrollbar) {
1112 rtVertScr.Set(m_rtClient.right() + kEditMargin, m_rtClient.top, fWidth,
1113 m_rtClient.height);
1114 } else {
1115 rtVertScr.Set(m_rtClient.right() - fWidth, m_rtClient.top, fWidth,
1116 m_rtClient.height);
1117 if (bShowHorzScrollbar)
1118 rtVertScr.height -= fWidth;
1119 }
1120 m_pVertScrollBar->SetWidgetRect(rtVertScr);
1121 m_pVertScrollBar->Update();
1122 }
1123 m_pVertScrollBar->SetStates(FWL_WGTSTATE_Invisible, false);
1124 } else if (m_pVertScrollBar) {
1125 m_pVertScrollBar->SetStates(FWL_WGTSTATE_Invisible, true);
1126 }
1127
1128 if (bShowHorzScrollbar) {
1129 if (!m_pHorzScrollBar) {
1130 if (!pfWidth) {
1131 pfWidth = static_cast<FX_FLOAT*>(
1132 GetThemeCapacity(CFWL_WidgetCapacity::ScrollBarWidth));
1133 }
1134
1135 FX_FLOAT fWidth = pfWidth ? *pfWidth : 0;
1136 InitScrollBar(false);
1137 CFX_RectF rtHoriScr;
1138 if (m_pProperties->m_dwStyleExes & FWL_STYLEEXT_EDT_OuterScrollbar) {
1139 rtHoriScr.Set(m_rtClient.left, m_rtClient.bottom() + kEditMargin,
1140 m_rtClient.width, fWidth);
1141 } else {
1142 rtHoriScr.Set(m_rtClient.left, m_rtClient.bottom() - fWidth,
1143 m_rtClient.width, fWidth);
1144 if (bShowVertScrollbar)
1145 rtHoriScr.width -= (fWidth);
1146 }
1147 m_pHorzScrollBar->SetWidgetRect(rtHoriScr);
1148 m_pHorzScrollBar->Update();
1149 }
1150 m_pHorzScrollBar->SetStates(FWL_WGTSTATE_Invisible, false);
1151 } else if (m_pHorzScrollBar) {
1152 m_pHorzScrollBar->SetStates(FWL_WGTSTATE_Invisible, true);
1153 }
1154 if (bShowVertScrollbar || bShowHorzScrollbar)
1155 UpdateScroll();
1156 }
1157
1158 void IFWL_Edit::DeviceToEngine(CFX_PointF& pt) {
1159 pt.x += m_fScrollOffsetX - m_rtEngine.left;
1160 pt.y += m_fScrollOffsetY - m_rtEngine.top - m_fVAlignOffset;
1161 }
1162
1163 void IFWL_Edit::InitScrollBar(bool bVert) {
1164 if ((bVert && m_pVertScrollBar) || (!bVert && m_pHorzScrollBar))
1165 return;
1166
1167 auto prop = pdfium::MakeUnique<CFWL_WidgetProperties>();
1168 prop->m_dwStyleExes = bVert ? FWL_STYLEEXT_SCB_Vert : FWL_STYLEEXT_SCB_Horz;
1169 prop->m_dwStates = FWL_WGTSTATE_Disabled | FWL_WGTSTATE_Invisible;
1170 prop->m_pParent = this;
1171 prop->m_pThemeProvider = m_pProperties->m_pThemeProvider;
1172
1173 CFWL_ScrollBar* sb = new CFWL_ScrollBar(m_pOwnerApp, std::move(prop), this);
1174 if (bVert)
1175 m_pVertScrollBar.reset(sb);
1176 else
1177 m_pHorzScrollBar.reset(sb);
1178 }
1179
1180 bool FWL_ShowCaret(IFWL_Widget* pWidget,
1181 bool bVisible,
1182 const CFX_RectF* pRtAnchor) {
1183 CXFA_FFWidget* pXFAWidget =
1184 static_cast<CXFA_FFWidget*>(pWidget->GetLayoutItem());
1185 if (!pXFAWidget)
1186 return false;
1187
1188 IXFA_DocEnvironment* pDocEnvironment =
1189 pXFAWidget->GetDoc()->GetDocEnvironment();
1190 if (!pDocEnvironment)
1191 return false;
1192
1193 if (bVisible) {
1194 CFX_Matrix mt;
1195 pXFAWidget->GetRotateMatrix(mt);
1196 CFX_RectF rt(*pRtAnchor);
1197 mt.TransformRect(rt);
1198 pDocEnvironment->DisplayCaret(pXFAWidget, bVisible, &rt);
1199 return true;
1200 }
1201
1202 pDocEnvironment->DisplayCaret(pXFAWidget, bVisible, pRtAnchor);
1203 return true;
1204 }
1205
1206 void IFWL_Edit::ShowCaret(bool bVisible, CFX_RectF* pRect) {
1207 if (m_pCaret) {
1208 m_pCaret->ShowCaret(bVisible);
1209 if (bVisible && !pRect->IsEmpty())
1210 m_pCaret->SetWidgetRect(*pRect);
1211 Repaint(&m_rtEngine);
1212 return;
1213 }
1214
1215 IFWL_Widget* pOuter = this;
1216 if (bVisible) {
1217 pRect->Offset(m_pProperties->m_rtWidget.left,
1218 m_pProperties->m_rtWidget.top);
1219 }
1220 while (pOuter->GetOuter()) {
1221 pOuter = pOuter->GetOuter();
1222 if (bVisible) {
1223 CFX_RectF rtOuter;
1224 pOuter->GetWidgetRect(rtOuter);
1225 pRect->Offset(rtOuter.left, rtOuter.top);
1226 }
1227 }
1228 FWL_ShowCaret(pOuter, bVisible, pRect);
1229 }
1230
1231 bool IFWL_Edit::ValidateNumberChar(FX_WCHAR cNum) {
1232 if (!m_bSetRange)
1233 return true;
1234
1235 CFX_WideString wsOld, wsText;
1236 m_EdtEngine.GetText(wsText, 0);
1237 if (wsText.IsEmpty()) {
1238 if (cNum == L'0')
1239 return false;
1240 return true;
1241 }
1242
1243 int32_t caretPos = m_EdtEngine.GetCaretPos();
1244 if (CountSelRanges() == 0) {
1245 if (cNum == L'0' && caretPos == 0)
1246 return false;
1247
1248 int32_t nLen = wsText.GetLength();
1249 CFX_WideString l = wsText.Mid(0, caretPos);
1250 CFX_WideString r = wsText.Mid(caretPos, nLen - caretPos);
1251 CFX_WideString wsNew = l + cNum + r;
1252 if (wsNew.GetInteger() <= m_iMax)
1253 return true;
1254 return false;
1255 }
1256
1257 if (wsText.GetInteger() <= m_iMax)
1258 return true;
1259 return false;
1260 }
1261
1262 void IFWL_Edit::InitCaret() {
1263 if (!m_pCaret) {
1264 if ((m_pProperties->m_dwStyleExes & FWL_STYLEEXT_EDT_InnerCaret)) {
1265 m_pCaret.reset(new CFWL_Caret(
1266 m_pOwnerApp, pdfium::MakeUnique<CFWL_WidgetProperties>(), this));
1267 m_pCaret->SetParent(this);
1268 m_pCaret->SetStates(m_pProperties->m_dwStates);
1269 }
1270 } else if ((m_pProperties->m_dwStyleExes & FWL_STYLEEXT_EDT_InnerCaret) ==
1271 0) {
1272 m_pCaret.reset();
1273 }
1274 }
1275
1276 void IFWL_Edit::ClearRecord() {
1277 m_iCurRecord = -1;
1278 m_DoRecords.clear();
1279 }
1280
1281 void IFWL_Edit::ProcessInsertError(int32_t iError) {
1282 if (iError != -2)
1283 return;
1284
1285 CFWL_EvtTextFull textFullEvent;
1286 textFullEvent.m_pSrcTarget = this;
1287 DispatchEvent(&textFullEvent);
1288 }
1289
1290 void IFWL_Edit::OnProcessMessage(CFWL_Message* pMessage) {
1291 if (!pMessage)
1292 return;
1293
1294 CFWL_MessageType dwMsgCode = pMessage->GetClassID();
1295 switch (dwMsgCode) {
1296 case CFWL_MessageType::SetFocus:
1297 case CFWL_MessageType::KillFocus:
1298 OnFocusChanged(pMessage, dwMsgCode == CFWL_MessageType::SetFocus);
1299 break;
1300 case CFWL_MessageType::Mouse: {
1301 CFWL_MsgMouse* pMsg = static_cast<CFWL_MsgMouse*>(pMessage);
1302 switch (pMsg->m_dwCmd) {
1303 case FWL_MouseCommand::LeftButtonDown:
1304 OnLButtonDown(pMsg);
1305 break;
1306 case FWL_MouseCommand::LeftButtonUp:
1307 OnLButtonUp(pMsg);
1308 break;
1309 case FWL_MouseCommand::LeftButtonDblClk:
1310 OnButtonDblClk(pMsg);
1311 break;
1312 case FWL_MouseCommand::Move:
1313 OnMouseMove(pMsg);
1314 break;
1315 case FWL_MouseCommand::RightButtonDown:
1316 DoButtonDown(pMsg);
1317 break;
1318 default:
1319 break;
1320 }
1321 break;
1322 }
1323 case CFWL_MessageType::Key: {
1324 CFWL_MsgKey* pKey = static_cast<CFWL_MsgKey*>(pMessage);
1325 if (pKey->m_dwCmd == FWL_KeyCommand::KeyDown)
1326 OnKeyDown(pKey);
1327 else if (pKey->m_dwCmd == FWL_KeyCommand::Char)
1328 OnChar(pKey);
1329 break;
1330 }
1331 default:
1332 break;
1333 }
1334 IFWL_Widget::OnProcessMessage(pMessage);
1335 }
1336
1337 void IFWL_Edit::OnProcessEvent(CFWL_Event* pEvent) {
1338 if (!pEvent)
1339 return;
1340 if (pEvent->GetClassID() != CFWL_EventType::Scroll)
1341 return;
1342
1343 IFWL_Widget* pSrcTarget = pEvent->m_pSrcTarget;
1344 if ((pSrcTarget == m_pVertScrollBar.get() && m_pVertScrollBar) ||
1345 (pSrcTarget == m_pHorzScrollBar.get() && m_pHorzScrollBar)) {
1346 CFWL_EvtScroll* pScrollEvent = static_cast<CFWL_EvtScroll*>(pEvent);
1347 OnScroll(static_cast<CFWL_ScrollBar*>(pSrcTarget),
1348 pScrollEvent->m_iScrollCode, pScrollEvent->m_fPos);
1349 }
1350 }
1351
1352 void IFWL_Edit::OnDrawWidget(CFX_Graphics* pGraphics,
1353 const CFX_Matrix* pMatrix) {
1354 DrawWidget(pGraphics, pMatrix);
1355 }
1356
1357 void IFWL_Edit::DoButtonDown(CFWL_MsgMouse* pMsg) {
1358 if ((m_pProperties->m_dwStates & FWL_WGTSTATE_Focused) == 0)
1359 SetFocus(true);
1360
1361 IFDE_TxtEdtPage* pPage = m_EdtEngine.GetPage(0);
1362 if (!pPage)
1363 return;
1364
1365 CFX_PointF pt(pMsg->m_fx, pMsg->m_fy);
1366 DeviceToEngine(pt);
1367 bool bBefore = true;
1368 int32_t nIndex = pPage->GetCharIndex(pt, bBefore);
1369 if (nIndex < 0)
1370 nIndex = 0;
1371
1372 m_EdtEngine.SetCaretPos(nIndex, bBefore);
1373 }
1374
1375 void IFWL_Edit::OnFocusChanged(CFWL_Message* pMsg, bool bSet) {
1376 uint32_t dwStyleEx = GetStylesEx();
1377 bool bRepaint = !!(dwStyleEx & FWL_STYLEEXT_EDT_InnerCaret);
1378 if (bSet) {
1379 m_pProperties->m_dwStates |= FWL_WGTSTATE_Focused;
1380
1381 UpdateVAlignment();
1382 UpdateOffset();
1383 UpdateCaret();
1384 } else if (m_pProperties->m_dwStates & FWL_WGTSTATE_Focused) {
1385 m_pProperties->m_dwStates &= ~FWL_WGTSTATE_Focused;
1386 ShowCaret(false);
1387 if ((dwStyleEx & FWL_STYLEEXT_EDT_NoHideSel) == 0) {
1388 int32_t nSel = CountSelRanges();
1389 if (nSel > 0) {
1390 ClearSelections();
1391 bRepaint = true;
1392 }
1393 m_EdtEngine.SetCaretPos(0, true);
1394 UpdateOffset();
1395 }
1396 ClearRecord();
1397 }
1398
1399 LayoutScrollBar();
1400 if (!bRepaint)
1401 return;
1402
1403 CFX_RectF rtInvalidate;
1404 rtInvalidate.Set(0, 0, m_pProperties->m_rtWidget.width,
1405 m_pProperties->m_rtWidget.height);
1406 Repaint(&rtInvalidate);
1407 }
1408
1409 void IFWL_Edit::OnLButtonDown(CFWL_MsgMouse* pMsg) {
1410 if (m_pProperties->m_dwStates & FWL_WGTSTATE_Disabled)
1411 return;
1412
1413 m_bLButtonDown = true;
1414 SetGrab(true);
1415 DoButtonDown(pMsg);
1416 int32_t nIndex = m_EdtEngine.GetCaretPos();
1417 bool bRepaint = false;
1418 if (m_EdtEngine.CountSelRanges() > 0) {
1419 m_EdtEngine.ClearSelection();
1420 bRepaint = true;
1421 }
1422
1423 if ((pMsg->m_dwFlags & FWL_KEYFLAG_Shift) && m_nSelStart != nIndex) {
1424 int32_t iStart = std::min(m_nSelStart, nIndex);
1425 int32_t iEnd = std::max(m_nSelStart, nIndex);
1426 m_EdtEngine.AddSelRange(iStart, iEnd - iStart);
1427 bRepaint = true;
1428 } else {
1429 m_nSelStart = nIndex;
1430 }
1431 if (bRepaint)
1432 Repaint(&m_rtEngine);
1433 }
1434
1435 void IFWL_Edit::OnLButtonUp(CFWL_MsgMouse* pMsg) {
1436 m_bLButtonDown = false;
1437 SetGrab(false);
1438 }
1439
1440 void IFWL_Edit::OnButtonDblClk(CFWL_MsgMouse* pMsg) {
1441 IFDE_TxtEdtPage* pPage = m_EdtEngine.GetPage(0);
1442 if (!pPage)
1443 return;
1444
1445 CFX_PointF pt(pMsg->m_fx, pMsg->m_fy);
1446 DeviceToEngine(pt);
1447 int32_t nCount = 0;
1448 int32_t nIndex = pPage->SelectWord(pt, nCount);
1449 if (nIndex < 0)
1450 return;
1451
1452 m_EdtEngine.AddSelRange(nIndex, nCount);
1453 m_EdtEngine.SetCaretPos(nIndex + nCount - 1, false);
1454 Repaint(&m_rtEngine);
1455 }
1456
1457 void IFWL_Edit::OnMouseMove(CFWL_MsgMouse* pMsg) {
1458 if (m_nSelStart == -1 || !m_bLButtonDown)
1459 return;
1460
1461 IFDE_TxtEdtPage* pPage = m_EdtEngine.GetPage(0);
1462 if (!pPage)
1463 return;
1464
1465 CFX_PointF pt(pMsg->m_fx, pMsg->m_fy);
1466 DeviceToEngine(pt);
1467 bool bBefore = true;
1468 int32_t nIndex = pPage->GetCharIndex(pt, bBefore);
1469 m_EdtEngine.SetCaretPos(nIndex, bBefore);
1470 nIndex = m_EdtEngine.GetCaretPos();
1471 m_EdtEngine.ClearSelection();
1472
1473 if (nIndex == m_nSelStart)
1474 return;
1475
1476 int32_t nLen = m_EdtEngine.GetTextLength();
1477 if (m_nSelStart >= nLen)
1478 m_nSelStart = nLen;
1479
1480 m_EdtEngine.AddSelRange(std::min(m_nSelStart, nIndex),
1481 FXSYS_abs(nIndex - m_nSelStart));
1482 }
1483
1484 void IFWL_Edit::OnKeyDown(CFWL_MsgKey* pMsg) {
1485 FDE_TXTEDTMOVECARET MoveCaret = MC_MoveNone;
1486 bool bShift = !!(pMsg->m_dwFlags & FWL_KEYFLAG_Shift);
1487 bool bCtrl = !!(pMsg->m_dwFlags & FWL_KEYFLAG_Ctrl);
1488 uint32_t dwKeyCode = pMsg->m_dwKeyCode;
1489 switch (dwKeyCode) {
1490 case FWL_VKEY_Left: {
1491 MoveCaret = MC_Left;
1492 break;
1493 }
1494 case FWL_VKEY_Right: {
1495 MoveCaret = MC_Right;
1496 break;
1497 }
1498 case FWL_VKEY_Up: {
1499 MoveCaret = MC_Up;
1500 break;
1501 }
1502 case FWL_VKEY_Down: {
1503 MoveCaret = MC_Down;
1504 break;
1505 }
1506 case FWL_VKEY_Home: {
1507 MoveCaret = bCtrl ? MC_Home : MC_LineStart;
1508 break;
1509 }
1510 case FWL_VKEY_End: {
1511 MoveCaret = bCtrl ? MC_End : MC_LineEnd;
1512 break;
1513 }
1514 case FWL_VKEY_Insert:
1515 break;
1516 case FWL_VKEY_Delete: {
1517 if ((m_pProperties->m_dwStyleExes & FWL_STYLEEXT_EDT_ReadOnly) ||
1518 (m_pProperties->m_dwStates & FWL_WGTSTATE_Disabled)) {
1519 break;
1520 }
1521 int32_t nCaret = m_EdtEngine.GetCaretPos();
1522 #if (_FX_OS_ == _FX_MACOSX_)
1523 m_EdtEngine.Delete(nCaret, true);
1524 #else
1525 m_EdtEngine.Delete(nCaret);
1526 #endif
1527 break;
1528 }
1529 case FWL_VKEY_F2:
1530 break;
1531 case FWL_VKEY_Tab: {
1532 DispatchKeyEvent(pMsg);
1533 break;
1534 }
1535 default:
1536 break;
1537 }
1538 if (MoveCaret != MC_MoveNone)
1539 m_EdtEngine.MoveCaretPos(MoveCaret, bShift, bCtrl);
1540 }
1541
1542 void IFWL_Edit::OnChar(CFWL_MsgKey* pMsg) {
1543 if ((m_pProperties->m_dwStyleExes & FWL_STYLEEXT_EDT_ReadOnly) ||
1544 (m_pProperties->m_dwStates & FWL_WGTSTATE_Disabled)) {
1545 return;
1546 }
1547
1548 int32_t iError = 0;
1549 FX_WCHAR c = static_cast<FX_WCHAR>(pMsg->m_dwKeyCode);
1550 int32_t nCaret = m_EdtEngine.GetCaretPos();
1551 switch (c) {
1552 case FWL_VKEY_Back:
1553 m_EdtEngine.Delete(nCaret, true);
1554 break;
1555 case FWL_VKEY_NewLine:
1556 case FWL_VKEY_Escape:
1557 break;
1558 case FWL_VKEY_Tab: {
1559 iError = m_EdtEngine.Insert(nCaret, L"\t", 1);
1560 break;
1561 }
1562 case FWL_VKEY_Return: {
1563 if (m_pProperties->m_dwStyleExes & FWL_STYLEEXT_EDT_WantReturn) {
1564 iError = m_EdtEngine.Insert(nCaret, L"\n", 1);
1565 }
1566 break;
1567 }
1568 default: {
1569 if (!m_pWidgetMgr->IsFormDisabled()) {
1570 if (m_pProperties->m_dwStyleExes & FWL_STYLEEXT_EDT_Number) {
1571 if (((pMsg->m_dwKeyCode < FWL_VKEY_0) &&
1572 (pMsg->m_dwKeyCode != 0x2E && pMsg->m_dwKeyCode != 0x2D)) ||
1573 pMsg->m_dwKeyCode > FWL_VKEY_9) {
1574 break;
1575 }
1576 if (!ValidateNumberChar(c))
1577 break;
1578 }
1579 }
1580 #if (_FX_OS_ == _FX_MACOSX_)
1581 if (pMsg->m_dwFlags & FWL_KEYFLAG_Command)
1582 #else
1583 if (pMsg->m_dwFlags & FWL_KEYFLAG_Ctrl)
1584 #endif
1585 {
1586 break;
1587 }
1588 iError = m_EdtEngine.Insert(nCaret, &c, 1);
1589 break;
1590 }
1591 }
1592 if (iError < 0)
1593 ProcessInsertError(iError);
1594 }
1595
1596 bool IFWL_Edit::OnScroll(CFWL_ScrollBar* pScrollBar,
1597 FWL_SCBCODE dwCode,
1598 FX_FLOAT fPos) {
1599 CFX_SizeF fs;
1600 pScrollBar->GetRange(&fs.x, &fs.y);
1601 FX_FLOAT iCurPos = pScrollBar->GetPos();
1602 FX_FLOAT fStep = pScrollBar->GetStepSize();
1603 switch (dwCode) {
1604 case FWL_SCBCODE::Min: {
1605 fPos = fs.x;
1606 break;
1607 }
1608 case FWL_SCBCODE::Max: {
1609 fPos = fs.y;
1610 break;
1611 }
1612 case FWL_SCBCODE::StepBackward: {
1613 fPos -= fStep;
1614 if (fPos < fs.x + fStep / 2) {
1615 fPos = fs.x;
1616 }
1617 break;
1618 }
1619 case FWL_SCBCODE::StepForward: {
1620 fPos += fStep;
1621 if (fPos > fs.y - fStep / 2) {
1622 fPos = fs.y;
1623 }
1624 break;
1625 }
1626 case FWL_SCBCODE::PageBackward: {
1627 fPos -= pScrollBar->GetPageSize();
1628 if (fPos < fs.x) {
1629 fPos = fs.x;
1630 }
1631 break;
1632 }
1633 case FWL_SCBCODE::PageForward: {
1634 fPos += pScrollBar->GetPageSize();
1635 if (fPos > fs.y) {
1636 fPos = fs.y;
1637 }
1638 break;
1639 }
1640 case FWL_SCBCODE::Pos:
1641 case FWL_SCBCODE::TrackPos:
1642 case FWL_SCBCODE::None:
1643 break;
1644 case FWL_SCBCODE::EndScroll:
1645 return false;
1646 }
1647 if (iCurPos == fPos)
1648 return true;
1649
1650 pScrollBar->SetPos(fPos);
1651 pScrollBar->SetTrackPos(fPos);
1652 UpdateOffset(pScrollBar, fPos - iCurPos);
1653 UpdateCaret();
1654
1655 CFX_RectF rect;
1656 GetWidgetRect(rect);
1657 CFX_RectF rtInvalidate;
1658 rtInvalidate.Set(0, 0, rect.width + 2, rect.height + 2);
1659 Repaint(&rtInvalidate);
1660 return true;
1661 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698