Merge XFA to PDFium master at 4dc95e7 on 10/28/2014
[pdfium.git] / xfa / src / fwl / src / core / fwl_widgetmgrimp.cpp
1 // Copyright 2014 PDFium Authors. All rights reserved.\r
2 // Use of this source code is governed by a BSD-style license that can be\r
3 // found in the LICENSE file.\r
4 \r
5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com\r
6 \r
7 #include "../../../foxitlib.h"\r
8 #include "include/fwl_targetimp.h"\r
9 #include "include/fwl_noteimp.h"\r
10 #include "include/fwl_widgetmgrimp.h"\r
11 #include "include/fwl_threadimp.h"\r
12 #include "include/fwl_appimp.h"\r
13 #define FWL_NORMALMATRIX\r
14 FX_BOOL FWL_UseOffscreen(IFWL_Widget * pWidget)\r
15 {\r
16 #if (_FX_OS_==_FX_MACOSX_)\r
17     return FALSE;\r
18 #else\r
19     return pWidget->GetStyles() & FWL_WGTSTYLE_Offscreen;\r
20 #endif\r
21 }\r
22 IFWL_WidgetMgr* FWL_GetWidgetMgr()\r
23 {\r
24     IFWL_App *pApp = FWL_GetApp();\r
25     _FWL_RETURN_VALUE_IF_FAIL(pApp, NULL);\r
26     return pApp->GetWidgetMgr();\r
27 }\r
28 CFWL_WidgetMgr::CFWL_WidgetMgr(IFWL_AdapterNative *pAdapterNative)\r
29     : m_dwCapability(0)\r
30 {\r
31     m_pDelegate = FX_NEW CFWL_WidgetMgrDelegate(this);\r
32     m_pAdapter = pAdapterNative->GetWidgetMgr((IFWL_WidgetMgrDelegate*)m_pDelegate);\r
33     FXSYS_assert(m_pAdapter);\r
34     CFWL_WidgetMgrItem *pRoot = FX_NEW CFWL_WidgetMgrItem;\r
35     m_mapWidgetItem.SetAt(NULL, pRoot);\r
36 #if (_FX_OS_==_FX_WIN32_DESKTOP_) || (_FX_OS_==_FX_WIN64_)\r
37     m_rtScreen.Reset();\r
38     IFWL_AdapterMonitorMgr* pMonitorMgr = pAdapterNative->GetMonitorMgr();\r
39     if (pMonitorMgr) {\r
40         FWL_HMONITOR monitor = pMonitorMgr->GetCurrentMonitor();\r
41         if (monitor) {\r
42             pMonitorMgr->GetMonitorSize(monitor, m_rtScreen.width, m_rtScreen.height);\r
43         }\r
44     }\r
45 #endif\r
46 }\r
47 CFWL_WidgetMgr::~CFWL_WidgetMgr()\r
48 {\r
49     FX_POSITION ps = m_mapWidgetItem.GetStartPosition();\r
50     while (ps) {\r
51         FX_LPVOID pWidget;\r
52         CFWL_WidgetMgrItem *pItem;\r
53         m_mapWidgetItem.GetNextAssoc(ps, pWidget, (void*&)pItem);\r
54         delete pItem;\r
55     }\r
56     m_mapWidgetItem.RemoveAll();\r
57     if (m_pDelegate) {\r
58         delete m_pDelegate;\r
59         m_pDelegate = NULL;\r
60     }\r
61 }\r
62 FX_INT32 CFWL_WidgetMgr::CountWidgets(IFWL_Widget *pParent )\r
63 {\r
64     CFWL_WidgetMgrItem *pParentItem = GetWidgetMgrItem(pParent);\r
65     return TravelWidgetMgr(pParentItem, NULL, NULL);\r
66 }\r
67 IFWL_Widget* CFWL_WidgetMgr::GetWidget(FX_INT32 nIndex, IFWL_Widget *pParent )\r
68 {\r
69     CFWL_WidgetMgrItem *pParentItem = GetWidgetMgrItem(pParent);\r
70     IFWL_Widget *pWidget = NULL;\r
71     TravelWidgetMgr(pParentItem, &nIndex, NULL, &pWidget);\r
72     return pWidget;\r
73 }\r
74 IFWL_Widget* CFWL_WidgetMgr::GetWidget(IFWL_Widget *pWidget, FWL_WGTRELATION eRelation)\r
75 {\r
76     CFWL_WidgetMgrItem *pItem = GetWidgetMgrItem(pWidget);\r
77     if (!pItem) {\r
78         return NULL;\r
79     }\r
80     IFWL_Widget *pRet = NULL;\r
81     switch (eRelation) {\r
82         case FWL_WGTRELATION_Parent: {\r
83                 pRet = pItem->pParent ? pItem->pParent->pWidget : NULL;\r
84                 break;\r
85             }\r
86         case FWL_WGTRELATION_Owner: {\r
87                 pRet = pItem->pOwner ? pItem->pOwner->pWidget : NULL;\r
88                 break;\r
89             }\r
90         case FWL_WGTRELATION_FirstSibling: {\r
91                 pItem = pItem->pPrevious;\r
92                 while (pItem && pItem->pPrevious) {\r
93                     pItem = pItem->pPrevious;\r
94                 }\r
95                 pRet = pItem ? pItem->pWidget : NULL;\r
96                 break;\r
97             }\r
98         case FWL_WGTRELATION_PriorSibling: {\r
99                 pRet = pItem->pPrevious ? pItem->pPrevious->pWidget : NULL;\r
100                 break;\r
101             }\r
102         case FWL_WGTRELATION_NextSibling: {\r
103                 pRet = pItem->pNext ? pItem->pNext->pWidget : NULL;\r
104                 break;\r
105             }\r
106         case FWL_WGTRELATION_LastSibling: {\r
107                 pItem = pItem->pNext;\r
108                 while (pItem && pItem->pNext) {\r
109                     pItem = pItem->pNext;\r
110                 }\r
111                 pRet = pItem ? pItem->pWidget : NULL;\r
112                 break;\r
113             }\r
114         case FWL_WGTRELATION_FirstChild: {\r
115                 pRet = pItem->pChild ? pItem->pChild->pWidget : NULL;\r
116                 break;\r
117             }\r
118         case FWL_WGTRELATION_LastChild: {\r
119                 pItem = pItem->pChild;\r
120                 while (pItem && pItem->pNext) {\r
121                     pItem = pItem->pNext;\r
122                 }\r
123                 pRet = pItem ? pItem->pWidget : NULL;\r
124                 break;\r
125             }\r
126         case FWL_WGTRELATION_SystemForm: {\r
127                 while (pItem) {\r
128                     if (IsAbleNative(pItem->pWidget)) {\r
129                         pRet = pItem->pWidget;\r
130                         break;\r
131                     }\r
132                     pItem = pItem->pParent;\r
133                 }\r
134                 break;\r
135             }\r
136         default: {\r
137             }\r
138     }\r
139     return pRet;\r
140 }\r
141 FX_INT32 CFWL_WidgetMgr::GetWidgetIndex(IFWL_Widget *pWidget)\r
142 {\r
143     CFWL_WidgetMgrItem *pItem = GetWidgetMgrItem(pWidget);\r
144     _FWL_RETURN_VALUE_IF_FAIL(pItem, -1);\r
145     return TravelWidgetMgr(pItem->pParent, NULL, pItem);\r
146 }\r
147 FX_BOOL CFWL_WidgetMgr::SetWidgetIndex(IFWL_Widget *pWidget, FX_INT32 nIndex)\r
148 {\r
149     CFWL_WidgetMgrItem *pItem = GetWidgetMgrItem(pWidget);\r
150     _FWL_RETURN_VALUE_IF_FAIL(pItem, FALSE);\r
151     _FWL_RETURN_VALUE_IF_FAIL(pItem->pParent, FALSE);\r
152     CFWL_WidgetMgrItem *pChild = pItem->pParent->pChild;\r
153     FX_INT32 i = 0;\r
154     while (pChild) {\r
155         if (pChild == pItem) {\r
156             if (i == nIndex) {\r
157                 return TRUE;\r
158             }\r
159             if (pChild->pPrevious) {\r
160                 pChild->pPrevious->pNext = pChild->pNext;\r
161             }\r
162             if (pChild->pNext) {\r
163                 pChild->pNext->pPrevious = pChild->pPrevious;\r
164             }\r
165             if (pItem->pParent->pChild == pItem) {\r
166                 pItem->pParent->pChild = pItem->pNext;\r
167             }\r
168             pItem->pNext = NULL;\r
169             pItem->pPrevious = NULL;\r
170             break;\r
171         }\r
172         if(!pChild->pNext) {\r
173             break;\r
174         }\r
175         pChild = pChild->pNext;\r
176         ++i;\r
177     }\r
178     pChild = pItem->pParent->pChild;\r
179     if (pChild) {\r
180         if (nIndex < 0) {\r
181             while(pChild->pNext) {\r
182                 pChild = pChild->pNext;\r
183             }\r
184             pChild->pNext = pItem;\r
185             pItem->pPrevious = pChild;\r
186             pItem->pNext = NULL;\r
187             return TRUE;\r
188         }\r
189         i = 0;\r
190         while(i < nIndex && pChild->pNext ) {\r
191             pChild = pChild->pNext;\r
192             ++i;\r
193         }\r
194         if (!pChild->pNext) {\r
195             pChild->pNext = pItem;\r
196             pItem->pPrevious = pChild;\r
197             pItem->pNext = NULL;\r
198             return TRUE;\r
199         }\r
200         if (pChild->pPrevious) {\r
201             pItem->pPrevious = pChild->pPrevious;\r
202             pChild->pPrevious->pNext = pItem;\r
203         }\r
204         pChild->pPrevious = pItem;\r
205         pItem->pNext = pChild;\r
206         if (pItem->pParent->pChild == pChild) {\r
207             pItem->pParent->pChild = pItem;\r
208         }\r
209     } else {\r
210         pItem->pParent->pChild = pItem;\r
211         pItem->pPrevious = NULL;\r
212         pItem->pNext = NULL;\r
213     }\r
214     return TRUE;\r
215 }\r
216 FX_BOOL CFWL_WidgetMgr::IsWidget(FX_LPVOID pObj)\r
217 {\r
218     _FWL_RETURN_VALUE_IF_FAIL(pObj, FALSE);\r
219     return GetWidgetMgrItem((IFWL_Widget*)pObj) != NULL;\r
220 }\r
221 FWL_ERR CFWL_WidgetMgr::RepaintWidget(IFWL_Widget *pWidget, const CFX_RectF *pRect )\r
222 {\r
223     _FWL_RETURN_VALUE_IF_FAIL(m_pAdapter, FWL_ERR_Indefinite);\r
224     IFWL_Widget *pNative = pWidget;\r
225     CFX_RectF rect(*pRect);\r
226     if (IsFormDisabled()) {\r
227         IFWL_Widget *pOuter = pWidget->GetOuter();\r
228         while (pOuter) {\r
229             CFX_RectF rtTemp;\r
230             pNative->GetWidgetRect(rtTemp);\r
231             rect.left += rtTemp.left;\r
232             rect.top += rtTemp.top;\r
233             pNative = pOuter;\r
234             pOuter = pOuter->GetOuter();\r
235         }\r
236     } else if (!IsAbleNative(pWidget)) {\r
237         pNative = GetWidget(pWidget, FWL_WGTRELATION_SystemForm);\r
238         _FWL_RETURN_VALUE_IF_FAIL(pNative, FWL_ERR_Indefinite);\r
239         pWidget->TransformTo(pNative, rect.left, rect.top);\r
240     }\r
241     AddRedrawCounts(pNative);\r
242     return m_pAdapter->RepaintWidget(pNative, &rect);\r
243 }\r
244 void CFWL_WidgetMgr::AddWidget(IFWL_Widget *pWidget)\r
245 {\r
246     CFWL_WidgetMgrItem *pParentItem = GetWidgetMgrItem(NULL);\r
247     CFWL_WidgetMgrItem *pItem = GetWidgetMgrItem(pWidget);\r
248     if (!pItem) {\r
249         pItem = FX_NEW CFWL_WidgetMgrItem;\r
250         pItem->pWidget = pWidget;\r
251         m_mapWidgetItem.SetAt(pWidget, pItem);\r
252     }\r
253     if (pItem->pParent && pItem->pParent != pParentItem) {\r
254         if (pItem->pPrevious) {\r
255             pItem->pPrevious->pNext = pItem->pNext;\r
256         }\r
257         if (pItem->pNext) {\r
258             pItem->pNext->pPrevious = pItem->pPrevious;\r
259         }\r
260         if (pItem->pParent->pChild == pItem) {\r
261             pItem->pParent->pChild = pItem->pNext;\r
262         }\r
263     }\r
264     pItem->pParent = pParentItem;\r
265     SetWidgetIndex(pWidget, -1);\r
266 }\r
267 void CFWL_WidgetMgr::InsertWidget(IFWL_Widget *pParent, IFWL_Widget *pChild, FX_INT32 nIndex )\r
268 {\r
269     CFWL_WidgetMgrItem *pParentItem = GetWidgetMgrItem(pParent);\r
270     if (!pParentItem) {\r
271         pParentItem = FX_NEW CFWL_WidgetMgrItem;\r
272         pParentItem->pWidget = pParent;\r
273         m_mapWidgetItem.SetAt(pParent, pParentItem);\r
274         CFWL_WidgetMgrItem *pRoot = GetWidgetMgrItem(NULL);\r
275         pParentItem->pParent = pRoot;\r
276         SetWidgetIndex(pParent, -1);\r
277     }\r
278     CFWL_WidgetMgrItem *pItem = GetWidgetMgrItem(pChild);\r
279     if (!pItem) {\r
280         pItem = FX_NEW CFWL_WidgetMgrItem;\r
281         pItem->pWidget = pChild;\r
282         m_mapWidgetItem.SetAt(pChild, pItem);\r
283     }\r
284     if (pItem->pParent && pItem->pParent != pParentItem) {\r
285         if (pItem->pPrevious) {\r
286             pItem->pPrevious->pNext = pItem->pNext;\r
287         }\r
288         if (pItem->pNext) {\r
289             pItem->pNext->pPrevious = pItem->pPrevious;\r
290         }\r
291         if (pItem->pParent->pChild == pItem) {\r
292             pItem->pParent->pChild = pItem->pNext;\r
293         }\r
294     }\r
295     pItem->pParent = pParentItem;\r
296     SetWidgetIndex(pChild, nIndex);\r
297 }\r
298 void CFWL_WidgetMgr::RemoveWidget(IFWL_Widget *pWidget)\r
299 {\r
300     CFWL_WidgetMgrItem *pItem = GetWidgetMgrItem(pWidget);\r
301     if (!pItem) {\r
302         return;\r
303     }\r
304     if (pItem->pPrevious) {\r
305         pItem->pPrevious->pNext = pItem->pNext;\r
306     }\r
307     if (pItem->pNext) {\r
308         pItem->pNext->pPrevious = pItem->pPrevious;\r
309     }\r
310     if (pItem->pParent && pItem->pParent->pChild == pItem) {\r
311         pItem->pParent->pChild = pItem->pNext;\r
312     }\r
313     CFWL_WidgetMgrItem *pChild = pItem->pChild;\r
314     while (pChild) {\r
315         CFWL_WidgetMgrItem *pNext = pChild->pNext;\r
316         RemoveWidget(pChild->pWidget);\r
317         pChild = pNext;\r
318     }\r
319     m_mapWidgetItem.RemoveKey(pWidget);\r
320     delete pItem;\r
321 }\r
322 void CFWL_WidgetMgr::SetOwner(IFWL_Widget *pOwner, IFWL_Widget *pOwned)\r
323 {\r
324     CFWL_WidgetMgrItem *pParentItem = GetWidgetMgrItem(pOwner);\r
325     if (!pParentItem) {\r
326         pParentItem = FX_NEW CFWL_WidgetMgrItem;\r
327         pParentItem->pWidget = pOwner;\r
328         m_mapWidgetItem.SetAt(pOwner, pParentItem);\r
329         CFWL_WidgetMgrItem *pRoot = GetWidgetMgrItem(NULL);\r
330         pParentItem->pParent = pRoot;\r
331         SetWidgetIndex(pOwner, -1);\r
332     }\r
333     CFWL_WidgetMgrItem *pItem = GetWidgetMgrItem(pOwned);\r
334     if (!pItem) {\r
335         pItem = FX_NEW CFWL_WidgetMgrItem;\r
336         pItem->pWidget = pOwned;\r
337         m_mapWidgetItem.SetAt(pOwned, pItem);\r
338     }\r
339     pItem->pOwner = pParentItem;\r
340 }\r
341 void CFWL_WidgetMgr::SetParent(IFWL_Widget *pParent, IFWL_Widget *pChild)\r
342 {\r
343     CFWL_WidgetMgrItem *pParentItem = GetWidgetMgrItem(pParent);\r
344     CFWL_WidgetMgrItem *pItem = GetWidgetMgrItem(pChild);\r
345     _FWL_RETURN_IF_FAIL(pItem);\r
346     if (pItem->pParent && pItem->pParent != pParentItem) {\r
347         if (pItem->pPrevious) {\r
348             pItem->pPrevious->pNext = pItem->pNext;\r
349         }\r
350         if (pItem->pNext) {\r
351             pItem->pNext->pPrevious = pItem->pPrevious;\r
352         }\r
353         if (pItem->pParent->pChild == pItem) {\r
354             pItem->pParent->pChild = pItem->pNext;\r
355         }\r
356         pItem->pNext = NULL;\r
357         pItem->pPrevious = NULL;\r
358     }\r
359     pItem->pParent = pParentItem;\r
360     SetWidgetIndex(pChild, -1);\r
361     _FWL_RETURN_IF_FAIL(m_pAdapter);\r
362     m_pAdapter->SetParentWidget(pChild, pParent);\r
363 }\r
364 FX_BOOL CFWL_WidgetMgr::IsChild(IFWL_Widget *pChild, IFWL_Widget *pParent)\r
365 {\r
366     IFWL_Widget *pTemp = pChild;\r
367     do {\r
368         if (pTemp == pParent) {\r
369             return TRUE;\r
370         }\r
371         pTemp = GetWidget(pTemp, FWL_WGTRELATION_Parent);\r
372     } while (pTemp);\r
373     return FALSE;\r
374 }\r
375 FWL_ERR CFWL_WidgetMgr::CreateWidget_Native(IFWL_Widget *pWidget)\r
376 {\r
377     if (!IsAbleNative(pWidget)) {\r
378         return FWL_ERR_Succeeded;\r
379     }\r
380     return m_pAdapter->CreateWidget(pWidget, pWidget->GetOwner());\r
381 }\r
382 FWL_ERR CFWL_WidgetMgr::DestroyWidget_Native(IFWL_Widget *pWidget)\r
383 {\r
384     if (!IsAbleNative(pWidget)) {\r
385         return FWL_ERR_Succeeded;\r
386     }\r
387     return m_pAdapter->DestroyWidget(pWidget);\r
388 }\r
389 FWL_ERR CFWL_WidgetMgr::GetWidgetRect_Native(IFWL_Widget *pWidget, CFX_RectF &rect)\r
390 {\r
391     if (!IsAbleNative(pWidget)) {\r
392         return FWL_ERR_Succeeded;\r
393     }\r
394     return m_pAdapter->GetWidgetRect(pWidget, rect);\r
395 }\r
396 FWL_ERR CFWL_WidgetMgr::SetWidgetRect_Native(IFWL_Widget *pWidget, const CFX_RectF &rect)\r
397 {\r
398     if (FWL_UseOffscreen(pWidget)) {\r
399         CFWL_WidgetMgrItem *pItem = GetWidgetMgrItem(pWidget);\r
400         pItem->iRedrawCounter ++;\r
401         if (pItem->pOffscreen) {\r
402             CFX_RenderDevice *pDevice = pItem->pOffscreen->GetRenderDevice();\r
403             if (pDevice && pDevice->GetBitmap()) {\r
404                 CFX_DIBitmap *pBitmap = pDevice->GetBitmap();\r
405                 if (pBitmap->GetWidth() - rect.width > 1 || pBitmap->GetHeight() - rect.height > 1) {\r
406                     delete pItem->pOffscreen;\r
407                     pItem->pOffscreen = NULL;\r
408                 }\r
409             }\r
410         }\r
411 #if (_FX_OS_==_FX_WIN32_DESKTOP_) || (_FX_OS_==_FX_WIN64_)\r
412         pItem->bOutsideChanged = !m_rtScreen.Contains(rect);\r
413 #endif\r
414     }\r
415     return m_pAdapter->SetWidgetRect(pWidget, rect);\r
416 }\r
417 FWL_ERR CFWL_WidgetMgr::SetWidgetPosition_Native(IFWL_Widget *pWidget, FX_FLOAT fx, FX_FLOAT fy)\r
418 {\r
419     return m_pAdapter->SetWidgetPosition(pWidget, fx, fy);\r
420 }\r
421 FWL_ERR CFWL_WidgetMgr::SetWidgetIcon_Native(IFWL_Widget *pWidget, const CFX_DIBitmap *pIcon, FX_BOOL bBig)\r
422 {\r
423     return m_pAdapter->SetWidgetIcon(pWidget, pIcon, bBig);\r
424 }\r
425 FWL_ERR CFWL_WidgetMgr::SetWidgetCaption_Native(IFWL_Widget *pWidget, FX_WSTR wsCaption)\r
426 {\r
427     return m_pAdapter->SetWidgetCaption(pWidget, wsCaption);\r
428 }\r
429 FWL_ERR CFWL_WidgetMgr::SetBorderRegion_Native(IFWL_Widget *pWidget, CFX_Path *pPath)\r
430 {\r
431     return m_pAdapter->SetBorderRegion(pWidget, pPath);\r
432 }\r
433 FWL_ERR CFWL_WidgetMgr::ShowWidget_Native(IFWL_Widget *pWidget)\r
434 {\r
435     return m_pAdapter->ShowWidget(pWidget);\r
436 }\r
437 FWL_ERR CFWL_WidgetMgr::HideWidget_Native(IFWL_Widget *pWidget)\r
438 {\r
439     return m_pAdapter->HideWidget(pWidget);\r
440 }\r
441 FWL_ERR CFWL_WidgetMgr::SetNormal_Native(IFWL_Widget *pWidget)\r
442 {\r
443     return m_pAdapter->SetNormal(pWidget);\r
444 }\r
445 FWL_ERR CFWL_WidgetMgr::SetMaximize_Native(IFWL_Widget *pWidget)\r
446 {\r
447     return m_pAdapter->SetMaximize(pWidget);\r
448 }\r
449 FWL_ERR CFWL_WidgetMgr::SetMinimize_Native(IFWL_Widget *pWidget)\r
450 {\r
451     return m_pAdapter->SetMinimize(pWidget);\r
452 }\r
453 FX_BOOL CFWL_WidgetMgr::CheckMessage_Native()\r
454 {\r
455     return m_pAdapter->CheckMessage();\r
456 }\r
457 FWL_ERR CFWL_WidgetMgr::DispatchMessage_Native()\r
458 {\r
459     return m_pAdapter->DispatchMessage();\r
460 }\r
461 FX_BOOL CFWL_WidgetMgr::IsIdleMessage_Native()\r
462 {\r
463     return m_pAdapter->IsIdleMessage();\r
464 }\r
465 FWL_ERR CFWL_WidgetMgr::Exit_Native(FX_INT32 iExitCode)\r
466 {\r
467     return m_pAdapter->Exit(iExitCode);\r
468 }\r
469 FWL_ERR CFWL_WidgetMgr::CreateWidgetWithNativeId_Native(IFWL_Widget *pWidget, void *vp)\r
470 {\r
471     return m_pAdapter->CreateWidgetWithNativeId(pWidget, vp);\r
472 }\r
473 IFWL_Widget* CFWL_WidgetMgr::GetWidgetAtPoint(IFWL_Widget * parent, FX_FLOAT x, FX_FLOAT y)\r
474 {\r
475     _FWL_RETURN_VALUE_IF_FAIL(parent, NULL);\r
476     FX_FLOAT x1;\r
477     FX_FLOAT y1;\r
478     IFWL_Widget * child = GetWidget(parent, FWL_WGTRELATION_LastChild);\r
479     while (child) {\r
480         if ((child->GetStates() & FWL_WGTSTATE_Invisible) == 0) {\r
481             x1 = x;\r
482             y1 = y;\r
483             CFX_Matrix matrixOnParent;\r
484             child->GetMatrix(matrixOnParent);\r
485             CFX_Matrix m;\r
486             m.Reset();\r
487             m.SetReverse(matrixOnParent);\r
488             m.TransformPoint(x1, y1);\r
489             CFX_RectF bounds;\r
490             child->GetWidgetRect(bounds);\r
491             if (bounds.Contains(x1, y1)) {\r
492                 x1 -= bounds.left;\r
493                 y1 -= bounds.top;\r
494                 return GetWidgetAtPoint(child, x1, y1);\r
495             }\r
496         }\r
497         child = GetWidget(child, FWL_WGTRELATION_PriorSibling);\r
498     }\r
499     return parent;\r
500 }\r
501 void CFWL_WidgetMgr::NotifySizeChanged(IFWL_Widget *pForm, FX_FLOAT fx, FX_FLOAT fy)\r
502 {\r
503     if (!FWL_UseOffscreen(pForm)) {\r
504         return;\r
505     }\r
506     CFWL_WidgetMgrItem *pItem = GetWidgetMgrItem(pForm);\r
507     if (pItem->pOffscreen) {\r
508         delete pItem->pOffscreen;\r
509         pItem->pOffscreen = NULL;\r
510     }\r
511 }\r
512 IFWL_Widget* CFWL_WidgetMgr::nextTab(IFWL_Widget *parent, IFWL_Widget *focus, FX_BOOL &bFind)\r
513 {\r
514     IFWL_Widget *child = FWL_GetWidgetMgr()->GetWidget(parent, FWL_WGTRELATION_FirstChild);\r
515     while (child) {\r
516         if (focus == child) {\r
517             bFind = TRUE;\r
518         }\r
519         if ((child->GetStyles() & FWL_WGTSTYLE_TabStop) && (!focus || (focus != child && bFind))) {\r
520             return child;\r
521         }\r
522         IFWL_Widget *bRet = nextTab(child, focus, bFind);\r
523         if (bRet) {\r
524             return bRet;\r
525         }\r
526         child = FWL_GetWidgetMgr()->GetWidget(child, FWL_WGTRELATION_NextSibling);\r
527     }\r
528     return NULL;\r
529 }\r
530 FX_INT32 CFWL_WidgetMgr::CountRadioButtonGroup(IFWL_Widget *pFirst)\r
531 {\r
532     FX_INT32 iRet = 0;\r
533     IFWL_Widget *pChild = pFirst;\r
534     while (pChild) {\r
535         if ((pChild->GetStyles() & FWL_WGTSTYLE_Group) && pChild->GetClassID() == 3811304691) {\r
536             iRet ++;\r
537         }\r
538         pChild = GetWidget(pChild, FWL_WGTRELATION_NextSibling);\r
539     }\r
540     return iRet;\r
541 }\r
542 IFWL_Widget* CFWL_WidgetMgr::GetSiblingRadioButton(IFWL_Widget *pWidget, FX_BOOL bNext)\r
543 {\r
544     while ((pWidget = GetWidget(pWidget, bNext ? FWL_WGTRELATION_NextSibling : FWL_WGTRELATION_PriorSibling)) != NULL) {\r
545         if (pWidget->GetClassID() == 3811304691) {\r
546             return pWidget;\r
547         }\r
548     }\r
549     return NULL;\r
550 }\r
551 IFWL_Widget* CFWL_WidgetMgr::GetRadioButtonGroupHeader(IFWL_Widget *pRadioButton)\r
552 {\r
553     if (pRadioButton->GetStyles() & FWL_WGTSTYLE_Group) {\r
554         return pRadioButton;\r
555     }\r
556     IFWL_Widget *pNext = pRadioButton;\r
557     while ((pNext = GetSiblingRadioButton(pNext, FALSE)) != NULL) {\r
558         if (pNext->GetStyles() & FWL_WGTSTYLE_Group) {\r
559             return pNext;\r
560         }\r
561     }\r
562     pNext = GetWidget(pRadioButton, FWL_WGTRELATION_LastSibling);\r
563     if ((pNext->GetStyles() & FWL_WGTSTYLE_Group) && pNext->GetClassID() == 3811304691) {\r
564         return pNext;\r
565     }\r
566     while ((pNext = GetSiblingRadioButton(pNext, FALSE)) && pNext && pNext != pRadioButton) {\r
567         if (pNext->GetStyles() & FWL_WGTSTYLE_Group) {\r
568             return pNext;\r
569         }\r
570     }\r
571     pNext = GetWidget(pRadioButton, FWL_WGTRELATION_FirstSibling);\r
572     if (pNext && (pNext->GetStyles() == FWL_WGTSTYLE_Group) && pNext->GetClassID() == 3811304691) {\r
573         return pNext;\r
574     }\r
575     return GetSiblingRadioButton(pNext, TRUE);\r
576 }\r
577 void CFWL_WidgetMgr::GetSameGroupRadioButton(IFWL_Widget *pRadioButton, CFX_PtrArray &group)\r
578 {\r
579     IFWL_Widget *pFirst = GetWidget(pRadioButton, FWL_WGTRELATION_FirstSibling);\r
580     if (!pFirst) {\r
581         pFirst = pRadioButton;\r
582     }\r
583     FX_INT32 iGroup = CountRadioButtonGroup(pFirst);\r
584     if (iGroup < 2) {\r
585         if (pFirst->GetClassID() == 3811304691) {\r
586             group.Add(pFirst);\r
587         }\r
588         IFWL_Widget *pNext = pFirst;\r
589         while ((pNext = GetSiblingRadioButton(pNext, TRUE)) != NULL) {\r
590             group.Add(pNext);\r
591         }\r
592         return;\r
593     }\r
594     IFWL_Widget *pNext = GetRadioButtonGroupHeader(pRadioButton);\r
595     do {\r
596         group.Add(pNext);\r
597         pNext = GetSiblingRadioButton(pNext, TRUE);\r
598         if (!pNext) {\r
599             if (pFirst->GetClassID() == 3811304691) {\r
600                 pNext = pFirst;\r
601             } else {\r
602                 pNext = GetSiblingRadioButton(pFirst, TRUE);\r
603             }\r
604         }\r
605     } while (pNext && ((pNext->GetStyles() & FWL_WGTSTYLE_Group) == 0));\r
606 }\r
607 IFWL_Widget* CFWL_WidgetMgr::GetDefaultButton(IFWL_Widget *pParent)\r
608 {\r
609     if ((pParent->GetClassID() == 3521614244) && (pParent->GetStates() & (1 << (FWL_WGTSTATE_MAX + 2)))) {\r
610         return pParent;\r
611     }\r
612     IFWL_Widget *child = FWL_GetWidgetMgr()->GetWidget(pParent, FWL_WGTRELATION_FirstChild);\r
613     while (child) {\r
614         if ((child->GetClassID() == 3521614244) && (child->GetStates() & (1 << (FWL_WGTSTATE_MAX + 2)))) {\r
615             return child;\r
616         }\r
617         IFWL_Widget *find = GetDefaultButton(child);\r
618         if (find) {\r
619             return find;\r
620         }\r
621         child = FWL_GetWidgetMgr()->GetWidget(child, FWL_WGTRELATION_NextSibling);\r
622     }\r
623     return NULL;\r
624 }\r
625 void CFWL_WidgetMgr::AddRedrawCounts(IFWL_Widget *pWidget)\r
626 {\r
627     CFWL_WidgetMgrItem *pItem = GetWidgetMgrItem(pWidget);\r
628     (pItem->iRedrawCounter)++;\r
629 }\r
630 void CFWL_WidgetMgr::ResetRedrawCounts(IFWL_Widget *pWidget)\r
631 {\r
632     CFWL_WidgetMgrItem *pItem = GetWidgetMgrItem(pWidget);\r
633     pItem->iRedrawCounter = 0;\r
634 }\r
635 CFWL_WidgetMgrItem* CFWL_WidgetMgr::GetWidgetMgrItem(IFWL_Widget *pWidget)\r
636 {\r
637     return (CFWL_WidgetMgrItem*)m_mapWidgetItem.GetValueAt(pWidget);\r
638 }\r
639 FX_INT32 CFWL_WidgetMgr::TravelWidgetMgr(CFWL_WidgetMgrItem *pParent, FX_INT32 *pIndex, CFWL_WidgetMgrItem *pItem, IFWL_Widget **pWidget )\r
640 {\r
641     if (!pParent) {\r
642         return 0;\r
643     }\r
644     FX_INT32 iCount = 0;\r
645     CFWL_WidgetMgrItem *pChild = pParent->pChild;\r
646     while (pChild) {\r
647         iCount ++;\r
648         if (pIndex) {\r
649             if (*pIndex == 0) {\r
650                 *pWidget = pChild->pWidget;\r
651                 return iCount;\r
652             }\r
653             pIndex --;\r
654         }\r
655         if (pItem && pItem == pChild) {\r
656             return iCount - 1;\r
657         }\r
658         pChild = pChild->pNext;\r
659     }\r
660     if (pIndex) {\r
661         return 0;\r
662     } else if (pItem) {\r
663         return -1;\r
664     }\r
665     return iCount - 1;\r
666 }\r
667 FX_BOOL CFWL_WidgetMgr::IsAbleNative(IFWL_Widget *pWidget)\r
668 {\r
669     _FWL_RETURN_VALUE_IF_FAIL(pWidget, FALSE);\r
670     if (!pWidget->IsInstance(FX_WSTRC(FWL_CLASS_Form))) {\r
671         return FALSE;\r
672     }\r
673     FX_DWORD dwStyles = pWidget->GetStyles();\r
674     return ((dwStyles & FWL_WGTSTYLE_WindowTypeMask) == FWL_WGTSTYLE_OverLapper) || (dwStyles & FWL_WGTSTYLE_Popup);\r
675 }\r
676 FX_BOOL CFWL_WidgetMgr::IsThreadEnabled()\r
677 {\r
678     return !(m_dwCapability & FWL_WGTMGR_DisableThread);\r
679 }\r
680 FX_BOOL CFWL_WidgetMgr::IsFormDisabled()\r
681 {\r
682     return m_dwCapability & FWL_WGTMGR_DisableForm;\r
683 }\r
684 FX_BOOL CFWL_WidgetMgr::GetAdapterPopupPos(IFWL_Widget* pWidget, FX_FLOAT fMinHeight, FX_FLOAT fMaxHeight, const CFX_RectF &rtAnchor, CFX_RectF &rtPopup)\r
685 {\r
686     IFWL_AdapterWidgetMgr* pSDApapter = GetAdapterWidgetMgr();\r
687     return pSDApapter->GetPopupPos(pWidget, fMinHeight, fMaxHeight, rtAnchor, rtPopup);\r
688 }\r
689 CFWL_WidgetMgrDelegate::CFWL_WidgetMgrDelegate(CFWL_WidgetMgr *pWidgetMgr)\r
690     : m_pWidgetMgr(pWidgetMgr)\r
691 {\r
692 }\r
693 FWL_ERR CFWL_WidgetMgrDelegate::OnSetCapability(FX_DWORD dwCapability )\r
694 {\r
695     m_pWidgetMgr->m_dwCapability = dwCapability;\r
696     return FWL_ERR_Succeeded;\r
697 }\r
698 FX_INT32 CFWL_WidgetMgrDelegate::OnProcessMessageToForm(CFWL_Message *pMessage)\r
699 {\r
700     _FWL_RETURN_VALUE_IF_FAIL(pMessage, 0);\r
701     _FWL_RETURN_VALUE_IF_FAIL(pMessage->m_pDstTarget, 0);\r
702     IFWL_Widget *pDstWidget = (IFWL_Widget*)pMessage->m_pDstTarget;\r
703     IFWL_NoteThread *pNoteThread = pDstWidget->GetOwnerThread();\r
704     _FWL_RETURN_VALUE_IF_FAIL(pNoteThread, 0);\r
705     CFWL_NoteDriver *pNoteDriver = (CFWL_NoteDriver*)pNoteThread->GetNoteDriver();\r
706     _FWL_RETURN_VALUE_IF_FAIL(pNoteDriver, 0);\r
707     if (m_pWidgetMgr->IsThreadEnabled()) {\r
708         pMessage = (CFWL_Message*)pMessage->Clone();\r
709     }\r
710     if (m_pWidgetMgr->IsFormDisabled()) {\r
711         pNoteDriver->ProcessMessage(pMessage);\r
712     } else {\r
713         pNoteDriver->QueueMessage(pMessage);\r
714     }\r
715 #if (_FX_OS_==_FX_MACOSX_)\r
716     CFWL_NoteLoop *pTopLoop = pNoteDriver->GetTopLoop();\r
717     if (pTopLoop) {\r
718         pNoteDriver->UnqueueMessage(pTopLoop);\r
719     }\r
720 #endif\r
721     if (m_pWidgetMgr->IsThreadEnabled()) {\r
722         pMessage->Release();\r
723     }\r
724     return FWL_ERR_Succeeded;\r
725 }\r
726 FWL_ERR CFWL_WidgetMgrDelegate::OnDrawWidget(IFWL_Widget *        pWidget,\r
727         CFX_Graphics *    pGraphics,\r
728         const CFX_Matrix * pMatrix )\r
729 {\r
730     _FWL_RETURN_VALUE_IF_FAIL(pWidget, FWL_ERR_Indefinite);\r
731     _FWL_RETURN_VALUE_IF_FAIL(pGraphics, FWL_ERR_Indefinite);\r
732     CFX_Graphics *pTemp = DrawWidgetBefore(pWidget, pGraphics, pMatrix);\r
733     CFX_RectF clipCopy;\r
734     pWidget->GetWidgetRect(clipCopy);\r
735     clipCopy.left = clipCopy.top = 0;\r
736     if (bUseOffscreenDirect(pWidget)) {\r
737         DrawWidgetAfter(pWidget, pGraphics, clipCopy, pMatrix);\r
738         return FWL_ERR_Succeeded;\r
739     }\r
740     CFX_RectF clipBounds;\r
741 #if (_FX_OS_==_FX_WIN32_DESKTOP_) || (_FX_OS_==_FX_WIN64_) || (_FX_OS_ == _FX_LINUX_DESKTOP_) || (_FX_OS_ == _FX_LINUX_EMBEDDED_) || (_FX_OS_ == _FX_ANDROID_)\r
742     IFWL_WidgetDelegate *pDelegate = pWidget->SetDelegate(NULL);\r
743     pDelegate->OnDrawWidget(pTemp, pMatrix);\r
744     pGraphics->GetClipRect(clipBounds);\r
745     clipCopy = clipBounds;\r
746 #elif (_FX_OS_==_FX_MACOSX_)\r
747     if (m_pWidgetMgr->IsFormDisabled()) {\r
748         IFWL_WidgetDelegate *pDelegate = pWidget->SetDelegate(NULL);\r
749         pDelegate->OnDrawWidget(pTemp, pMatrix);\r
750         pGraphics->GetClipRect(clipBounds);\r
751         clipCopy = clipBounds;\r
752     } else {\r
753         clipBounds.Set(pMatrix->a, pMatrix->b, pMatrix->c, pMatrix->d);\r
754         ((CFX_Matrix*)pMatrix)->Reset();\r
755 #ifdef FWL_UseMacSystemBorder\r
756 #else\r
757 #endif\r
758         {\r
759             IFWL_WidgetDelegate *pDelegate = pWidget->SetDelegate(NULL);\r
760             pDelegate->OnDrawWidget(pTemp, pMatrix);\r
761         }\r
762     }\r
763 #endif\r
764     if (!m_pWidgetMgr->IsFormDisabled()) {\r
765         CFX_RectF rtClient;\r
766         pWidget->GetClientRect(rtClient);\r
767         clipBounds.Intersect(rtClient);\r
768     }\r
769     if (!clipBounds.IsEmpty()) {\r
770         DrawChild(pWidget, clipBounds, pTemp, pMatrix);\r
771     }\r
772     DrawWidgetAfter(pWidget, pGraphics, clipCopy, pMatrix);\r
773     m_pWidgetMgr->ResetRedrawCounts(pWidget);\r
774     return FWL_ERR_Succeeded;\r
775 }\r
776 void CFWL_WidgetMgrDelegate::DrawChild(IFWL_Widget*       parent,\r
777                                        const CFX_RectF& rtClip,\r
778                                        CFX_Graphics*     pGraphics,\r
779                                        const CFX_Matrix* pMatrix )\r
780 {\r
781     _FWL_RETURN_IF_FAIL(parent);\r
782     FX_BOOL bFormDisable = m_pWidgetMgr->IsFormDisabled();\r
783     IFWL_Widget* pNextChild = m_pWidgetMgr->GetWidget(parent, FWL_WGTRELATION_FirstChild);\r
784     while (pNextChild) {\r
785         IFWL_Widget* child = pNextChild;\r
786         pNextChild = m_pWidgetMgr->GetWidget(child, FWL_WGTRELATION_NextSibling);\r
787         if (child->GetStates() & FWL_WGTSTATE_Invisible) {\r
788             continue;\r
789         }\r
790         CFX_RectF       rtWidget;\r
791         child->GetWidgetRect(rtWidget);\r
792         if (rtWidget.IsEmpty()) {\r
793             continue;\r
794         }\r
795         CFX_Matrix      widgetMatrix;\r
796         CFX_RectF clipBounds(rtWidget);\r
797         if(!bFormDisable) {\r
798             child->GetMatrix(widgetMatrix, TRUE);\r
799         }\r
800         if (pMatrix) {\r
801             widgetMatrix.Concat(*pMatrix);\r
802         }\r
803         if (!bFormDisable) {\r
804             widgetMatrix.TransformPoint(clipBounds.left, clipBounds.top);\r
805             clipBounds.Intersect(rtClip);\r
806             if (clipBounds.IsEmpty()) {\r
807                 continue;\r
808             }\r
809             pGraphics->SaveGraphState();\r
810             pGraphics->SetClipRect(clipBounds);\r
811         }\r
812         widgetMatrix.Translate(rtWidget.left, rtWidget.top, TRUE);\r
813         IFWL_WidgetDelegate *pDelegate = child->SetDelegate(NULL);\r
814         if (pDelegate) {\r
815             if (m_pWidgetMgr->IsFormDisabled() || IsNeedRepaint(child, &widgetMatrix, rtClip)) {\r
816                 pDelegate->OnDrawWidget(pGraphics, &widgetMatrix);\r
817             }\r
818         }\r
819         if (!bFormDisable) {\r
820             pGraphics->RestoreGraphState();\r
821         }\r
822         DrawChild(child, clipBounds, pGraphics, bFormDisable ? &widgetMatrix : pMatrix);\r
823         child = m_pWidgetMgr->GetWidget(child, FWL_WGTRELATION_NextSibling);\r
824     }\r
825 }\r
826 CFX_Graphics* CFWL_WidgetMgrDelegate::DrawWidgetBefore(IFWL_Widget *pWidget, CFX_Graphics *pGraphics, const CFX_Matrix *pMatrix)\r
827 {\r
828     if (!FWL_UseOffscreen(pWidget)) {\r
829         return pGraphics;\r
830     }\r
831     CFWL_WidgetMgrItem *pItem = m_pWidgetMgr->GetWidgetMgrItem(pWidget);\r
832     if (!pItem->pOffscreen) {\r
833         pItem->pOffscreen = FX_NEW CFX_Graphics;\r
834         CFX_RectF rect;\r
835         pWidget->GetWidgetRect(rect);\r
836         pItem->pOffscreen->Create((FX_INT32)rect.width, (FX_INT32)rect.height, FXDIB_Argb);\r
837     }\r
838     CFX_RectF rect;\r
839     pGraphics->GetClipRect(rect);\r
840     pItem->pOffscreen->SetClipRect(rect);\r
841     return pItem->pOffscreen;\r
842 }\r
843 void CFWL_WidgetMgrDelegate::DrawWidgetAfter(IFWL_Widget *pWidget, CFX_Graphics *pGraphics, CFX_RectF &rtClip, const CFX_Matrix *pMatrix)\r
844 {\r
845     if (FWL_UseOffscreen(pWidget)) {\r
846         CFWL_WidgetMgrItem *pItem = m_pWidgetMgr->GetWidgetMgrItem(pWidget);\r
847         pGraphics->Transfer(pItem->pOffscreen, rtClip.left, rtClip.top, rtClip, (CFX_Matrix*)pMatrix);\r
848 #ifdef _WIN32\r
849         pItem->pOffscreen->ClearClip();\r
850 #endif\r
851     }\r
852     CFWL_WidgetMgrItem *pItem = m_pWidgetMgr->GetWidgetMgrItem(pWidget);\r
853     pItem->iRedrawCounter = 0;\r
854 }\r
855 #define FWL_NEEDREPAINTHIT_Point        12\r
856 #define FWL_NEEDREPAINTHIT_Piece        3\r
857 typedef struct _FWL_NeedRepaintHitData {\r
858     CFX_PointF hitPoint;\r
859     FX_BOOL bNotNeedRepaint;\r
860     FX_BOOL bNotContainByDirty;\r
861 } FWL_NeedRepaintHitData;\r
862 FX_BOOL CFWL_WidgetMgrDelegate::IsNeedRepaint(IFWL_Widget *pWidget, CFX_Matrix *pMatrix, const CFX_RectF &rtDirty)\r
863 {\r
864     CFWL_WidgetMgrItem * pItem = m_pWidgetMgr->GetWidgetMgrItem(pWidget);\r
865     if (pItem && pItem->iRedrawCounter > 0) {\r
866         pItem->iRedrawCounter = 0;\r
867         return TRUE;\r
868     }\r
869     CFX_RectF rtWidget;\r
870     pWidget->GetWidgetRect(rtWidget);\r
871     rtWidget.left = rtWidget.top = 0;\r
872     pMatrix->TransformRect(rtWidget);\r
873     if (!rtWidget.IntersectWith(rtDirty)) {\r
874         return FALSE;\r
875     }\r
876     IFWL_Widget * pChild = FWL_GetWidgetMgr()->GetWidget(pWidget, FWL_WGTRELATION_FirstChild);\r
877     if (!pChild) {\r
878         return TRUE;\r
879     }\r
880     if (pChild->GetClassID() == 3150298670) {\r
881         CFX_RectF rtTemp;\r
882         pChild->GetWidgetRect(rtTemp);\r
883         if (rtTemp.width >= rtWidget.width && rtTemp.height >= rtWidget.height) {\r
884             pChild = FWL_GetWidgetMgr()->GetWidget(pChild, FWL_WGTRELATION_FirstChild);\r
885             if (!pChild) {\r
886                 return TRUE;\r
887             }\r
888         }\r
889     }\r
890     CFX_RectF rtChilds;\r
891     rtChilds.Empty();\r
892     FX_BOOL bChildIntersectWithDirty = FALSE;\r
893     FX_BOOL bOrginPtIntersectWidthChild = FALSE;\r
894     FX_BOOL bOrginPtIntersectWidthDirty = rtDirty.Contains(rtWidget.left, rtWidget.top);\r
895     static FWL_NeedRepaintHitData hitPoint[FWL_NEEDREPAINTHIT_Point];\r
896     static FX_INT32 iSize = sizeof(FWL_NeedRepaintHitData);\r
897     FXSYS_memset(hitPoint, 0, iSize);\r
898     FX_FLOAT fxPiece = rtWidget.width / FWL_NEEDREPAINTHIT_Piece;\r
899     FX_FLOAT fyPiece = rtWidget.height / FWL_NEEDREPAINTHIT_Piece;\r
900     hitPoint[2].hitPoint.x = hitPoint[6].hitPoint.x = rtWidget.left;\r
901     hitPoint[0].hitPoint.x = hitPoint[3].hitPoint.x = hitPoint[7].hitPoint.x = hitPoint[10].hitPoint.x = fxPiece + rtWidget.left;\r
902     hitPoint[1].hitPoint.x = hitPoint[4].hitPoint.x = hitPoint[8].hitPoint.x = hitPoint[11].hitPoint.x = fxPiece * 2 + rtWidget.left;\r
903     hitPoint[5].hitPoint.x = hitPoint[9].hitPoint.x = rtWidget.width + rtWidget.left;\r
904     hitPoint[0].hitPoint.y = hitPoint[1].hitPoint.y = rtWidget.top;\r
905     hitPoint[2].hitPoint.y = hitPoint[3].hitPoint.y = hitPoint[4].hitPoint.y = hitPoint[5].hitPoint.y = fyPiece + rtWidget.top;\r
906     hitPoint[6].hitPoint.y = hitPoint[7].hitPoint.y = hitPoint[8].hitPoint.y = hitPoint[9].hitPoint.y = fyPiece * 2 + rtWidget.top;\r
907     hitPoint[10].hitPoint.y = hitPoint[11].hitPoint.y = rtWidget.height + rtWidget.top;\r
908     do {\r
909         CFX_RectF rect;\r
910         pChild->GetWidgetRect(rect);\r
911         CFX_RectF r = rect;\r
912         r.left += rtWidget.left;\r
913         r.top += rtWidget.top;\r
914         if (r.IsEmpty()) {\r
915             continue;\r
916         }\r
917         if (r.Contains(rtDirty)) {\r
918             return FALSE;\r
919         }\r
920         if (!bChildIntersectWithDirty && r.IntersectWith(rtDirty)) {\r
921             bChildIntersectWithDirty = TRUE;\r
922         }\r
923         if (bOrginPtIntersectWidthDirty && !bOrginPtIntersectWidthChild) {\r
924             bOrginPtIntersectWidthChild = rect.Contains(0, 0);\r
925         }\r
926         if (rtChilds.IsEmpty()) {\r
927             rtChilds = rect;\r
928         } else if (!(pChild->GetStates() & FWL_WGTSTATE_Invisible)) {\r
929             rtChilds.Union(rect);\r
930         }\r
931         for (FX_INT32 i = 0; i < FWL_NEEDREPAINTHIT_Point; i ++) {\r
932             if (hitPoint[i].bNotContainByDirty || hitPoint[i].bNotNeedRepaint) {\r
933                 continue;\r
934             }\r
935             if (!rtDirty.Contains(hitPoint[i].hitPoint)) {\r
936                 hitPoint[i].bNotContainByDirty = TRUE;\r
937                 continue;\r
938             }\r
939             if (r.Contains(hitPoint[i].hitPoint)) {\r
940                 hitPoint[i].bNotNeedRepaint = TRUE;\r
941             }\r
942         }\r
943     } while ((pChild = FWL_GetWidgetMgr()->GetWidget(pChild, FWL_WGTRELATION_NextSibling)) != NULL);\r
944     if (!bChildIntersectWithDirty) {\r
945         return TRUE;\r
946     }\r
947     if (bOrginPtIntersectWidthDirty && !bOrginPtIntersectWidthChild) {\r
948         return TRUE;\r
949     }\r
950     if (rtChilds.IsEmpty()) {\r
951         return TRUE;\r
952     }\r
953     FX_INT32 repaintPoint = FWL_NEEDREPAINTHIT_Point;\r
954     for (FX_INT32 i = 0; i < FWL_NEEDREPAINTHIT_Point; i ++) {\r
955         if (hitPoint[i].bNotNeedRepaint) {\r
956             repaintPoint --;\r
957         }\r
958     }\r
959     if (repaintPoint > 0) {\r
960         return TRUE;\r
961     }\r
962     pMatrix->TransformRect(rtChilds);\r
963     if (rtChilds.Contains(rtDirty) || rtChilds.Contains(rtWidget)) {\r
964         return FALSE;\r
965     }\r
966     return TRUE;\r
967 }\r
968 FX_BOOL CFWL_WidgetMgrDelegate::bUseOffscreenDirect(IFWL_Widget *pWidget)\r
969 {\r
970     CFWL_WidgetMgrItem *pItem = m_pWidgetMgr->GetWidgetMgrItem(pWidget);\r
971     if (!FWL_UseOffscreen(pWidget) || !(pItem->pOffscreen)) {\r
972         return FALSE;\r
973     }\r
974 #if (_FX_OS_==_FX_WIN32_DESKTOP_) || (_FX_OS_==_FX_WIN64_)\r
975     if (pItem->bOutsideChanged) {\r
976         CFX_RectF r;\r
977         pWidget->GetWidgetRect(r);\r
978         CFX_RectF temp(m_pWidgetMgr->m_rtScreen);\r
979         temp.Deflate(50, 50);\r
980         if (!temp.Contains(r)) {\r
981             return FALSE;\r
982         }\r
983         pItem->bOutsideChanged = FALSE;\r
984     }\r
985 #endif\r
986     return pItem->iRedrawCounter == 0;\r
987 }\r
988 static void FWL_WriteBMP(CFX_DIBitmap* pBitmap, FX_LPCSTR filename)\r
989 {\r
990     FILE* file = fopen(filename, "wb");\r
991     if (file == NULL) {\r
992         return;\r
993     }\r
994     int size = 14 + 40 + pBitmap->GetPitch() * pBitmap->GetHeight();\r
995     unsigned char buffer[40];\r
996     buffer[0] = 'B';\r
997     buffer[1] = 'M';\r
998     buffer[2] = (unsigned char)size;\r
999     buffer[3] = (unsigned char)(size >> 8);\r
1000     buffer[4] = (unsigned char)(size >> 16);\r
1001     buffer[5] = (unsigned char)(size >> 24);\r
1002     buffer[6] = buffer[7] = buffer[8] = buffer[9] = 0;\r
1003     buffer[10] = 54;\r
1004     buffer[11] = buffer[12] = buffer[13] = 0;\r
1005     fwrite(buffer, 14, 1, file);\r
1006     memset(buffer, 0, 40);\r
1007     buffer[0] = 40;\r
1008     buffer[4] = (unsigned char)pBitmap->GetWidth();\r
1009     buffer[5] = (unsigned char)(pBitmap->GetWidth() >> 8);\r
1010     buffer[6] = (unsigned char)(pBitmap->GetWidth() >> 16);\r
1011     buffer[7] = (unsigned char)(pBitmap->GetWidth() >> 24);\r
1012     buffer[8] = (unsigned char)(-pBitmap->GetHeight());\r
1013     buffer[9] = (unsigned char)((-pBitmap->GetHeight()) >> 8);\r
1014     buffer[10] = (unsigned char)((-pBitmap->GetHeight()) >> 16);\r
1015     buffer[11] = (unsigned char)((-pBitmap->GetHeight()) >> 24);\r
1016     buffer[12] = 1;\r
1017     buffer[14] = pBitmap->GetBPP();\r
1018     fwrite(buffer, 40, 1, file);\r
1019     for (int row = 0; row < pBitmap->GetHeight(); row ++) {\r
1020         FX_LPBYTE scan_line = pBitmap->GetBuffer() + row * pBitmap->GetPitch();\r
1021         fwrite(scan_line, pBitmap->GetPitch(), 1, file);\r
1022     }\r
1023     fclose(file);\r
1024 }\r
1025 FWL_ERR FWL_WidgetMgrSnapshot(IFWL_Widget *pWidget, const CFX_WideString *saveFile, const CFX_Matrix *pMatrix)\r
1026 {\r
1027     CFX_RectF r;\r
1028     pWidget->GetWidgetRect(r);\r
1029     CFX_Graphics gs;\r
1030     gs.Create((FX_INT32)r.width, (FX_INT32)r.height, FXDIB_Argb);\r
1031     CFWL_WidgetMgr *widgetMgr = (CFWL_WidgetMgr*)FWL_GetWidgetMgr();\r
1032     CFWL_WidgetMgrDelegate *delegate = widgetMgr->GetDelegate();\r
1033     delegate->OnDrawWidget(pWidget, &gs, pMatrix);\r
1034     CFX_DIBitmap *dib = gs.GetRenderDevice()->GetBitmap();\r
1035     FWL_WriteBMP(dib, saveFile->UTF8Encode());\r
1036     return FWL_ERR_Succeeded;\r
1037 }\r
1038 FX_BOOL FWL_WidgetIsChild(IFWL_Widget *parent, IFWL_Widget *find)\r
1039 {\r
1040     if (!find) {\r
1041         return FALSE;\r
1042     }\r
1043     IFWL_Widget *child = FWL_GetWidgetMgr()->GetWidget(parent, FWL_WGTRELATION_FirstChild);\r
1044     while (child) {\r
1045         if (child == find) {\r
1046             return TRUE;\r
1047         }\r
1048         if (FWL_WidgetIsChild(child, find)) {\r
1049             return TRUE;\r
1050         }\r
1051         child = FWL_GetWidgetMgr()->GetWidget(child, FWL_WGTRELATION_NextSibling);\r
1052     }\r
1053     return FALSE;\r
1054 }\r