OLD | NEW |
| (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/cfwl_widgetmgr.h" | |
8 | |
9 #include <utility> | |
10 | |
11 #include "third_party/base/ptr_util.h" | |
12 #include "xfa/fwl/core/cfwl_app.h" | |
13 #include "xfa/fwl/core/cfwl_form.h" | |
14 #include "xfa/fwl/core/cfwl_notedriver.h" | |
15 #include "xfa/fxfa/app/xfa_fwladapter.h" | |
16 #include "xfa/fxfa/xfa_ffapp.h" | |
17 | |
18 namespace { | |
19 | |
20 const int kNeedRepaintHitPoints = 12; | |
21 const int kNeedRepaintHitPiece = 3; | |
22 | |
23 struct FWL_NEEDREPAINTHITDATA { | |
24 CFX_PointF hitPoint; | |
25 bool bNotNeedRepaint; | |
26 bool bNotContainByDirty; | |
27 }; | |
28 | |
29 } // namespace | |
30 | |
31 bool FWL_UseOffscreen(CFWL_Widget* pWidget) { | |
32 #if (_FX_OS_ == _FX_MACOSX_) | |
33 return false; | |
34 #else | |
35 return !!(pWidget->GetStyles() & FWL_WGTSTYLE_Offscreen); | |
36 #endif | |
37 } | |
38 | |
39 CFWL_WidgetMgr::CFWL_WidgetMgr(CXFA_FFApp* pAdapterNative) | |
40 : m_dwCapability(0), m_pAdapter(pAdapterNative->GetWidgetMgr(this)) { | |
41 ASSERT(m_pAdapter); | |
42 m_mapWidgetItem[nullptr] = pdfium::MakeUnique<Item>(); | |
43 #if (_FX_OS_ == _FX_WIN32_DESKTOP_) || (_FX_OS_ == _FX_WIN64_) | |
44 m_rtScreen.Reset(); | |
45 #endif | |
46 } | |
47 | |
48 CFWL_WidgetMgr::~CFWL_WidgetMgr() {} | |
49 | |
50 CFWL_Widget* CFWL_WidgetMgr::GetParentWidget(CFWL_Widget* pWidget) const { | |
51 Item* pItem = GetWidgetMgrItem(pWidget); | |
52 return pItem && pItem->pParent ? pItem->pParent->pWidget : nullptr; | |
53 } | |
54 | |
55 CFWL_Widget* CFWL_WidgetMgr::GetOwnerWidget(CFWL_Widget* pWidget) const { | |
56 Item* pItem = GetWidgetMgrItem(pWidget); | |
57 return pItem && pItem->pOwner ? pItem->pOwner->pWidget : nullptr; | |
58 } | |
59 | |
60 CFWL_Widget* CFWL_WidgetMgr::GetFirstSiblingWidget(CFWL_Widget* pWidget) const { | |
61 Item* pItem = GetWidgetMgrItem(pWidget); | |
62 if (!pItem) | |
63 return nullptr; | |
64 | |
65 pItem = pItem->pPrevious; | |
66 while (pItem && pItem->pPrevious) | |
67 pItem = pItem->pPrevious; | |
68 return pItem ? pItem->pWidget : nullptr; | |
69 } | |
70 | |
71 CFWL_Widget* CFWL_WidgetMgr::GetPriorSiblingWidget(CFWL_Widget* pWidget) const { | |
72 Item* pItem = GetWidgetMgrItem(pWidget); | |
73 return pItem && pItem->pPrevious ? pItem->pPrevious->pWidget : nullptr; | |
74 } | |
75 | |
76 CFWL_Widget* CFWL_WidgetMgr::GetNextSiblingWidget(CFWL_Widget* pWidget) const { | |
77 Item* pItem = GetWidgetMgrItem(pWidget); | |
78 return pItem && pItem->pNext ? pItem->pNext->pWidget : nullptr; | |
79 } | |
80 | |
81 CFWL_Widget* CFWL_WidgetMgr::GetFirstChildWidget(CFWL_Widget* pWidget) const { | |
82 Item* pItem = GetWidgetMgrItem(pWidget); | |
83 return pItem && pItem->pChild ? pItem->pChild->pWidget : nullptr; | |
84 } | |
85 | |
86 CFWL_Widget* CFWL_WidgetMgr::GetLastChildWidget(CFWL_Widget* pWidget) const { | |
87 Item* pItem = GetWidgetMgrItem(pWidget); | |
88 if (!pItem) | |
89 return nullptr; | |
90 | |
91 pItem = pItem->pChild; | |
92 while (pItem && pItem->pNext) | |
93 pItem = pItem->pNext; | |
94 return pItem ? pItem->pWidget : nullptr; | |
95 } | |
96 | |
97 CFWL_Widget* CFWL_WidgetMgr::GetSystemFormWidget(CFWL_Widget* pWidget) const { | |
98 Item* pItem = GetWidgetMgrItem(pWidget); | |
99 while (pItem) { | |
100 if (IsAbleNative(pItem->pWidget)) | |
101 return pItem->pWidget; | |
102 pItem = pItem->pParent; | |
103 } | |
104 return nullptr; | |
105 } | |
106 | |
107 void CFWL_WidgetMgr::AppendWidget(CFWL_Widget* pWidget) { | |
108 Item* pItem = GetWidgetMgrItem(pWidget); | |
109 if (!pItem) | |
110 return; | |
111 if (!pItem->pParent) | |
112 return; | |
113 | |
114 Item* pChild = pItem->pParent->pChild; | |
115 int32_t i = 0; | |
116 while (pChild) { | |
117 if (pChild == pItem) { | |
118 if (pChild->pPrevious) | |
119 pChild->pPrevious->pNext = pChild->pNext; | |
120 if (pChild->pNext) | |
121 pChild->pNext->pPrevious = pChild->pPrevious; | |
122 if (pItem->pParent->pChild == pItem) | |
123 pItem->pParent->pChild = pItem->pNext; | |
124 | |
125 pItem->pNext = nullptr; | |
126 pItem->pPrevious = nullptr; | |
127 break; | |
128 } | |
129 if (!pChild->pNext) | |
130 break; | |
131 | |
132 pChild = pChild->pNext; | |
133 ++i; | |
134 } | |
135 | |
136 pChild = pItem->pParent->pChild; | |
137 if (pChild) { | |
138 while (pChild->pNext) | |
139 pChild = pChild->pNext; | |
140 | |
141 pChild->pNext = pItem; | |
142 pItem->pPrevious = pChild; | |
143 } else { | |
144 pItem->pParent->pChild = pItem; | |
145 pItem->pPrevious = nullptr; | |
146 } | |
147 pItem->pNext = nullptr; | |
148 } | |
149 | |
150 void CFWL_WidgetMgr::RepaintWidget(CFWL_Widget* pWidget, | |
151 const CFX_RectF* pRect) { | |
152 if (!m_pAdapter) | |
153 return; | |
154 | |
155 CFWL_Widget* pNative = pWidget; | |
156 CFX_RectF rect(*pRect); | |
157 if (IsFormDisabled()) { | |
158 CFWL_Widget* pOuter = pWidget->GetOuter(); | |
159 while (pOuter) { | |
160 CFX_RectF rtTemp = pNative->GetWidgetRect(); | |
161 rect.left += rtTemp.left; | |
162 rect.top += rtTemp.top; | |
163 pNative = pOuter; | |
164 pOuter = pOuter->GetOuter(); | |
165 } | |
166 } else if (!IsAbleNative(pWidget)) { | |
167 pNative = GetSystemFormWidget(pWidget); | |
168 if (!pNative) | |
169 return; | |
170 | |
171 pWidget->TransformTo(pNative, rect.left, rect.top); | |
172 } | |
173 AddRedrawCounts(pNative); | |
174 m_pAdapter->RepaintWidget(pNative, &rect); | |
175 } | |
176 | |
177 void CFWL_WidgetMgr::InsertWidget(CFWL_Widget* pParent, CFWL_Widget* pChild) { | |
178 Item* pParentItem = GetWidgetMgrItem(pParent); | |
179 if (!pParentItem) { | |
180 auto item = pdfium::MakeUnique<Item>(pParent); | |
181 pParentItem = item.get(); | |
182 m_mapWidgetItem[pParent] = std::move(item); | |
183 | |
184 pParentItem->pParent = GetWidgetMgrItem(nullptr); | |
185 AppendWidget(pParent); | |
186 } | |
187 | |
188 Item* pItem = GetWidgetMgrItem(pChild); | |
189 if (!pItem) { | |
190 auto item = pdfium::MakeUnique<Item>(pChild); | |
191 pItem = item.get(); | |
192 m_mapWidgetItem[pChild] = std::move(item); | |
193 } | |
194 if (pItem->pParent && pItem->pParent != pParentItem) { | |
195 if (pItem->pPrevious) | |
196 pItem->pPrevious->pNext = pItem->pNext; | |
197 if (pItem->pNext) | |
198 pItem->pNext->pPrevious = pItem->pPrevious; | |
199 if (pItem->pParent->pChild == pItem) | |
200 pItem->pParent->pChild = pItem->pNext; | |
201 } | |
202 pItem->pParent = pParentItem; | |
203 AppendWidget(pChild); | |
204 } | |
205 | |
206 void CFWL_WidgetMgr::RemoveWidget(CFWL_Widget* pWidget) { | |
207 Item* pItem = GetWidgetMgrItem(pWidget); | |
208 if (!pItem) | |
209 return; | |
210 if (pItem->pPrevious) | |
211 pItem->pPrevious->pNext = pItem->pNext; | |
212 if (pItem->pNext) | |
213 pItem->pNext->pPrevious = pItem->pPrevious; | |
214 if (pItem->pParent && pItem->pParent->pChild == pItem) | |
215 pItem->pParent->pChild = pItem->pNext; | |
216 | |
217 Item* pChild = pItem->pChild; | |
218 while (pChild) { | |
219 Item* pNext = pChild->pNext; | |
220 RemoveWidget(pChild->pWidget); | |
221 pChild = pNext; | |
222 } | |
223 m_mapWidgetItem.erase(pWidget); | |
224 } | |
225 | |
226 void CFWL_WidgetMgr::SetOwner(CFWL_Widget* pOwner, CFWL_Widget* pOwned) { | |
227 Item* pParentItem = GetWidgetMgrItem(pOwner); | |
228 if (!pParentItem) { | |
229 auto item = pdfium::MakeUnique<Item>(pOwner); | |
230 pParentItem = item.get(); | |
231 m_mapWidgetItem[pOwner] = std::move(item); | |
232 | |
233 pParentItem->pParent = GetWidgetMgrItem(nullptr); | |
234 AppendWidget(pOwner); | |
235 } | |
236 | |
237 Item* pItem = GetWidgetMgrItem(pOwned); | |
238 if (!pItem) { | |
239 auto item = pdfium::MakeUnique<Item>(pOwned); | |
240 pItem = item.get(); | |
241 m_mapWidgetItem[pOwned] = std::move(item); | |
242 } | |
243 pItem->pOwner = pParentItem; | |
244 } | |
245 void CFWL_WidgetMgr::SetParent(CFWL_Widget* pParent, CFWL_Widget* pChild) { | |
246 Item* pParentItem = GetWidgetMgrItem(pParent); | |
247 Item* pItem = GetWidgetMgrItem(pChild); | |
248 if (!pItem) | |
249 return; | |
250 if (pItem->pParent && pItem->pParent != pParentItem) { | |
251 if (pItem->pPrevious) | |
252 pItem->pPrevious->pNext = pItem->pNext; | |
253 if (pItem->pNext) | |
254 pItem->pNext->pPrevious = pItem->pPrevious; | |
255 if (pItem->pParent->pChild == pItem) | |
256 pItem->pParent->pChild = pItem->pNext; | |
257 | |
258 pItem->pNext = nullptr; | |
259 pItem->pPrevious = nullptr; | |
260 } | |
261 pItem->pParent = pParentItem; | |
262 AppendWidget(pChild); | |
263 } | |
264 | |
265 void CFWL_WidgetMgr::SetWidgetRect_Native(CFWL_Widget* pWidget, | |
266 const CFX_RectF& rect) { | |
267 if (!FWL_UseOffscreen(pWidget)) | |
268 return; | |
269 | |
270 Item* pItem = GetWidgetMgrItem(pWidget); | |
271 pItem->iRedrawCounter++; | |
272 if (pItem->pOffscreen) { | |
273 CFX_RenderDevice* pDevice = pItem->pOffscreen->GetRenderDevice(); | |
274 if (pDevice && pDevice->GetBitmap()) { | |
275 CFX_DIBitmap* pBitmap = pDevice->GetBitmap(); | |
276 if (pBitmap->GetWidth() - rect.width > 1 || | |
277 pBitmap->GetHeight() - rect.height > 1) { | |
278 pItem->pOffscreen.reset(); | |
279 } | |
280 } | |
281 } | |
282 #if (_FX_OS_ == _FX_WIN32_DESKTOP_) || (_FX_OS_ == _FX_WIN64_) | |
283 pItem->bOutsideChanged = !m_rtScreen.Contains(rect); | |
284 #endif | |
285 } | |
286 | |
287 CFWL_Widget* CFWL_WidgetMgr::GetWidgetAtPoint(CFWL_Widget* parent, | |
288 FX_FLOAT x, | |
289 FX_FLOAT y) { | |
290 if (!parent) | |
291 return nullptr; | |
292 | |
293 FX_FLOAT x1; | |
294 FX_FLOAT y1; | |
295 CFWL_Widget* child = GetLastChildWidget(parent); | |
296 while (child) { | |
297 if ((child->GetStates() & FWL_WGTSTATE_Invisible) == 0) { | |
298 x1 = x; | |
299 y1 = y; | |
300 CFX_Matrix matrixOnParent; | |
301 child->GetMatrix(matrixOnParent, false); | |
302 CFX_Matrix m; | |
303 m.SetIdentity(); | |
304 m.SetReverse(matrixOnParent); | |
305 m.TransformPoint(x1, y1); | |
306 CFX_RectF bounds = child->GetWidgetRect(); | |
307 if (bounds.Contains(x1, y1)) { | |
308 x1 -= bounds.left; | |
309 y1 -= bounds.top; | |
310 return GetWidgetAtPoint(child, x1, y1); | |
311 } | |
312 } | |
313 child = GetPriorSiblingWidget(child); | |
314 } | |
315 return parent; | |
316 } | |
317 | |
318 void CFWL_WidgetMgr::NotifySizeChanged(CFWL_Widget* pForm, | |
319 FX_FLOAT fx, | |
320 FX_FLOAT fy) { | |
321 if (FWL_UseOffscreen(pForm)) | |
322 GetWidgetMgrItem(pForm)->pOffscreen.reset(); | |
323 } | |
324 | |
325 CFWL_Widget* CFWL_WidgetMgr::NextTab(CFWL_Widget* parent, | |
326 CFWL_Widget* focus, | |
327 bool& bFind) { | |
328 CFWL_WidgetMgr* pMgr = parent->GetOwnerApp()->GetWidgetMgr(); | |
329 CFWL_Widget* child = pMgr->GetFirstChildWidget(parent); | |
330 while (child) { | |
331 if (focus == child) | |
332 bFind = true; | |
333 | |
334 if ((child->GetStyles() & FWL_WGTSTYLE_TabStop) && | |
335 (!focus || (focus != child && bFind))) { | |
336 return child; | |
337 } | |
338 CFWL_Widget* bRet = NextTab(child, focus, bFind); | |
339 if (bRet) | |
340 return bRet; | |
341 | |
342 child = pMgr->GetNextSiblingWidget(child); | |
343 } | |
344 return nullptr; | |
345 } | |
346 | |
347 int32_t CFWL_WidgetMgr::CountRadioButtonGroup(CFWL_Widget* pFirst) const { | |
348 int32_t iRet = 0; | |
349 CFWL_Widget* pChild = pFirst; | |
350 while (pChild) { | |
351 pChild = GetNextSiblingWidget(pChild); | |
352 ++iRet; | |
353 } | |
354 return iRet; | |
355 } | |
356 | |
357 CFWL_Widget* CFWL_WidgetMgr::GetRadioButtonGroupHeader( | |
358 CFWL_Widget* pRadioButton) const { | |
359 CFWL_Widget* pNext = pRadioButton; | |
360 if (pNext && (pNext->GetStyles() & FWL_WGTSTYLE_Group)) | |
361 return pNext; | |
362 return nullptr; | |
363 } | |
364 | |
365 void CFWL_WidgetMgr::GetSameGroupRadioButton( | |
366 CFWL_Widget* pRadioButton, | |
367 CFX_ArrayTemplate<CFWL_Widget*>& group) const { | |
368 CFWL_Widget* pFirst = GetFirstSiblingWidget(pRadioButton); | |
369 if (!pFirst) | |
370 pFirst = pRadioButton; | |
371 | |
372 int32_t iGroup = CountRadioButtonGroup(pFirst); | |
373 if (iGroup < 2) | |
374 return; | |
375 group.Add(GetRadioButtonGroupHeader(pRadioButton)); | |
376 } | |
377 | |
378 CFWL_Widget* CFWL_WidgetMgr::GetDefaultButton(CFWL_Widget* pParent) const { | |
379 if ((pParent->GetClassID() == FWL_Type::PushButton) && | |
380 (pParent->GetStates() & (1 << (FWL_WGTSTATE_MAX + 2)))) { | |
381 return pParent; | |
382 } | |
383 | |
384 CFWL_Widget* child = | |
385 pParent->GetOwnerApp()->GetWidgetMgr()->GetFirstChildWidget(pParent); | |
386 while (child) { | |
387 if ((child->GetClassID() == FWL_Type::PushButton) && | |
388 (child->GetStates() & (1 << (FWL_WGTSTATE_MAX + 2)))) { | |
389 return child; | |
390 } | |
391 if (CFWL_Widget* find = GetDefaultButton(child)) | |
392 return find; | |
393 | |
394 child = child->GetOwnerApp()->GetWidgetMgr()->GetNextSiblingWidget(child); | |
395 } | |
396 return nullptr; | |
397 } | |
398 | |
399 void CFWL_WidgetMgr::AddRedrawCounts(CFWL_Widget* pWidget) { | |
400 GetWidgetMgrItem(pWidget)->iRedrawCounter++; | |
401 } | |
402 | |
403 void CFWL_WidgetMgr::ResetRedrawCounts(CFWL_Widget* pWidget) { | |
404 GetWidgetMgrItem(pWidget)->iRedrawCounter = 0; | |
405 } | |
406 | |
407 CFWL_WidgetMgr::Item* CFWL_WidgetMgr::GetWidgetMgrItem( | |
408 CFWL_Widget* pWidget) const { | |
409 auto it = m_mapWidgetItem.find(pWidget); | |
410 return it != m_mapWidgetItem.end() ? static_cast<Item*>(it->second.get()) | |
411 : nullptr; | |
412 } | |
413 | |
414 bool CFWL_WidgetMgr::IsAbleNative(CFWL_Widget* pWidget) const { | |
415 if (!pWidget) | |
416 return false; | |
417 if (!pWidget->IsInstance(FX_WSTRC(FWL_CLASS_Form))) | |
418 return false; | |
419 | |
420 uint32_t dwStyles = pWidget->GetStyles(); | |
421 return ((dwStyles & FWL_WGTSTYLE_WindowTypeMask) == | |
422 FWL_WGTSTYLE_OverLapper) || | |
423 (dwStyles & FWL_WGTSTYLE_Popup); | |
424 } | |
425 | |
426 void CFWL_WidgetMgr::GetAdapterPopupPos(CFWL_Widget* pWidget, | |
427 FX_FLOAT fMinHeight, | |
428 FX_FLOAT fMaxHeight, | |
429 const CFX_RectF& rtAnchor, | |
430 CFX_RectF& rtPopup) const { | |
431 m_pAdapter->GetPopupPos(pWidget, fMinHeight, fMaxHeight, rtAnchor, rtPopup); | |
432 } | |
433 | |
434 void CFWL_WidgetMgr::OnSetCapability(uint32_t dwCapability) { | |
435 m_dwCapability = dwCapability; | |
436 } | |
437 | |
438 void CFWL_WidgetMgr::OnProcessMessageToForm(CFWL_Message* pMessage) { | |
439 if (!pMessage) | |
440 return; | |
441 if (!pMessage->m_pDstTarget) | |
442 return; | |
443 | |
444 CFWL_Widget* pDstWidget = pMessage->m_pDstTarget; | |
445 const CFWL_App* pApp = pDstWidget->GetOwnerApp(); | |
446 if (!pApp) | |
447 return; | |
448 | |
449 CFWL_NoteDriver* pNoteDriver = | |
450 static_cast<CFWL_NoteDriver*>(pApp->GetNoteDriver()); | |
451 if (!pNoteDriver) | |
452 return; | |
453 | |
454 std::unique_ptr<CFWL_Message> pClonedMessage = pMessage->Clone(); | |
455 if (IsFormDisabled()) | |
456 pNoteDriver->ProcessMessage(pClonedMessage.get()); | |
457 else | |
458 pNoteDriver->QueueMessage(std::move(pClonedMessage)); | |
459 | |
460 #if (_FX_OS_ == _FX_MACOSX_) | |
461 CFWL_NoteLoop* pTopLoop = pNoteDriver->GetTopLoop(); | |
462 if (pTopLoop) | |
463 pNoteDriver->UnqueueMessage(pTopLoop); | |
464 #endif | |
465 } | |
466 | |
467 void CFWL_WidgetMgr::OnDrawWidget(CFWL_Widget* pWidget, | |
468 CFX_Graphics* pGraphics, | |
469 const CFX_Matrix* pMatrix) { | |
470 if (!pWidget || !pGraphics) | |
471 return; | |
472 | |
473 CFX_Graphics* pTemp = DrawWidgetBefore(pWidget, pGraphics, pMatrix); | |
474 CFX_RectF clipCopy = pWidget->GetWidgetRect(); | |
475 clipCopy.left = clipCopy.top = 0; | |
476 | |
477 if (UseOffscreenDirect(pWidget)) { | |
478 DrawWidgetAfter(pWidget, pGraphics, clipCopy, pMatrix); | |
479 return; | |
480 } | |
481 CFX_RectF clipBounds; | |
482 | |
483 #if _FX_OS_ == _FX_WIN32_DESKTOP_ || _FX_OS_ == _FX_WIN64_ || \ | |
484 _FX_OS_ == _FX_LINUX_DESKTOP_ || _FX_OS_ == _FX_ANDROID_ | |
485 pWidget->GetDelegate()->OnDrawWidget(pTemp, pMatrix); | |
486 pGraphics->GetClipRect(clipBounds); | |
487 clipCopy = clipBounds; | |
488 #elif _FX_OS_ == _FX_MACOSX_ | |
489 if (IsFormDisabled()) { | |
490 pWidget->GetDelegate()->OnDrawWidget(pTemp, pMatrix); | |
491 pGraphics->GetClipRect(clipBounds); | |
492 clipCopy = clipBounds; | |
493 } else { | |
494 clipBounds.Set(pMatrix->a, pMatrix->b, pMatrix->c, pMatrix->d); | |
495 const_cast<CFX_Matrix*>(pMatrix)->SetIdentity(); // FIXME: const cast. | |
496 pWidget->GetDelegate()->OnDrawWidget(pTemp, pMatrix); | |
497 } | |
498 #endif // _FX_OS_ == _FX_MACOSX_ | |
499 | |
500 if (!IsFormDisabled()) { | |
501 CFX_RectF rtClient; | |
502 pWidget->GetClientRect(rtClient); | |
503 clipBounds.Intersect(rtClient); | |
504 } | |
505 if (!clipBounds.IsEmpty()) | |
506 DrawChild(pWidget, clipBounds, pTemp, pMatrix); | |
507 | |
508 DrawWidgetAfter(pWidget, pGraphics, clipCopy, pMatrix); | |
509 ResetRedrawCounts(pWidget); | |
510 } | |
511 | |
512 void CFWL_WidgetMgr::DrawChild(CFWL_Widget* parent, | |
513 const CFX_RectF& rtClip, | |
514 CFX_Graphics* pGraphics, | |
515 const CFX_Matrix* pMatrix) { | |
516 if (!parent) | |
517 return; | |
518 | |
519 bool bFormDisable = IsFormDisabled(); | |
520 CFWL_Widget* pNextChild = GetFirstChildWidget(parent); | |
521 while (pNextChild) { | |
522 CFWL_Widget* child = pNextChild; | |
523 pNextChild = GetNextSiblingWidget(child); | |
524 if (child->GetStates() & FWL_WGTSTATE_Invisible) | |
525 continue; | |
526 | |
527 CFX_RectF rtWidget = child->GetWidgetRect(); | |
528 if (rtWidget.IsEmpty()) | |
529 continue; | |
530 | |
531 CFX_Matrix widgetMatrix; | |
532 CFX_RectF clipBounds(rtWidget); | |
533 if (!bFormDisable) | |
534 child->GetMatrix(widgetMatrix, true); | |
535 if (pMatrix) | |
536 widgetMatrix.Concat(*pMatrix); | |
537 | |
538 if (!bFormDisable) { | |
539 widgetMatrix.TransformPoint(clipBounds.left, clipBounds.top); | |
540 clipBounds.Intersect(rtClip); | |
541 if (clipBounds.IsEmpty()) | |
542 continue; | |
543 | |
544 pGraphics->SaveGraphState(); | |
545 pGraphics->SetClipRect(clipBounds); | |
546 } | |
547 widgetMatrix.Translate(rtWidget.left, rtWidget.top, true); | |
548 | |
549 if (IFWL_WidgetDelegate* pDelegate = child->GetDelegate()) { | |
550 if (IsFormDisabled() || IsNeedRepaint(child, &widgetMatrix, rtClip)) | |
551 pDelegate->OnDrawWidget(pGraphics, &widgetMatrix); | |
552 } | |
553 if (!bFormDisable) | |
554 pGraphics->RestoreGraphState(); | |
555 | |
556 DrawChild(child, clipBounds, pGraphics, | |
557 bFormDisable ? &widgetMatrix : pMatrix); | |
558 child = GetNextSiblingWidget(child); | |
559 } | |
560 } | |
561 | |
562 CFX_Graphics* CFWL_WidgetMgr::DrawWidgetBefore(CFWL_Widget* pWidget, | |
563 CFX_Graphics* pGraphics, | |
564 const CFX_Matrix* pMatrix) { | |
565 if (!FWL_UseOffscreen(pWidget)) | |
566 return pGraphics; | |
567 | |
568 Item* pItem = GetWidgetMgrItem(pWidget); | |
569 if (!pItem->pOffscreen) { | |
570 pItem->pOffscreen.reset(new CFX_Graphics); | |
571 CFX_RectF rect = pWidget->GetWidgetRect(); | |
572 pItem->pOffscreen->Create((int32_t)rect.width, (int32_t)rect.height, | |
573 FXDIB_Argb); | |
574 } | |
575 CFX_RectF rect; | |
576 pGraphics->GetClipRect(rect); | |
577 pItem->pOffscreen->SetClipRect(rect); | |
578 return pItem->pOffscreen.get(); | |
579 } | |
580 | |
581 void CFWL_WidgetMgr::DrawWidgetAfter(CFWL_Widget* pWidget, | |
582 CFX_Graphics* pGraphics, | |
583 CFX_RectF& rtClip, | |
584 const CFX_Matrix* pMatrix) { | |
585 if (FWL_UseOffscreen(pWidget)) { | |
586 Item* pItem = GetWidgetMgrItem(pWidget); | |
587 pGraphics->Transfer(pItem->pOffscreen.get(), rtClip.left, rtClip.top, | |
588 rtClip, pMatrix); | |
589 #ifdef _WIN32 | |
590 pItem->pOffscreen->ClearClip(); | |
591 #endif | |
592 } | |
593 Item* pItem = GetWidgetMgrItem(pWidget); | |
594 pItem->iRedrawCounter = 0; | |
595 } | |
596 | |
597 bool CFWL_WidgetMgr::IsNeedRepaint(CFWL_Widget* pWidget, | |
598 CFX_Matrix* pMatrix, | |
599 const CFX_RectF& rtDirty) { | |
600 Item* pItem = GetWidgetMgrItem(pWidget); | |
601 if (pItem && pItem->iRedrawCounter > 0) { | |
602 pItem->iRedrawCounter = 0; | |
603 return true; | |
604 } | |
605 | |
606 CFX_RectF rtWidget = pWidget->GetWidgetRect(); | |
607 rtWidget.left = rtWidget.top = 0; | |
608 pMatrix->TransformRect(rtWidget); | |
609 if (!rtWidget.IntersectWith(rtDirty)) | |
610 return false; | |
611 | |
612 CFWL_Widget* pChild = | |
613 pWidget->GetOwnerApp()->GetWidgetMgr()->GetFirstChildWidget(pWidget); | |
614 if (!pChild) | |
615 return true; | |
616 | |
617 CFX_RectF rtChilds; | |
618 rtChilds.Empty(); | |
619 bool bChildIntersectWithDirty = false; | |
620 bool bOrginPtIntersectWidthChild = false; | |
621 bool bOrginPtIntersectWidthDirty = | |
622 rtDirty.Contains(rtWidget.left, rtWidget.top); | |
623 static FWL_NEEDREPAINTHITDATA hitPoint[kNeedRepaintHitPoints]; | |
624 FXSYS_memset(hitPoint, 0, sizeof(hitPoint)); | |
625 FX_FLOAT fxPiece = rtWidget.width / kNeedRepaintHitPiece; | |
626 FX_FLOAT fyPiece = rtWidget.height / kNeedRepaintHitPiece; | |
627 hitPoint[2].hitPoint.x = hitPoint[6].hitPoint.x = rtWidget.left; | |
628 hitPoint[0].hitPoint.x = hitPoint[3].hitPoint.x = hitPoint[7].hitPoint.x = | |
629 hitPoint[10].hitPoint.x = fxPiece + rtWidget.left; | |
630 hitPoint[1].hitPoint.x = hitPoint[4].hitPoint.x = hitPoint[8].hitPoint.x = | |
631 hitPoint[11].hitPoint.x = fxPiece * 2 + rtWidget.left; | |
632 hitPoint[5].hitPoint.x = hitPoint[9].hitPoint.x = | |
633 rtWidget.width + rtWidget.left; | |
634 hitPoint[0].hitPoint.y = hitPoint[1].hitPoint.y = rtWidget.top; | |
635 hitPoint[2].hitPoint.y = hitPoint[3].hitPoint.y = hitPoint[4].hitPoint.y = | |
636 hitPoint[5].hitPoint.y = fyPiece + rtWidget.top; | |
637 hitPoint[6].hitPoint.y = hitPoint[7].hitPoint.y = hitPoint[8].hitPoint.y = | |
638 hitPoint[9].hitPoint.y = fyPiece * 2 + rtWidget.top; | |
639 hitPoint[10].hitPoint.y = hitPoint[11].hitPoint.y = | |
640 rtWidget.height + rtWidget.top; | |
641 do { | |
642 CFX_RectF rect = pChild->GetWidgetRect(); | |
643 CFX_RectF r = rect; | |
644 r.left += rtWidget.left; | |
645 r.top += rtWidget.top; | |
646 if (r.IsEmpty()) | |
647 continue; | |
648 if (r.Contains(rtDirty)) | |
649 return false; | |
650 if (!bChildIntersectWithDirty && r.IntersectWith(rtDirty)) | |
651 bChildIntersectWithDirty = true; | |
652 if (bOrginPtIntersectWidthDirty && !bOrginPtIntersectWidthChild) | |
653 bOrginPtIntersectWidthChild = rect.Contains(0, 0); | |
654 | |
655 if (rtChilds.IsEmpty()) | |
656 rtChilds = rect; | |
657 else if (!(pChild->GetStates() & FWL_WGTSTATE_Invisible)) | |
658 rtChilds.Union(rect); | |
659 | |
660 for (int32_t i = 0; i < kNeedRepaintHitPoints; i++) { | |
661 if (hitPoint[i].bNotContainByDirty || hitPoint[i].bNotNeedRepaint) | |
662 continue; | |
663 if (!rtDirty.Contains(hitPoint[i].hitPoint)) { | |
664 hitPoint[i].bNotContainByDirty = true; | |
665 continue; | |
666 } | |
667 if (r.Contains(hitPoint[i].hitPoint)) | |
668 hitPoint[i].bNotNeedRepaint = true; | |
669 } | |
670 pChild = | |
671 pChild->GetOwnerApp()->GetWidgetMgr()->GetNextSiblingWidget(pChild); | |
672 } while (pChild); | |
673 | |
674 if (!bChildIntersectWithDirty) | |
675 return true; | |
676 if (bOrginPtIntersectWidthDirty && !bOrginPtIntersectWidthChild) | |
677 return true; | |
678 if (rtChilds.IsEmpty()) | |
679 return true; | |
680 | |
681 int32_t repaintPoint = kNeedRepaintHitPoints; | |
682 for (int32_t i = 0; i < kNeedRepaintHitPoints; i++) { | |
683 if (hitPoint[i].bNotNeedRepaint) | |
684 repaintPoint--; | |
685 } | |
686 if (repaintPoint > 0) | |
687 return true; | |
688 | |
689 pMatrix->TransformRect(rtChilds); | |
690 if (rtChilds.Contains(rtDirty) || rtChilds.Contains(rtWidget)) | |
691 return false; | |
692 return true; | |
693 } | |
694 | |
695 bool CFWL_WidgetMgr::UseOffscreenDirect(CFWL_Widget* pWidget) const { | |
696 Item* pItem = GetWidgetMgrItem(pWidget); | |
697 if (!FWL_UseOffscreen(pWidget) || !(pItem->pOffscreen)) | |
698 return false; | |
699 | |
700 #if (_FX_OS_ == _FX_WIN32_DESKTOP_) || (_FX_OS_ == _FX_WIN64_) | |
701 if (pItem->bOutsideChanged) { | |
702 CFX_RectF r = pWidget->GetWidgetRect(); | |
703 CFX_RectF temp(m_rtScreen); | |
704 temp.Deflate(50, 50); | |
705 if (!temp.Contains(r)) | |
706 return false; | |
707 | |
708 pItem->bOutsideChanged = false; | |
709 } | |
710 #endif | |
711 | |
712 return pItem->iRedrawCounter == 0; | |
713 } | |
714 | |
715 CFWL_WidgetMgr::Item::Item() : CFWL_WidgetMgr::Item(nullptr) {} | |
716 | |
717 CFWL_WidgetMgr::Item::Item(CFWL_Widget* widget) | |
718 : pParent(nullptr), | |
719 pOwner(nullptr), | |
720 pChild(nullptr), | |
721 pPrevious(nullptr), | |
722 pNext(nullptr), | |
723 pWidget(widget), | |
724 iRedrawCounter(0) | |
725 #if (_FX_OS_ == _FX_WIN32_DESKTOP_) || (_FX_OS_ == _FX_WIN64_) | |
726 , | |
727 bOutsideChanged(false) | |
728 #endif | |
729 { | |
730 } | |
731 | |
732 CFWL_WidgetMgr::Item::~Item() {} | |
OLD | NEW |